-1

While I was going through the java inner class section, I read about compiler creating a separate .class file for the inner class which is in $.class format. Later I found that for every outer class constructor as well, it creates a separate .class file which is in $1.class.

Why compiler does this for constructors as well? I was wondering if there was any relation between constructors and inner classes.

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();
    }
}
Maneesh
  • 119
  • 10
  • 3
    Can you add a specific example to this question, maybe with some code, what you expect to happen, what actually happens, what is different? – pvg Aug 01 '15 at 06:25
  • Indeed, I think you've misdiagnosed this. – Jon Skeet Aug 01 '15 at 06:31
  • @pvg I was not expecting anything. I was just wondering why a separate .class file for constructors as well ? For "inner class" it sounds sensible as it is a "class". But why for constructors ? And if it is for constructors, then why not for any other method of the class ? – Maneesh Aug 01 '15 at 06:33
  • @Maneesh: post a code example, post the class file names generated by the compiler for that code example, and we'll explain why it generates those class files. It has nothing to do with constructors. – JB Nizet Aug 01 '15 at 06:38
  • 1
    In short: no it doesn't. – RealSkeptic Aug 01 '15 at 06:44
  • This is the source code. 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(); } }/* class Foo ends */ And these are the class files that it generated. Foo$1.class Foo$Bar.class Foo.class – Maneesh Aug 01 '15 at 07:03
  • Do not put code in the comments. It's unreadable. Edit your question, and add the code there, properly formatted. – RealSkeptic Aug 01 '15 at 07:15
  • @Jon Skeet.. When I look at the compiled .class files I think you are right that I have misdiagnosed the problem. – Maneesh Aug 01 '15 at 07:29
  • I suggest you delete this question, in that case. – Jon Skeet Aug 01 '15 at 07:33
  • I have attached the code now. I see three .class files generated as mentioned below. Foo$1.class Foo$Bar.class Foo.class – Maneesh Aug 01 '15 at 08:21
  • 1
    @JonSkeet this results from something else. Actually I think that I can say why you see the Foo$1. That's because you're extending in place (creating anonymous extened class) the Bar class (new Bar() **{}**). And because the class is anonymous & is inside Foo it's name is Foo$1.class. – Xeon Aug 01 '15 at 08:59
  • Try to remove appropriate **{}** from your code and you'll see that the Foo$1 won't be created. – Xeon Aug 01 '15 at 09:02

2 Answers2

1

Because this question is open again I'll try to answer it as in comments.

This compiler behaviour results from something else.

That's because you're extending in place (creating anonymous extened class) the Bar class (new Bar() {}). And because the class is anonymous & is inside Foo class it's name is Foo$1.class

The decompiled class looks like this:

Foo$1.class

class Foo$1 extends r
{

    final Foo this$0;

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

I used JAD decompiler. extends r is because JAD didn't know anything about super class.

If you modify your code like this:

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

The decompiled Foo$1.class will look like this:

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);
    }
}

Which proves that Foo$1.class is the extended in place (anonymous) Bar class .

Xeon
  • 5,949
  • 5
  • 31
  • 52
1

Let's look at your code:

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
    }
}

So the three class files you get are:

  1. For the class Foo - Foo.class
  2. For the inner class Bar - Foo$Bar.class
  3. For the anonymous class inside makeBar - Foo$1.class

So you see, this has nothing to do with the constructors. It only has to do with actual classes created inside your class. An anonymous class creates a class file just like a named inner class - but the naming convention is that a number follows the $ sign rather than the class's name, because it is anonymous.

You can easily change the code in the makeBar method to:

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

Which will eliminate the anonymous class, give you the same output, but only create two class files. So it has nothing to do with the constructors.

RealSkeptic
  • 33,993
  • 7
  • 53
  • 79