深入理解内部类

# 1、内部类初探

内部类是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在的。内部类可为静态,可用protected和private修饰(而外部类只能使用public和缺省的包访问权限)。内部类主要有以下几类:成员内部类、局部内部类、静态内部类、匿名内部类。

  • (1)内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。
  • (2)内部类不能用普通的方式访问。
  • (3)内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量
  • (4)外部类不能直接访问内部类的的成员,但可以通过内部类对象来访问

内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的。因为当某个外围类的对象创建内部类的对象时,此内部类会捕获一个隐式引用,它引用了实例化该内部对象的外围类对象。通过这个指针,可以访问外围类对象的全部状态。
通过反编译内部类的字节码,分析之后主要是通过以下几步做到的:   
1 编译器自动为内部类添加一个成员变量,这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象的引用;   
2 编译器自动为内部类的构造方法添加一个参数,参数的类型是外部类的类型, 在构造方法内部使用这个参数为1中添加的成员变量赋值;   
3 在调用内部类的构造函数初始化内部类对象时,会默认传入外部类的引用。

使用内部类的好处

静态内部类的作用:

  • 只是为了降低包的深度,方便类的使用,静态内部类适用于包含类当中,但又不依赖与外在的类。
  • 由于Java规定静态内部类不能用使用外在类的非静态属性和方法,所以只是为了方便管理类结构而定义。于是我们在创建静态内部类的时候,不需要外部类对象的引用。

非静态内部类的作用:

  • 内部类继承自某个类或实现某个接口,内部类的代码操作创建其他外围类的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。
  • 使用内部类最吸引人的原因是:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响
  • 如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。
    从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了"多重继承"。

静态内部类和普通内部类的区别

  • 静态内部类不持有外部类的引用 在普通内部类中,我们可以直接访问外部类的属性、方法,即使是private类型也可以访问,这是因为内部类持有一个外部类的引用,可以自由访问。而静态内部类,则只可以访问外部类的静态方法和静态属性(如果是private权限也能访问,这是由其代码位置所决定的),其他则不能访问。
  • 静态内部类不依赖外部类 普通内部类与外部类之间是相互依赖的关系,内部类实例不能脱离外部类实例,也就是说它们会同生同死,一起声明,一起被垃圾回收器回收。而静态内部类是可以独立存在的,即使外部类消亡了,静态内部类还是可以存在的。
  • 普通内部类不能声明static的方法和变量,注意这里说的是变量,常量(也就是final static修饰的属性)还是可以的,而静态内部类形似外部类,没有任何限制。
静态内部类 普通内部类
不持有外部类的引用,只可以访问外部类的静态方法和静态属性(如果是private权限也能访问,这是由其代码位置所决定的),其他则不能访问 可以直接访问外部类的属性、方法,即使是private类型也可以访问,这是因为内部类持有一个外部类的引用,可以自由访问
不依赖于外部类,可以独立存在,即使外部类消亡了,静态内部类还是可以存在的 与外部类相互依赖,同生共死,一起被垃圾回收器回收
没有限制 不能声明static的方法和变量,注意这里说的是变量,常量(也就是final static修饰的属性)还是可以的

为什么普通内部类不能有静态变量

  • 普通内部类是成员内部类,是实例的一部分而不是类的一部分
  • static类型的属性和方法,在类加载的时候就会存在于内存中。 要想使用某个类的static属性和方法,那么这个类必须要加载到JAVA虚拟机中。非静态内部类并不随外部类一起加载,只有在实例化外部类之后才会加载。现在考虑这个情况:在外部类并没有实例化,内部类还没有加载,这时候如果 调用内部类的静态成员或方法,内部类还没有加载,却试图在内存中创建该内部类的静态成员,这明显是矛盾的。所以非静态内部类不能有静态成员变量或静态方法。

2、局部内部类

在方法中定义的内部类称为局部内部类。与局部变量类似,局部内部类不能有访问说明符,因为它不是外围类的一部分,但是它可以访问当前代码块内的常量,和此外围类所有的成员。
需要注意的是: 局部内部类只能在定义该内部类的方法内实例化,不可以在此方法外对其实例化。

3、匿名内部类

匿名内部类就是没有名字的内部类,并且,匿名内部类是局部内部类的一种特殊形式。什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的: 只用到类的一个实例。 类在定义后马上用到。 类非常小(SUN推荐是在4行代码以下) 给类命名并不会导致你的代码更容易被理解。 在使用匿名内部类时,要记住以下几个原则:
1  匿名内部类不能有构造方法。
2  匿名内部类不能定义任何静态成员、方法和类。
3  匿名内部类不能是public,protected,private,static。
4  只能创建匿名内部类的一个实例。
5 一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
6  因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。

猜你喜欢

转载自blog.csdn.net/qq_37935909/article/details/108435891