? ? ? ? 我们都已经学过类和方法了,但是没有讲过什么是内部类,那么这一篇我们就来填上最后一个缺口——内部类。
????????当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整结构又只为外部事物提供服务,那么这个内部完整结构最好使用内部类。
????????在Java中,可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。
????????内部类也是封装的一种体现。
内部类分为:
- 实例内部类
- 静态内部类
- 匿名内部类
- 局部内部类。
? ? ? ? 我们先来看实例内部类。实例内部类中不能定义静态常量和静态方法。
? ? ? ? 此时我们在OuterClass中定义一个InnerClass实例内部类。之后实例化这个内部类,发现报错。
class OuterClass {
public int data;
private int data2;
public static int data3;
class InnerClass {
public int data4 = 4;
//public static int data5 = 5;//报错
private int data6 = 6;
public void test() {
System.out.println("InnerClass::test()");
}
}
public void test() {
System.out.println("OutterClass::test()");
}
}
public class Test2 {
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
//不能够实例化
}
}
????????也就是说实例内部类不能被直接实例化,但是可以间接实例化。?我们要先实例化外部类,之后通过外部类的对象去初始化外部类中的实例内部类。
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
????????此时我们就能理解为什么实例内部类不能有静态成员了,因为内部类需要外部类引用调用的,而静态成员不需要实例化,可以直接进行使用,所以互相冲突。
????????如果真的需要使用静态,那么可以加上final。
? ? ? ? 如果内部类中有和该外部类中相同的名称的变量成员是,在内部类中访问,优先访问内部类中的成员,也就是说遵循就近原则。
? ? ? ? 如果因为成员名冲突时,要访问外部类的成员,需要使用 外部类的名字.this.成员名进行访问。
? ? ? ? 我们之前说过,一个类就会产生一个字节码文件。那么内部类生成的字节码文件我们执行完代码之后也可以进行查看(在out目录中)。?
? ? ? ? 可以发现内部类的字节码文件名是 外部类 $ 内部类。
? ? ? ? 顾名思义,就是前面加上了static关键字的内部类。静态内部类只能去调用其外部类中的静态成员或方法。
class Out {
public int data1 = 1;
public static int data2 = 2;
private int data3 = 3;
static class InClass {
public int data4 = 4;
public static int data5 = 5;
private int data6 = 6;
public void test() {
System.out.println(out.data1);
System.out.println(data2);//只能调用外部类的静态成员或方法
System.out.println(out.data3);
System.out.println(data4);
System.out.println(data5);
System.out.println("InClass::test()");
}
}
public void test() {
System.out.println("Out::test()");
}
}
?????????静态内部类中如果想调用外部类中的非静态成员,则要先初始化一个外部类,之后通过对象引用调用。
? ? ? ? 此时我们就在静态内部类中实例化一其外部类,之后通过外部类的对象去调用里面的非静态成员。
public void test() {
Out out = new Out();
System.out.println(out.data1);
System.out.println(data2);//只能调用外部类的静态成员或方法
System.out.println(out.data3);
System.out.println(data4);
System.out.println(data5);
System.out.println("InClass::test()");
}
????????局部内部类:一般在方法中定义,没有什么实际用途。下面代码就是在方法中定义了一个内部类。
public void func() {
class AA {
public int a;
}
AA aa = new AA();
System.out.println(aa.a);
}
????????也会生成一个字节码文件。
? ? ? ? 生成了一个Test2$1AA.class字节码文件,命名规则我们不去讨论。
????????匿名内部类一般要使用接口。我们先看代码:
interface IA {
void test();
}
public class Test2 {
public static void main(String[] args) {
new IA() {
@Override
public void test() {
System.out.println("这是重写了接口的方法!");
}
};
IA ia = new IA() {
@Override
public void test() {
System.out.println("这是重写了接口的方法!");
}
};
}
}
? ? ? ? 这里先写了一个接口,之后通过Test2直接定义了一个匿名内部类(我也不知道名字别问我),之后重写接口中的方法,最后通过向上转型动态绑定调用重写方法。
? ? ? ? 博主无能,不清楚内部类的作用,希望大佬能说一下。?