1.成员内部类

创建

创建成员内部类对象的一般形式为: 外部类类名.内部类类名 xxx = 外部类对象名.new 内部类类名()

位置

成员内部类是最普通的内部类,它定义在一个类的内部

结构

可以定义非静态属性和方法。
不可以定义static修饰的属性和方法。
但可以定义static final修饰的编译期变量。

首先要先知道sttaic final修饰的变量叫做常量,常量分为编译期常量和非编译期常量
编译期常量:在程序编译阶段【不需要加载类的字节码】,就可以确定常量的值
非编译期常量:在程序运行阶段【需要加载类的字节码】,可以确定常量的值

public class OutterClass {
    
    class Inner{
        int a = 0;//非静态变量
        static int b = 0;//静态变量【报错!!】
        static final int c = 0;//编译期常量,不需要类加载
        static final Integer d = new Integer(2);//非编译期常量,需要类加载【报错!!】
    }
    
    public static void main(String[] args) {
        System.out.println(OutterClass.Inner.b);
        System.out.println(OutterClass.Inner.c);
        System.out.println(OutterClass.Inner.d);
    }
    /*
    b属性是静态的,它需要加载类的字节码Inner类,由于它是在OutterClass内部,需要外部类实例化才能加载,但是调用处没有实例化外部类,所以Inner也不会类加载,所以报错
    c属性是编译期常量,它不需要加载类的字节码Inner类,所以不会报错
    d属性是非编译期常量。它需要加载类的字节码Inner类,所以报错
    */
}

访问权限

成员内部类可以无条件访问外部类的所有成员属性和成员方法。

而在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问。
两种情况:
1.访问普通属性和方法:需要创建成员内部类的对象
2.访问常量:可以直接使用 外部类.内部类.常量

class Outter {
    class Inner{
        static final int a = 4;
    }
    public static void main(String[] args) {
        //第一种
        Outter.Inner in = new Outter().new Inner();
        System.out.println(in.a);
        //第二种
        System.out.println(Outter.Inner.a);
    }
}

访问修饰符

内部类可以被任何访问修饰符修饰,因为它也是类的成员。

注意

当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:

外部类.this.成员变量
外部类.this.成员方法

为什么成员内部类可以无条件访问外部类的成员?

编译器在进行编译的时候,会将成员内部类单独编译成一个字节码文件。
编译器会默认为成员内部类添加一个指向外部类对象的引用。

成员内部类中的指针便指向了外部类对象,因此可以在成员内部类中随意访问外部类的成员。从这里也间接说明了成员内部类是依赖于外部类的,如果没有创建外部类的对象,则无法对引用进行初始化赋值,也就无法创建成员内部类的对象了。

继承

java在类的内部定义一个私有静态类_内部类

2.局部内部类

位置

局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。

访问修饰符

不能有访问修饰符

注意,局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。

3.匿名内部类

特点

匿名内部类是唯一一种没有构造器的类。
正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。
匿名内部类在编译的时候由系统自动起名为Outter$1.class。
一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。

访问修饰符

同样的,匿名内部类也是不能有访问修饰符和static修饰符的。

4.静态内部类

创建

创建静态内部类对象的一般形式为: 外部类类名.内部类类名 xxx = new 外部类类名.内部类类名()

位置

静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。
静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。

注意

静态内部类是不依赖于外部类的,也就说可以在不创建外部类对象的情况下创建内部类的对象。
静态内部类是不持有指向外部类对象的引用的。

5.内部类的使用场景和好处

1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整,
2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
3.方便编写事件驱动程序
4.方便编写线程代码