Java中的内部类

前言: 

        我们都已经学过类和方法了,但是没有讲过什么是内部类,那么这一篇我们就来填上最后一个缺口——内部类。

        当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整结构又只为外部事物提供服务,那么这个内部完整结构最好使用内部类。

        在Java中,可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。

        内部类也是封装的一种体现。

内部类分为:

  1. 实例内部类
  2. 静态内部类
  3. 匿名内部类
  4. 局部内部类。

实例内部类:

        我们先来看实例内部类。实例内部类中不能定义静态常量和静态方法。

        此时我们在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() {@Overridepublic void test() {System.out.println("这是重写了接口的方法!");}};IA ia = new IA() {@Overridepublic void test() {System.out.println("这是重写了接口的方法!");}};}
}

        这里先写了一个接口,之后通过Test2直接定义了一个匿名内部类(我也不知道名字别问我),之后重写接口中的方法,最后通过向上转型动态绑定调用重写方法。

        博主无能,不清楚内部类的作用,希望大佬能说一下。