Java 从扩展外部类本身的内部类中访问外部类成员

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19349391/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 16:21:28  来源:igfitidea点击:

Accessing outer class members from within an inner class extending the outer class itself

javainheritanceinner-classes

提问by Tiny

In the code snippet shown below, an inner class inherits an outer class itself.

在下面显示的代码片段中,内部类继承了外部类本身。

package test;

class TestInnerClass {

    private String value;

    public TestInnerClass(String value) {
        this.value = value;
    }

    private String getValue() {
        return value;
    }

    public void callShowValue() {
        new InnerClass("Another value").showValue();
    }

    private final class InnerClass extends TestInnerClass {

        public InnerClass(String value) {
            super(value);
        }

        public void showValue() {
            System.out.println(getValue());
            System.out.println(value);
        }
    }
}


public final class Test {

    public static void main(String[] args) {
        new TestInnerClass("Initial value").callShowValue();
    }
}

The only statement inside the main()method (the last snippet) assigns the value Initial valueto the private field valueof the TestInnerClassclass and then invokes the callShowValue()method.

方法中的唯一语句main()(最后一个片段)将值分配给类Initial value的私有字段valueTestInnerClass然后调用该callShowValue()方法。

The callShowValue()method causes another string - Another valueto be set the to the private field valueof the TestInnerClassclass before invoking the showValue()method of InnerClassextending TestInnerClass.

callShowValue()方法会导致另一个字符串-Another value要设置的私人领域value中的TestInnerClass类调用之前showValue()的方法InnerClass延长TestInnerClass

Accordingly, the following two statements inside the showValue()method,

因此,showValue()方法内部的以下两个语句,

System.out.println(getValue());
System.out.println(value);

should display,

应该显示,

Another value
Another value

另一个值
另一个值

But they display,

但他们显示,

Initial value
Initial value

初始值
初始值

Why does this happen?

为什么会发生这种情况?

采纳答案by Sotirios Delimanolis

The method getValue()and the field valueare both private. As such, they are not accessible to any other classes, including sub-classes, ie. they are not inherited.

方法getValue()和字段value都是private。因此,它们不能被任何其他类访问,包括子类,即。它们不是遗传的。

In InnerClass#showValue()

InnerClass#showValue()

public void showValue() {
    System.out.println(getValue());
    System.out.println(value);
}

because of the fact that those are private, getValue()and valueare referring to the outer class' members, which are accessible because you are in the same class, ie. inner classes can access outer class private members. The above calls are equivalent to

因为这些是私有的,getValue()并且value指的是外部类的成员,这些成员可以访问,因为您在同一个类中,即。内部类可以访问外部类私有成员。以上调用等价于

public void showValue() {
    System.out.println(TestInnerClass.this.getValue());
    System.out.println(TestInnerClass.this.value);
}

And since you've set valueas

既然你已经设置value

new TestInnerClass("Initial value")

you see "Initial value"being printed twice. There is no way to access those privatemembers in the sub-class.

你看到"Initial value"被打印了两次。无法访问private子类中的这些成员。



The point is: don't make sub classes inner classes.

重点是:不要让子类成为内部类。

回答by Nakul Patekar

In the above case there are 2 different relations between TestInnerClass and InnerClass.

在上述情况下,TestInnerClass 和 InnerClass之间有两种不同的关系。

But there is a little twist in story.. there are two objects! and the problem is that we are putting "Another Value"into different object! and printing the valuefrom the old one..

但是故事有点曲折……有两个对象!问题是我们将“另一个价值”放入不同的对象中!并打印旧值的值..

First Object:

第一个对象:

public static void main(String[] args) {
    new TestInnerClass("Initial value").callShowValue();
}

Above method in Test Class creates an instance of TestInnerClass with "Initial value"

测试类中的上述方法创建了一个具有“初始值”的 TestInnerClass 实例

second Object:

第二个对象:

public void callShowValue() {
    new InnerClass("Another value").showValue();
}

Since the InnerClassis extending the TestInnerClassanother new Instance of TestInnerClass is created with "Another Value". But we are printing the value from old object not the second one.

由于InnerClass正在扩展TestInnerClass,因此使用"Another Value"创建了另一个新的 TestInnerClass 实例。但是我们正在打印旧对象的值而不是第二个。

回答by Rohit Jain

