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
Accessing outer class members from within an inner class extending the outer class itself
提问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 value
to the private field value
of the TestInnerClass
class and then invokes the callShowValue()
method.
方法中的唯一语句main()
(最后一个片段)将值分配给类Initial value
的私有字段value
,TestInnerClass
然后调用该callShowValue()
方法。
The callShowValue()
method causes another string - Another value
to be set the to the private field value
of the TestInnerClass
class before invoking the showValue()
method of InnerClass
extending 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 value
are 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 value
are 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 value
as
既然你已经设置value
为
new TestInnerClass("Initial value")
you see "Initial value"
being printed twice. There is no way to access those private
members 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 private
and non-private
members. (Note:I'll talk about non-static
inner classes here, as question is about that only).
这里的关键是理解内部类如何访问外部类的成员。以及如何访问那些符合条件的成员private
和non-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$0
remains same for all of them, but this
reference would differ.
内部类存储对封闭实例的引用作为字段。该字段被命名为this$0
。封闭实例始终绑定到内部类对象。当您从封闭类内部创建内部类的对象时,它们的引用值都this$0
保持不变,但this
引用会有所不同。
You access this$0
field using Outer.this
syntax 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$0
reference:
可以使用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$0
using OuterClass.this
reference. So, consider field value
in 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 thispublic 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 thispublic 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 this
in the inner class, you will get a compiler error:
如果您this
在内部类中明确尝试限定字段或方法访问表达式,您将收到编译器错误:
new Outer("rohit").callShowValue();
The above print statement won't compile, because value
is not a field of the inner class itself. It's an outer class field. this
refers 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 this
will be valid for non-private members. For private
members, that would still not be valid, as private
members 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.this
will refer to the field of enclosing instance - this$0
.
在继承内部类的情况下,直接访问外部类成员使用this
. 这意味着,它们将作为内部类成员被访问。虽然明确限定访问 withOuter.this
将引用封闭实例的字段 - this$0
。
Considering value
field is declared as public
:
考虑value
字段声明为public
:
new Inner("rj").showValue();
the first two print statement will print the value
field of the inner class instance, while the 3rd print statement will print the value
field 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$0
reference.
记得我说过,当您从外部类内部创建内部类的多个实例时,它们将具有相同的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.value
is different from Outer.this.value
.
您会注意到,this.value
与Outer.this.value
.
What if you make value
field 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$0
this time. now change the field value
private, 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 value
with this
or this$0
based on whether the field is public
or private
.
这就是问题所在。第一个print语句资格value
用this
或this$0
基于字段是否public
还是private
。
Coming to your concrete problem:
来到你的具体问题:
Now in your code, since both value
field and getValue()
method is private
, the showValue()
method:
现在在您的代码中,由于value
field 和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 TestInnerClass
and are accessing the first), however there is actually a way to access the private members of TestInnerClass
in its subclass - the keyword super
.
其他答案很好地解释了为什么您会得到所看到的结果(您有两个实例TestInnerClass
并且正在访问第一个),但是实际上有一种方法可以访问TestInnerClass
其子类中的私有成员- 关键字super
。
If you replace your showValue
method with this:
如果你showValue
用这个替换你的方法:
You will get the output that you expected.
您将获得预期的输出。
I would also suggest that if you decide to do this you make InnerClass
a static inner class because it no longer needs a reference to an instance of its outer class.
我还建议,如果您决定这样做,您可以创建InnerClass
一个静态内部类,因为它不再需要对其外部类的实例的引用。