Why does the constructor of a non-private inner member class need a variable representing the immediately enclosing instance of this class?

I am very curious about this question. The Java Language Specification has told me part of the reason:

  1. In a class instance creation expression for a non-private inner member class, §15.9.2 specifies the immediately enclosing instance of
    the member class. The member class may have been emitted by a compiler
    which is different than the compiler of the class instance creation
    expression. Therefore, there must be a standard way for the compiler
    of the creation expression to pass a reference (representing the
    immediately enclosing instance) to the member class’s constructor.
    Consequently, the Java programming language deems in this section that
    a non-private inner member class’s constructor implicitly declares an
    initial parameter for the immediately enclosing instance. §15.9.3
    specifies that the instance is passed to the constructor. …

But for me, this is still not detailed enough.
For example, why is it that because of “The member class may have been emitted by a compiler which is different than the compiler of the class instance creation
expression.”, so “there must be a standard way for the compiler
of the creation expression to pass a reference (representing the
immediately enclosing instance) to the member class’s constructor.”?
I can’t figure out what causal relationship exists between these two sentences.

I have read some related texts, such as this one and this one.But I still feel puzzled.
Could someone please explain this passage to me in detail?
It would be even better if an example could be combined.

Thank you for your reading.

0

An inner (non-static) class has the seemingly magical ability to reference the creating instance of the outer class, but it’s actually just syntactic sugar. The compiler produces a normal class with an extra reference to the outer class passed into the constructor.

So what looks like this:

class Outer {
    class Inner {}
}

Effectively compiles to something like this:

class Outer {
    final Outer outer;

    static class Inner {
        Inner(Outer outer) {
            this.outer = outer;
        }
    }
}

Now, consider the caller:

Outer o = new Outer();
Inner i = o.new Inner();

This has to be translated by the compiler to:

Outer o = new Outer();
Inner i = new Inner(o);

But what if the inner class already has explicit constructor args? Do we call new Inner(o, arg0, arg1, ..., argN) or new Inner(arg0, arg1, ..., argN, o)? If we could guarantee the class and its users are built by the same compiler, the answer would be, “Who cares? It’s not exposed to the code anyway.*” But classes need to be binary compatible, which means compiler A might produce class Inner and compiler B might produce the bytecode that’s using it, and B needs to know how to pass in Outer when instantiating Inner. Hence the JLS specification that it’s to be inserted as the first constructor argument.

*except via reflection, but let’s not go there

12

Suppose there is no such requirement on how the enclosing instance is passed, and suppose that there are compiler implementations A and B.

Let’s use compiler A to compile

public class Outer {
    public void foo() {

    }
    public class Inner {
        public Inner(Outer anotherOuter) {
            // Inner should be able to access the members of the enclosing instance here
            // Note that this is different from anotherOuter.foo()
            Outer.this.foo();
        }
    }
}
$ javacA Outer.java

This produces two files – Outer.class and Outer$Inner.class. Compiler A has put the anotherOuter parameter as the first parameter of the Inner constructor, and uses the second parameter to take the enclosing instance.

Then we use compiler B to compile

public class JavaClass
{
    public static void main (String [] args)
    {
        Outer o1 = new Outer();
        Outer o2 = new Outer();
        Outer.Inner i = o1.new Inner(o2);
    }
}
# assuming Outer.class and Outer$Inner.class are on the class path
javacB JavaClass.java

But compiler B has a problem, what parameter should it pass to the constructor of Outer.Inner? From its perspective, Inner‘s constructor takes two Outer parameters, but it doesn’t know which one is supposed to take the enclosing instance o1, and which one is supposed to take o2!

This is why the spec needs to specify this, essentially providing a way to identify which parameter should the enclosing instance be passed to.

Of course, it doesn’t have to be the first parameter. This is just a design choice. The spec could have said that “the parameter with the name of <insert some name here> should be passed the enclosing instance” or many other variations.

7

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật