前言:看Java源码时经常能看到内部类、静态内部类、私有内部类,一直好奇为什么要这么设计,这样的设计理念与作用在哪里,今天来研究下。
参考:
https://blog.csdn.net/jeason_chan_zju/article/details/103657934
https://www.zhihu.com/question/54730071/answer/140867608
https://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class
https://www.cnblogs.com/downey/p/4946815.html
https://blog.csdn.net/jianghuafeng0/article/details/109194468
目录
第一章 内部类概要
1.1 为什么需要内部类
感觉主要是为了高内聚低耦合,当类中某个属性包含很多方面时可以将其声明为内部类,如设计类 B 的目的只是为了给类 A 使用,那么,我们就可将其设定为内部类,没有必要将类 B 设置成单独的 Java 文件,防止与其他类产生依赖关系。
1.2 内部类编译后文件的形式
代码:
public class TestInnerClass {
String name;
Head head ;
public TestInnerClass(){
head = new Head();
head.IQ=100;
}
public int getIQ(){
System.out.println(head.IQ);
return head.IQ;
}
public class Head {
String eye;
String nose;
private String brain;
private int IQ;
}
public static class Clothes {
String jacket;
String pants;
}
}
编译后:
可以看到内部类会被编译成加上$符号类,为了证明带$符号的类和其它的类一样,我尝试创建了Test$T类,也编译成了带$符号的类,证明内部类虽然是创建在类的内部,但编译之后还是会和正常类一样存在一个class文件。
public class Test$T {
}
思考: 既然会拆成不同的类,那么如何做到互相访问private属性?
javac会把内部类代码的解糖为类似下面的形式(不是一个代码哈,理解下意思就行了):
作者:RednaxelaFX
链接:https://www.zhihu.com/question/54730071/answer/140867608
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
public class Outer {
private int outProp;
public Outer() {
super();
this.outProp = 8;
}
public void accessInnerProp() {
System.out.println(Outer$Inner.access$000(new Outer$Inner(this)));
}
public static void main(String[] args) {
Outer p = new Outer();
p.accessInnerProp();
}
}
class Outer$Inner {
private int inProp;
final /* synthetic */ Outer this$0;
Outer$Inner(Outer outer) {
this.this$0 = outer;
super();
this.inProp = 5;
}
static /* synthetic */ int access$000(Outer$Inner self) {
return self.inProp;
}
}
第二章 静态内部类与内部类的区别
看源码的时候,很多内部类都是静态内部类,不禁思考为什么要用静态内部类
2.1 内部类的创建区别
首先看一下stackoverflow上给的区别:
静态内部类一般被称为nested classes(按中文翻译是嵌套类),普通的内部类一般被称为inner classes(按中文翻译是内部类),不过这里我们为了通俗易懂就还是按之前的静态内部类,普通内部类区分了。
静态内部类可以单独创建。
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
普通内部类只能依赖外部类生存,必须创建了外部类才能创建内部类。
OuterClass outerObject = new OuterClass()
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
2.2 内部类的访问权限
在普通内部类中,可以直接访问外部类的属性、方法,即使是private类型也可以,这是因为内部类持有外部类的引用,可以自由访问。而静态内部类只能访问外部类的静态方法和静态属性,如果是private也能访问,其他则不能访问。静态内部类与外部类并不会保存相互之间的引用。
2.3 内部类中变量的定义
普通内部类不能声明static的方法和变量,允许static常量,静态内部类形似外部类,没有任何限制
2.4 私有内部类
就是普通内部类加了private修饰,私有内部类中可以使用外部类中所有的内容,私有内部类只能在外部类中可以通过对象使用私有内部类中的内容,其他类中不能创建私有内部类。
第三章 应用场景
如果内部类与外部类关系不紧密,耦合程度不高,不需要访问外部类的所有属性或方法,需要使用到外部类的静态属性或者需要其他类来处理这个类的内容,那么设计成静态内部类。
你在内部类中需要访问有关外部类的所有属性及方法与不符合静态内部类提供的好处的用普通内部类。
网上说比较典型的使用静态内部类的代码就是HashMap的源码,HashMap源码就有个静态内部类的经典使用,HashMap把put进去的一个key value包装成一个Node,该Node就是静态内部类。
个人感觉ReentrantLock中AbstractQueuedSynchronizer的应用也是挺典型的静态内部类的实现,有兴趣可以看看。