目录
一、Java类包
1.1 类名冲突
1.2 完整的类路径
1.3 创建包
1.4 导入包
1.4.1 使用import关键字导入包
1.4.2 使用import导入静态成员
二、内部类
2.1 成员内部类
2.1.1 成员内部类简介
2.1.2 使用this关键字获取内部类与外部类的引用
2.2 匿名内部类
类除了具有普通的特性,还具有一些高级特性,如包、内部类等。包在整个管理过程中起到了非常重要的作用,使用包可以有效地管理繁杂的类文件解决类重名的问题。在类中应用包与权限修饰符,可以控制其他人对类成员的访问。Java中还有一个更为有效的隐藏实现细节的方式,那就是使用内部类,通过后可以向上转型为被内部类实现的公共接口。由于在类中可以定义多个内部类,实现接口的方式也不止一个,因此只要将内部类中的方法设置为类最小范围的修饰权限,即可将内部类的实现细节有效地隐藏。
一、Java类包
Java中提供了一种管理类文件的机制,就是类包。
1.1 类名冲突
编译器不会允许存在同名的类文件。解决这类问题的办法就是将这两个类放置在不同的类包中。
1.2 完整的类路径
编写Java程序经常用到String类,其实String类并不是它的完整名称。String的完整名称是:java.lang.String。一个完整的类名需要包名与类名的组合,每个类都隶属于一个类包,只要保证同一类包中的类不同名,就可以有效地避免同名类冲突的情况。
例如,一个程序中同时使用到java.util.Date类与java.sql.Date类,如果在程序中不指定完整的类路径,编译器不会知道这段代码使用的是java.util类包中的Date类还是java.sql类包中的Date类,所以需要在指定代码中给出完整的类路径。
例如,在程序中使用两个不同Date类的完整类路径,可以使用如下代码:
java.util.Date date=new java.util.Date();
java.sql.Date date2=new java.sql.Date(1000);
在Java中采用类包机制非常重要,类包不仅可以解决类名冲突问题,还可以在开发庞大的应用程序时,帮助开发人员管理庞大的应用程序组件,方便软件复用。
同一包中的类相互访问时,可以不指定包名。
1.3 创建包
在Java中包名设计应与文件系统结构相对应,如一个包名为com.mr,那么包中的类位于com文件夹下的mr子文件夹下。没有定义包的类会被归纳在默认包(default package)中。
定义包的语法如下:
package 包名
在类中指定包名时,需要将package表达式放置在程序的第一行,它必须是文件中的第一行非注释代码。使用package关键字为类指定包名之后,包名将会成为类名中的一部分,预示着这个类必须指定全名。例如,在使用位于com.mr包下的Dog.java类时,需要使用形如com.mr.Dog这样的表达式。
为了避免产生包名冲突现象,在Java中定义包名时通常使用创建者的Internet域名的反序,由于Internet域名是独一无二的,包名自然不会发生冲突。
package haha; //指定包名
public class Math{
public static void main(String[] args) {
System.out.println("不是java.lang.Math类,而是com.mr.Math类");
}
}
可以看出,在不同包中定义相同类名也是没有问题的。
1.4 导入包
1.4.1 使用import关键字导入包
如果某个类中需要使用Math类,可以使用Java中的import关键字指定是java.lang.Math类还是com.mr.Math类。例如,如果在程序中使用import关键字导入com.mr.Math类,在程序中使用Math类时会自动选择com.mr.Math类。
import com.mr.* //导入com.mr包中的所有类
import com.mr.Math //导入com.mr包中的Math类
如果类定义中已经导入com.mr.Math类,在类体中再使用其他包中的Math类时就必须指定完整的带有包格式的类名。例如,在上述情况下再使用java.lang包的Math类时就要使用全名格式java.lang.Math。
在程序中添加import关键字时,就开始在CLASSPATH指定的目录下进行查找,查找子目录com.mr,然后从这个目录下编译完成的文件中查找是否有名称符合者,最后寻找到Math.class文件。另外,当使用import指定了一个包中的所有类时,并不会指定这个包的子包中的类,如果用到这个包的子包中的类,需要再次对子包进行单独引用。
1.4.2 使用import导入静态成员
import关键字除了导入包外,还可以导入静态成员。使用import导入静态成员的语法如下:
import static 静态成员
package haha;
import static java.lang.Math.max; //导入静态成员方法
import static java.lang.System.out; //导入静态成员变量
public class ImportTest{
public static void main(String[] args) {
out.println("1和4的较大值为:"+max(1,4)); //主方法中可以直接使用这些静态成员
}
}
二、内部类
如果在类中再定义一个类,则将在类中再定义的那个类称为内部类。成员内部类和匿名类是最常见的内部类。
2.1 成员内部类
2.1.1 成员内部类简介
在一个类中使用内部类,可以在内部类中直接存取其所在类的私有成员变量。成员内部类的语法如下:
class OuterClass{ //外部类
class InnerClass{ //内部类
}
}
在成员内部类中可以随意使用外部类的成员方法及成员变量,尽管这些类成员被修饰为private。
内部类的实例一定要绑定在外部类的实例上,如果从外部类中初始化一个内部类对象,那么内部类对象就会绑定在外部类对象上。内部类初始化方式与其他类的初始化方式相同,都是使用new关键字。
例:使用内部成员类模拟发动机点火
首先创建Car类,Car类中有私有属性brand和start()方法,然后在Car类的内部创建Engine类,Engine类中有私有属性model和ignite()方法,最后打印出“启动大众朗行,发动机EA211点火”。
package haha;
public class Car{ //创建汽车类
private String brand; //汽车品牌
public Car(String brand) { //汽车类的构造方法,参数为汽车品牌
this.brand=brand; //给汽车品牌赋值
}
class Engine{ //发动机类(内部类)
String model; //发动机型号
public Engine(String model) { //发动机类的构造方法,参数为发动机型号
this.model=model; //给发动机型号赋值
}
public void ignite() { //(发动机)点火方法
System.out.println("发动机"+this.model+"点火");
}
}
public void start() { //启动(汽车)方法
System.out.println("启动"+this.brand);
}
public static void main(String[] args) {
Car car=new Car("大众朗行"); //创建汽车类对象,并为汽车品牌赋值
car.start(); //汽车类对象调用启动(汽车)方法
//创建发动机类(内部类)对象,并未发动机型号赋值
Car.Engine engine=car.new Engine("EA211");
engine.ignite(); //发动机类对象调用(发动机)点火方法
}
}
成员内部类不止可以在外部类中使用,在其它类中也可以使用。在其它类中创建内部类对象的语法如下:
外部类 outer = new 外部类();
外部类.内部类 inner = outer.new 内部类();
内部类对象会依赖于外部类对象,除非已经存在一个外部类对象,否则类中不会出现内部类对象。
2.1.2 使用this关键字获取内部类与外部类的引用
如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this关键字。
例:在内部类中调用外部类对象
在项目中创建TheSameName类,在类中定义成员变量x,再定义一个内部类Inner,在内部类中也创建x变量,并在内部类的doit()方法中定义一个局部变量x。
package haha;
public class TheSameName{
private int x=7; //外部类的x
private class Inner{
private int x=9; //内部类的x
public void doit() {
int x=11; //局部变量x
x++;
this.x++; //调用内部类的x
TheSameName.this.x++; //调用外部类的x
}
}
}
2.2 匿名内部类
匿名类是只在创建对象时才会编写类体的一种写法。匿名类的特点是“现用现写”,其语法如下:
new 父类/父接口(){
子类实现的内容
};
最后一个大括号之后有分号。
例:使用匿名内部类创建一个抽象狗类的对象
创建一个抽象的狗类,类中有一个颜色属性和两个抽象方法,在测试类的主方法中创建抽象类对象,并用匿名内部类实现该对象的抽象方法。
package haha;
abstract class Dog{
String Color;
public abstract void move();
public abstract void call();
}
public class Demo{
public static void main(String args[]) {
Dog maomao=new Dog() {
public void move() {
System.out.println("四腿狂奔");
}
public void call() {
System.out.println("嗷呜~");
}
};
maomao.Color="灰色";
maomao.move();
maomao.call();
}
}
在程序中maomao只能解读为“一只具体的无名之狗”。
使用匿名类时应该遵循以下原则:
- 匿名类不能写构造方法。
- 匿名类不能定义静态的成员。
- 如果匿名类创建的对象没有赋值给任何引用变量,会导致该对象用完一次就会被Java虚拟机销毁。