2.2 静态内部类
2.2.1 定义
静态内部类也称为嵌套类,是使用 static 关键字修饰的内部类。如下代码中定义了一个静态内部类:
public class Car1 { // 静态内部类 static class Engine { public void run() { System.out.println("我是静态内部类的run()方法"); System.out.println("发动机启动了"); } } }
2.2.2 实例化
静态内部类的实例化,可以不依赖外部类的对象直接创建。我们在主方法中可以这样写:
// 直接创建静态内部类对象 Engine engine = new Engine(); // 调用对象下run()方法 engine.run();
运行结果:
我是静态内部类的run()方法 发动机启动
2.2.3 成员的访问
在静态内部类中,只能直接访问外部类的静态成员。例如:
实例演示
public class Sky1 { String brand = "宝马"; static String name = "外部类的静态属性name"; // 静态内部类 static class Engine { public void fly() { System.out.println(name); } } public static void main(String[] args) { Engine engine = new Engine(); engine.fly(); } }
在 fly() 方法中,打印的 name 属性就是外部类中所定义的静态属性 name。编译执行,将会输出:
外部类的静态属性name
对于内外部类存在同名属性的问题,同样遵循就近原则。这种情况下依然希望调用外部类的静态成员,可以使用外部类名.静态成员的方式来进行调用。这里不再一一举例。
如果想要访问外部类的非静态属性,可以通过对象的方式调用,例如在 fly() 方法中调用 Sky1 的实例属性 brand:
public void run() { // 实例化对象 Car1 car1 = new Car1(); System.out.println(car1.brand); }
2.3 方法内部类
2.3.1 定义
方法内部类,是定义在方法中的内部类,也称局部内部类。
如下是方法内部类的代码:
实例演示
public class Sky2 { // 外部类的fly()方法 public void fly() { class Engine { public void fly() { System.out.println("方法内部类的fly()方法"); System.out.println("发动机启动了"); } } // 在Sky2.fly()方法的内部实例化其方法内部类Engine Engine engine = new Engine(); // 调用Engine的fly()方法 engine.fly(); } public static void main(String[] args) { Sky2 Sky2 = new Sky2(); Sky2.fly(); } }
运行结果:
方法内部类的run()方法 发动机启动了
如果我们想调用方法内部类的 fly() 方法,必须在方法内对 Engine 类进行实例化,再去调用其 fly() 方法,然后通过外部类调用自身方法的方式让内部类方法执行。
2.3.2 特点
与局部变量相同,局部内部类也有以下特点:
方法内定义的局部内部类只能在方法内部使用;
方法内不能定义静态成员;
不能使用访问修饰符。
也就是说,Sky2.getEngine() 方法中的 Engine 内部类只能在其方法内部使用;并且不能出现 static 关键字;也不能出现任何的访问修饰符,例如把方法内部类 Engine 声明为 public 是不合法的。
2.4 匿名内部类
2.4.1 定义
匿名内部类就是没有名字的内部类。使用匿名内部类,通常令其实现一个抽象类或接口。
实例演示
// 定义一个交通工具抽象父类,里面只有一个fly()方法 public abstract class Transport { public void fly() { System.out.println("交通工具fly()方法"); } public static void main(String[] args) { // 此处为匿名内部类,将对象的定义和实例化放到了一起 Transport Sky = new Transport() { // 实现抽象父类的fly()方法 @Override public void fly() { System.out.println("汽车跑"); } }; // 调用其方法 Sky.fly(); Transport airPlain = new Transport() { // 实现抽象父类的fly()方法 @Override public void fly() { System.out.println("飞机飞"); } }; airPlain.fly(); } }
运行结果:
汽车跑 飞机飞
上述代码中的抽象父类中有一个方法 fly(),其子类必须实现,我们使用匿名内部类的方式将子类的定义和对象的实例化放到了一起,通过观察我们可以看出,代码中定义了两个匿名内部类,并且分别进行了对象的实例化,分别为 Sky 和 airPlain,然后成功调用了其实现的成员方法 fly()。
2.4.2 特点
含有匿名内部类的类被编译之后,匿名内部类会单独生成一个字节码文件,文件名的命名方式为:外部类名称$数字.class。例如,我们将上面含有两个匿名内部类的 Transport.java 编译,目录下将会生成三个字节码文件:
Transport$1.class Transport$2.class Transport.class
匿名内部类没有类型名称和实例对象名称;
匿名内部类可以继承父类也可以实现接口,但二者不可兼得;
匿名内部类无法使用访问修饰符、static、abstract 关键字修饰;
匿名内部类无法编写构造方法,因为它没有类名;
匿名内部类中不能出现静态成员。
2.4.2 使用场景
由于匿名内部类没有名称,类的定义可实例化都放到了一起,这样可以简化代码的编写,但同时也让代码变得不易阅读。当我们在代码中只用到类的一个实例、方法只调用一次,可以使用匿名内部类。