The key here is to understand how inner classes accesses the members of outer classes. And how is access to those members qualified in case of privateand non-privatemembers. (Note:I'll talk about non-staticinner classes here, as question is about that only).

这里的关键是理解内部类如何访问外部类的成员。以及如何访问那些符合条件的成员privatenon-private成员。(注意:我将static在这里讨论非内部类,因为问题仅与此有关)。

Inner classes store reference to enclosing instance:

内部类存储对封闭实例的引用:

An inner class stores a reference to the enclosing instance as a field. The field is named as this$0. The enclosing instance is always bound to the inner class object. When you create an object of inner class from inside the enclosing class, the reference value of this$0remains same for all of them, but thisreference would differ.

内部类存储对封闭实例的引用作为字段。该字段被命名为this$0。封闭实例始终绑定到内部类对象。当您从封闭类内部创建内部类的对象时,它们的引用值都this$0保持不变,但this引用会有所不同。

You access this$0field using Outer.thissyntax in the inner class. For example, consider this code:

您可以this$0使用Outer.this内部类中的语法访问字段。例如,考虑以下代码:

class Outer {
    public Outer() { }

    public void createInnerInstance() {
        Inner obj1 = new Inner();
        Inner obj2 = new Inner();
    }

    private class Inner {
        public Inner() {
            System.out.println(Outer.this);
            System.out.println(this);
        }
    }
}

public static void main(String[] args) {
    new Outer().createInnerInstance();
}

When you execute this code, you will get output like this:

当你执行这段代码时,你会得到这样的输出:

Outer@135fbaa4
Outer$Inner@45ee12a7
Outer@135fbaa4
Outer$Inner@330bedb4

Notice how 1stand 3rdreferences are same, while 2ndand 4thare different.

通知1如何第一和3个RD参考是相同的,而2和4是不同的。



Outer class members can be accessed in inner class using this$0reference:

可以使用this$0引用在内部类中访问外部类成员:

When you access the fields or any other member of outer class from inner class, the access expression is qualified with automatically this$0. You explicitly qualify the member access as this$0using OuterClass.thisreference. So, consider field valuein your outer class was public, then in the showValue()method in your inner class:

当您从内部类访问外部类的字段或任何其他成员时,访问表达式会自动使用this$0. 您明确地将成员访问限定为this$0使用OuterClass.this引用。因此,请考虑value外部类中的字段was public,然后在showValue()内部类中的方法中:

public void showValue() {
    System.out.println(TestInnerClass.this.value);
    System.out.println(value);
}

the first 2 print statements are equivalent. They would be compiled to the same byte code:

前 2 个打印语句是等效的。它们将被编译为相同的字节码:

 public void showValue();
   Code:
      0: getstatic     #3                  // Field java/lang/System.out:Ljava/
o/PrintStream;
      3: aload_0
      4: getfield      #1                  // Field this
public void showValue() {
    System.out.println(this.value);  // this won't compile
}
:LTestInnerClass; 7: getfield #4 // Field TestInnerClass.value:Ljava/lang/Stri g; 10: invokevirtual #5 // Method java/io/PrintStream.printl :(Ljava/lang/String;)V 13: getstatic #3 // Field java/lang/System.out:Ljava/ o/PrintStream; 16: aload_0 17: getfield #1 // Field this
public void showValue() { 
    System.out.println(value);            // inner class instance field
    System.out.println(this.value);       // inner class instance field
    System.out.println(Outer.this.value); // enclosing instance field
}
:LTestInnerClass; 20: getfield #4 // Field TestInnerClass.value:Ljava/lang/Stri g; 23: invokevirtual #5 // Method java/io/PrintStream.printl :(Ljava/lang/String;)V 26: return


You cannot access the outer class members explicitly using this:

您不能使用以下方法显式访问外部类成员this

If you explicitly try to qualify the field or method access expression with thisin the inner class, you will get a compiler error:

如果您this在内部类中明确尝试限定字段或方法访问表达式,您将收到编译器错误:

new Outer("rohit").callShowValue();

The above print statement won't compile, because valueis not a field of the inner class itself. It's an outer class field. thisrefers to the inner class instance, not the outer one.

上面的打印语句不会编译,因为value它不是内部类本身的字段。这是一个外部类字段。this指的是内部类实例,而不是外部类实例。



Story changes when inner class extends outer class:

当内部类扩展外部类时,故事会发生变化:

When your inner class extends the outer class, then is when things start to go weird. Because in that case, qualifying the field or method access with thiswill be valid for non-private members. For privatemembers, that would still not be valid, as privatemembers are not inherited.

当你的内部类扩展了外部类时,事情就开始变得奇怪了。因为在这种情况下,限定字段或方法访问this对非私有成员有效。对于private成员,这仍然无效,因为private成员不是继承的。

In case of inherited inner class, directly accessing the outer class members are qualified with this. That means, they will be accessed as inner class members. While explicitly qualifying the access with Outer.thiswill refer to the field of enclosing instance - this$0.

在继承内部类的情况下,直接访问外部类成员使用this. 这意味着,它们将作为内部类成员被访问。虽然明确限定访问 withOuter.this将引用封闭实例的字段 - this$0

Considering valuefield is declared as public:

考虑value字段声明为public

new Inner("rj").showValue();

the first two print statement will print the valuefield of the inner class instance, while the 3rd print statement will print the valuefield of enclosing instance. Confused?

前两个打印语句将打印value内部类实例的字段,而第三个打印语句将打印value封闭实例的字段。使困惑?

Remember I said, when you create multiple instance of inner class from inside the outer class, they will have same this$0reference.

记得我说过,当您从外部类内部创建内部类的多个实例时,它们将具有相同的this$0引用。

Consider you create an outer class instance:

考虑您创建一个外部类实例:

rj
rj
rohit

and then in callShowValue()method, you create an instance of inner class:

然后在callShowValue()方法中,创建内部类的实例:

public void showValue() { 
    System.out.println(value);            // enclosing instance field
    System.out.println(this.value);       // compiler error
    System.out.println(Outer.this.value); // enclosing instance field
}

Now, the output of the showValue()method would be:

现在,该showValue()方法的输出将是:

public void showValue() {
    System.out.println(getValue());
    System.out.println(value);
}

You would notice that, this.valueis different from Outer.this.value.

您会注意到,this.valueOuter.this.value.

What if you make valuefield private:

如果你制作value字段怎么办private

Now, when you make the outer class field private, then of course you can't access it using this.value;. So, the 2nd print statement won't compile.

现在,当您创建外部类 field 时private,当然您不能使用this.value;. 因此,第二个打印语句将无法编译。

And direct access of field in that case would be qualified with this$0this time. now change the field valueprivate, and modify the showValue()method as:

并且在这种情况下直接访问字段将符合this$0这个时间。现在更改字段value私有,并将showValue()方法修改为:

public void showValue() {
    System.out.println(TestInnerClass.this.getValue());
    System.out.println(TestInnerClass.this.value);
}

This is where the problem lies. The first print statement qualifies valuewith thisor this$0based on whether the field is publicor private.

这就是问题所在。第一个print语句资格valuethisthis$0基于字段是否public还是private



Coming to your concrete problem:

来到你的具体问题:

Now in your code, since both valuefield and getValue()method is private, the showValue()method:

现在在您的代码中,由于valuefield 和getValue()method 都是private,因此showValue()方法:

public void showValue() {
    System.out.println(super.getValue());
    System.out.println(super.value);
}

is same as:

与:

##代码##

which is accessing the field and method of enclosing instance. And the field is still Initial Value. And that is why the output is:

这是访问封闭实例的字段和方法。并且该字段仍然是Initial Value。这就是为什么输出是:

Initial Value
Initial Value

初始值
初始值

回答by Alex

The other answers have explained well why you are getting the results you see (you have two instances of TestInnerClassand are accessing the first), however there is actually a way to access the private members of TestInnerClassin its subclass - the keyword super.

其他答案很好地解释了为什么您会得到所看到的结果(您有两个实例TestInnerClass并且正在访问第一个),但是实际上有一种方法可以访问TestInnerClass其子类中的私有成员- 关键字super

If you replace your showValuemethod with this:

如果你showValue用这个替换你的方法:

##代码##

You will get the output that you expected.

您将获得预期的输出。

I would also suggest that if you decide to do this you make InnerClassa static inner class because it no longer needs a reference to an instance of its outer class.

我还建议,如果您决定这样做,您可以创建InnerClass一个静态内部类,因为它不再需要对其外部类的实例的引用。