16

I have the following java class:

class Outer
{
    private Integer a;
    private Long b;

    class Inner
    {
        public void foo()
        { 
            System.out.println("a and b are " + a + " " + b);
        }
    }
}

when I run javap on Outer and Outer$Inner, I get the following:

C:\test>javap Outer
Compiled from "Outer.java"
class Outer extends java.lang.Object{
    Outer();
    static java.lang.Integer access$000(Outer);
    static java.lang.Long access$100(Outer);
}

C:\test>javap Outer$Inner
Compiled from "Outer.java"
class Outer$Inner extends java.lang.Object{    
    final Outer this$0;
    Outer$Inner(Outer);
    public void foo();
}

I have two questions:

1) why does java compiler generate static methods that take 'Outer' param, in the outer class, for accessing its private variables ? why not instance methods that the inner class can easily call through its this$0 member ?

2) why is this$0 in inner class made final ? what will happen if it is not final ?

Thanks and regards.

Danubian Sailor
  • 1
  • 38
  • 145
  • 223
shrini1000
  • 7,038
  • 12
  • 59
  • 99
  • 1
    IMHO this mechanism (added in Java 1.1) was a mistake. I try to avoid this mess by declaring `a` and `b` with default (package) access. You don't lose anything as the compiler hack makes the fields package-visible anyway. – finnw Feb 04 '10 at 13:01

2 Answers2

14

Non-static inner classes have an implicit reference to an instance of the outer class. This is implemented as a final reference to the outer class. If it wasn't final technically it could be modified after instantiation.

The outer class is implicitly passed in which is why any constructors on the inner class have an implicit parameter of the outer class, which is how this$0 is passed in.

Edit: as for the access$000 methods the key clue is that they're package access and they take an Outer as an argument. So when code in Inner calls, say, Inner.this.a it's actually calling Inner.access$000(this$0). So those methods are there to give access to private members of the outer class to the inner class.

cletus
  • 616,129
  • 168
  • 910
  • 942
  • 2
    why the `access$...()` methods need to be `static`? The answer you provided is for the second question, and for the question that is never asked. – Adeel Ansari Feb 04 '10 at 11:53
  • 2
    Hi Cletus, thanks for your answer. I understand that 'access*' methods are given so inner class can access private members of outer class. But why are these methods static ? why can't they be instance methods ? since inner class has this$0, the code there can as easily call this$0.access$000 had it been an instance method, instead of calling Outer.access$000(this$0). – shrini1000 Feb 04 '10 at 12:58
  • If they weren't static then you'd have to worry about every potential subclass accidentally overriding them. Only static methods provide the class-specific semantics required. – PSpeed Feb 04 '10 at 22:38
  • 1
    Vinegar's response explains that better... I should have scrolled down. – PSpeed Feb 04 '10 at 22:39
  • This got me pointed in the right direction. Lombok @Builder generates code which when decompiled shows like return new ErrorVO(errorCode$set ? errorCode : ErrorVO.access$000()). In this case the access$000 is referring to the private static method $default$errorCode(). Lombok appears to create one of these for each of the marked variables. Example here https://stackoverflow.com/a/54079511/1981358 – peater Aug 12 '20 at 21:51
2

1) They have to be static, in order to not be overridden in some sub class. I hope you understand.

<Addendum>

Shrini, from your comment, it seems that there is a need to explain the things to avoid some misconceptions. First of all, know on thing that static methods can not be overridden. Overriding is exclusive in objects, and it is there to facilitate polymorphism. Whereas static methods belongs to the class. Found a couple of good resources to support my argument and for you to understand that static methods can not be overridden.

Now for your second retort, you are right in saying that they have package level access and can't be overridden in subclasses outside the package. But I don't know why are you neglecting the case where subclass/es exist in the same package. Its a valid case, IMO. In fact, it would be absurd to name a method like access$000() or something like that, in a real work. But don't underestimate the chance of accidental overriding. There can be a case where the subclass of Outer, say SubOuter, has an inner class of itself too. I didn't try to javap that case myself, just guessing.

</Addendum>

2) Even if you think it will not get modified, technically there is a possibility as cletus pointed out already, use of final can provide easy optimizations by the compiler.

Adeel Ansari
  • 39,541
  • 12
  • 93
  • 133
  • Hi Vinegar, thanks for your answer. But subclasses can override their parent classes' static methods; plus in this specific case the methods are package access, so subclasses outside of this package won't be able to override them anyway. So I don't understand #1 of your answer. – shrini1000 Feb 04 '10 at 13:26
  • @shrini1000: No, you are in a folly. See my addendum. – Adeel Ansari Feb 05 '10 at 01:59
  • Hi Vinegar, thank you for your explanation. I had coded a super/sub class and tested it before making my earlier reply; but I hadn't considered the case where a superclass ref points to a subclassed object. Thanks for pointing that out. And my apologies if my reply offended you; that was never the intention. – shrini1000 Feb 05 '10 at 04:52
  • Question 1 is unfortunately still not answered. There is no technical difference between a nonvirtual member function (i.e. final method in java parlance) and a static or freestanding function: the compiler knows exactly the final code to jump to. There is no way for a derived class to change that. I'm more inclined to guess compiler writers just decided that the OO notation was irrelevant in such implementation details and that using freestanding access$xxx functions looks the more natural the more you approach bare metal programming. – Johan Boulé Dec 31 '18 at 12:32