【2021-07-05】请说出内部类和静态内部类的区别?
请移步至:
每日一题 查看更多的题目 ~
答:
普通内部类:
- 可以访问外部类的所有属性和方法
- 普通内部类中不能包含静态的属性和方法
静态内部类:
- 静态内部类只能访问外部类的静态属性及方法,无法访问外部类的普通成员(变量和方法)
- 静态内部类可以包含静态的属性和方法
那么,你知道为什么普通内部类可以访问到外部类的成员变量么?
我们来看一个示例:
Home
package com.github.test;
public class Home {
class A {
}
}
Home2
package com.github.test;
public class Home2 {
static class A {
}
}
执行编译后,我们来到 target 目录下,查看 Home 与 Home2 反编译的 class 文件
执行命令:
javap -private 'Home$A'
Home$A.class
class com.github.test.Home$A {
final com.github.test.Home this$0;
com.github.test.Home$A(com.github.test.Home);
}
执行命令:
javap -private 'Home2$A'
Home2$A.class
class com.github.test.Home2$A {
com.github.test.Home2$A();
}
我们可以看到 Home 类当中含有普通内部类 A,对 class 文件反编译后,我们看到了一个特殊的字段:com.github.test.Home this$0;
,这个字段是 JDK 为我们自动添加的,指向了外部类 Home。
所以,我们也就搞清楚了,之所以普通内部类可以直接访问外部类成员变量,是因为 JDK 为我么偷偷添加了一个隐式的变量 this$0,指向外部类。
那么,我们应该在什么时候使用内部类,什么时候使用静态内部类呢?
《Effective java》 第 24 条的内容是:Favor static member classes over nonstatic,即:优先考虑使用静态内部类。
因为非静态内部类会持有外部类的一个隐式引用(this$0), 存储这个引用需要占用时间和空间。更严重的是有可能会导致宿主类在满足垃圾回收的条件时却仍然驻留在内存中,由此引发内存泄漏的问题。
所以,在需要使用内部类的情况下,我们应该尽可能选择使用静态内部类。