包含内部类的.java文件编译后生成几个.class文件
如果一个类有内部类,编译将生成几个字节码文件,规则是怎样呢?
写在前,自己动手丰衣足食,结论只有个人实验支持,没有官方数据支持,欢迎自行查阅文档然后来指正,轻喷,谢谢。
1.普通类包含内部类的样例
public class Test319 {
private static class StaticInner{ }//静态内部类
private class Inner{}//成员内部类
public void outerFunction1(){
class PartInner3{}//局部内部类3
}
public void outerFunction2(){
class PartInner1{}//局部内部类1
class PartInner2{}//局部内部类2
}
public Thread thread1 = new Thread(new Runnable() {//匿名内部类1
@Override
public void run() {
}
}, "thread1");
public Thread thread2 = new Thread(new Runnable() {//匿名内部类2
@Override
public void run() {
}
}, "thread2");
public Thread thread3 = new Thread(()->{//匿名内部类(使用lambda表达式)
},"thread3");
}
2.编译后生成的文件目录
3.小总结
首先,包括外部类在内一共有9个类,而目录中只有8个class文件,可以看出一套规律:全部内部类编译后都会生成字节码文件,但是匿名内部类有个特点
1.成员内部类:外部类名后加一个dollar接内部类名
2.静态内部类:和成员内部类一样(毕竟都是外部类的成员,静态非静态而已)
3.局部内部类:在dollar后比成员内部类多了个数字
4.匿名内部类:dollar后只有一个数字,如果使用lambda表达式创建匿名内部类将不生成class文件,否则会生成。
其次,局部内部类和不使用lambda表达式创建的匿名内部类,他们的class文件名都包含数字,数字究竟是什么含义?(在没有查资料的情况下,首先猜测,数字顺序就是内部类声明的顺序)先用两个匿名内部类来进行测试,后面再说局部内部类的问题。
4.关于文件名中数字的测试(匿名内部类)
第一步,为了观察方便给代码做些调整,加入简单的方法体。
public Thread thread1 = new Thread(new Runnable() {//匿名内部类1
@Override
public void run() {
System.out.println("Hello World");
}
}, "thread1");
public Thread thread2 = new Thread(new Runnable() {//匿名内部类2
@Override
public void run() {
int i = 10;
i += 1;
}
}, "thread2");
先声明的进行print操作,后声明的进行int加法计算。通过javap命令对两个字节码进行解释,结果如下:
由上述过程可看出,小数字的进行了print,大数字的进行了int+1,而定义的顺序也就是print操作的在前,int+1操作的在后。
第二步,使用相同手法,在.java文件中调换两个操作的声明顺序,即先声明的进行int+1操作,后声明的进行print操作,得到了相同的结论,具体不再赘述。
通过反复实验,结果一致。但因为没有查阅官方文档,先提出一个我自己的想法:数字顺序是内部类的声明顺序,同时作为区分匿名内部类的依据。
5.关于局部内部类
再回过头说局部内部类的问题。匿名内部类没有名字自然需要数字区分,那么如果其他有名字的内部类名称重复怎么办(此情况只能发生于局部内部类)?同样可以先得出一个结论,数字是区分重名局部内部类的依据。
但是我发现数字顺序并不是声明顺序……不再赘述实验过程,简单来说在外部类的两个方法里定义名称相同的局部内部类,调换两个方法的声明位置。编译后文件目录如下:
这里看出数字不再是声明顺序,定义了两个局部内部类的方法我是后声明的,数字反而变成了1而不是2。有种被逗了的感觉。秉持着“死也不去查资料先作作看结果”的精神,实验继续……(*其实是我不知道该去看官方的哪个文档,也懒得去找*)
新定义和新编译生成的文件目录如下:
public class Test319 {
public void outerFunction1(){
class PartInner1{}
}
public void outerFunction2(){
class PartInner1{}
class PartInner2{}
}
public void outerFunction3(){
class PartInner1{}
class PartInner2{}
class PartInner3{}
}
}
差一点,我就以为数字顺序是内部类所在方法定义的逆序了。还好所做了几组实验,毕竟自己归纳就已经很不科学了,更不能仅从一组实验就得出结论。中间步骤不说了,直接来看最后一组实验:
public class Test319 {
public void outerFunction1(){
class PartInner1{}
}
public void outerFunction3(){
class PartInner1{}
class PartInner2{}
class PartInner3{}
}
public void outerFunction2(){
class PartInner1{}
class PartInner2{}
class PartInner3{}
class PartInner4{}
class PartInner5{}
}
public void outerFunction0(){
class PartInner1{}
class PartInner2{}
class PartInner3{}
class PartInner4{}
}
}
具体的自行细品吧,直接说我的结论:定义内部类个数最多的方法,它里面的内部类生成的class文件,名称里的数字就是最小的。
6.最终总结
大致总结在上面的【3】,再总结一下关于数字的事情。
首先关于为什么会有数字,因为匿名内部类没名字(废话。。。),局部内部类名称可能相同,所以数字用来做不同内部类之间的区分,这也是为什么只有他们两个编译出来的字节码文件,名称中带有数字。
其次关于数字顺序,匿名内部类,数字顺序是声明顺序;局部内部类,定义内部类个数最多的方法,它里面的内部类生成的class文件,名称里的数字就是最小的。
以上是个人实验的结果,未查阅文档,有一定的不可靠性。但是懒得去找和读文档了,欢迎指正。
相关文章
- [Java基础] 使用JMAP dump及分析dump文件
- java基础知识回顾之javaIO类--File类应用:获取指定目录下面的指定扩展名的文件,将文件的绝对路径写入到目的文件当中
- java实现遍历树形菜单方法——映射文件VoteTree.hbm.xml
- java:练习学校学生
- Java实现WUST 1002: 哈夫曼树
- Java实现 洛谷 P1000 超级玛丽游戏
- Java实现 蓝桥杯 历届试题 邮局
- java 生成xml文件
- Atitit.java expression fsm 表达式分词fsm引擎
- Atitit.sql ast 表达式 语法树 语法 解析原理与实现 java php c#.net js python
- 华为OD机试 - 没有回文串(Java & JS & Python)
- 统计某个路径下所有的java文件,以及统计代码数量
- Myeclipse自动生成java的Bean和BeanName.hbm.xml文件(java项目必须支持Hibernate)
- Java代理模式:如何优雅地控制对象访问?
- Java类和对象(一)
- 基于JAVA实现的WEB端UI自动化 - WebDriver高级篇 - exe文件执行
- 【LeetCode-面试算法经典-Java实现】【066-Plus One(加一)】
- java有关的打包文件.jar、.war、.ear
- 【Android 安全】DEX 加密 ( Java 工具开发 | 生成 dex 文件 | Java 命令行执行 )
- Java Web文件上传原理分析(不借助开源fileupload上传jar包)
- java 使用jdbc连接Greenplum数据库和Postgresql数据库
- 对Java内存模型即JMM的理解
- app_process执行java文件(三十五)
- Java 生成本文文件的时候,Dos格式转成Unix格式
- JAVA字符串格式化-String.format()使用
- Hadoop HDFS (3) JAVA訪问HDFS之二 文件分布式读写策略
- 《Thinking in java》第四版中的例子tupeinfo/SweetShop.java存在问题,全限定名;forName()方法
- JAVA操作Excel表格:方法二:POI的使用①:Excel实战之POI创建excel文件(低版本)