zl程序教程

您现在的位置是:首页 >  后端

当前栏目

包含内部类的.java文件编译后生成几个.class文件

JAVA文件 生成 编译 几个 Class 包含 内部
2023-09-14 09:06:16 时间

如果一个类有内部类,编译将生成几个字节码文件,规则是怎样呢?

写在前,自己动手丰衣足食,结论只有个人实验支持,没有官方数据支持,欢迎自行查阅文档然后来指正,轻喷,谢谢。

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.编译后生成的文件目录

编译后生成的clas文件目录

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命令对两个字节码进行解释,结果如下:
class文件名中数字为1
class文件名中数字为2
由上述过程可看出,小数字的进行了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文件,名称里的数字就是最小的。
以上是个人实验的结果,未查阅文档,有一定的不可靠性。但是懒得去找和读文档了,欢迎指正。