Java编译的类文件

时间:2015-08-01 06:19:33

标签: java constructor inner-classes .class-file

当我浏览java内部类时,我读到了编译器为内部类创建一个单独的.class文件,该文件是$ .class格式。 后来我发现对于每个外部类构造函数,它都会创建一个单独的.class文件,该文件位于$ 1.class中。

为什么编译器也为构造函数执行此操作?我想知道构造函数和内部类之间是否存在任何关系。

public class Foo 
{
    Foo() 
    {
        System.out.print("foo");
    }

class Bar
{
    Bar() 
    {
        System.out.print("bar");
    }
    public void go() 
    {
        System.out.print("hi");
    }
} /* class Bar ends */

    public static void main (String [] args) 
    {
        Foo f = new Foo();
        f.makeBar();
    }
    void makeBar() 
    {
        (new Bar() {}).go();
    }
}

2 个答案:

答案 0 :(得分:1)

因为这个问题再次打开,我会尝试在评论中回答。

此编译器行为来自其他内容。

这是因为您正在Bar(new Bar() {})进行扩展(创建匿名扩展类)。而且因为这个课程是匿名的在Foo类内,它的名称为Foo$1.class

反编译的类看起来像这样:

<强>富$ 1.class

class Foo$1 extends r
{

    final Foo this$0;

    Foo$1()
    {
        this$0 = Foo.this;
        super(Foo.this);
    }
}

我使用了JAD反编译器。 extends r是因为JAD对超级课程一无所知。

如果您修改代码如下:

void makeBar() {
    (new Bar() {
        public void test() { // added method
            System.out.println("It's alive!");
        }
    }).go();
}

反编译的Foo $ 1.class看起来像这样:

class Foo$1 extends r
{

    public void test()
    {
        System.out.println("It's alive!");
    }

    final Foo this$0;

    Foo$1()
    {
        this$0 = Foo.this;
        super(Foo.this);
    }
}

证明Foo $ 1.class是扩展到位(匿名)Bar类。

答案 1 :(得分:1)

让我们看看您的代码:

public class Foo 
{
    Foo()                            // Constructor of Foo
    {
        System.out.print("foo");
    }                                // End of Constructor for Foo

    class Bar                        // Inner class Bar
    {
        Bar()                        // Constructor of Bar
        {
            System.out.print("bar");
        }                            // End of constructor for Bar
        public void go() 
        {
            System.out.print("hi");
        }
    }                               // End of inner class Bar

    public static void main (String [] args) 
    {
        Foo f = new Foo();
        f.makeBar();
    }
    void makeBar() 
    {
        (new Bar() {}).go();        // Anonymous class inheriting from Bar
    }
}

所以你得到的三个类文件是:

  1. 对于Foo类 - Foo.class
  2. 对于内部类Bar - Foo$Bar.class
  3. 对于makeBar - Foo$1.class
  4. 中的匿名课程

    所以你看,这与构造函数无关。它只与在类中创建的实际类有关。匿名类创建一个class文件就像一个命名的内部类 - 但命名约定是一个数字跟在$符号后面而不是类的名称,因为它是匿名的。 / p>

    您可以轻松地将makeBar方法中的代码更改为:

        void makeBar() 
        {
            new Bar().go();
        }
    

    这将消除匿名类,为您提供相同的输出,但只创建两个class文件。所以它与构造函数无关。