我有以下内部类的情况。
class Outer {
private class Inner1 extends InnerBase {
}
private class Inner2 extends InnerBase {
}
private class InnerBase {
}
}
通常我认为内部类有一个额外的,隐藏的“this”到外部类。
然而,会发生什么是内部类派生自另一个内部类?
所有内部类(Inner1,Inner2,InnerBase)都应该有一个额外的。
Inner1,Inner2会有自己的外部参考吗? 或者只是重用InnerBase中的一个,导致一个略微不同的行为?
(隐藏此= =指向外部类实例的引用)
答案 0 :(得分:2)
在内部,层次结构中的每个非静态内部类都有自己对this
的引用。您可以使用javap
$ javap -private Outer.Inner1
Compiled from "Outer.java"
class Outer$Inner1 extends Outer$InnerBase{
final Outer this$0;
private Outer$Inner1(Outer);
}
$ javap -private Outer.InnerBase
Compiled from "Outer.java"
class Outer$InnerBase extends java.lang.Object{
final Outer this$0;
private Outer$InnerBase(Outer);
Outer$InnerBase(Outer, Outer$1);
}
BTW,如果你真的想要,你可以利用一些不起眼的java语法,为父类和子类之间的this$0
成员提供不同的值。方法如下:
public class Outer {
class InnerBase {
Outer innerBaseOuter() { return Outer.this; }
}
class Inner1 extends InnerBase {
public Inner1() {}
public Inner1(Outer parentOuter) {
parentOuter.super(); // set a different super in InnerBase
}
Outer innerOuter() { return Outer.this; }
}
public static void main(String[] args) {
Outer outer1 = new Outer();
Outer outer2 = new Outer();
Inner1 a = outer1.new Inner1();
System.out.println("Checking (a.base == a.inner) => "+
(a.innerBaseOuter() == a.innerOuter()));
Inner1 b = outer1.new Inner1(outer2);
System.out.println("Checking (b.base == b.inner) => "+
(b.innerBaseOuter() == b.innerOuter()));
}
}
运行你得到的程序:
Checking (a.base == a.inner) => true
Checking (b.base == b.inner) => false
答案 1 :(得分:1)
每个人都会引用同一个Outer实例。它们每个都有自己对Outer的引用,但该引用将指向外部的同一个实例。由于无法更改引用,因此从其中任何引用引用外部都是等效的。
class Outer {
private class Inner1 extends InnerBase {
Outer getOuter() {
return Outer.this;
}
}
private class Inner2 extends InnerBase {
Outer getOuter() {
return Outer.this;
}
}
private class InnerBase {
Outer getOuter() {
return Outer.this;
}
}
public static void main(String[] args) {
new Outer().test();
}
public void test() {
System.out.println((new Inner1()).getOuter());
System.out.println((new Inner2()).getOuter());
System.out.println((new InnerBase()).getOuter());
}
}
答案 2 :(得分:1)
让我们来看看该计划:
public class Outer
{
public Outer() {}
class Inner1 extends Outer
{
public Inner1()
{
super(); // invokes Object() constructor
}
}
class Inner2 extends Inner1
{
public Inner2()
{
super(); // invokes Inner1() constructor
}
}
}
如果尝试编译它,则会发生错误。
Outer.java:12: cannot reference this before
supertype constructor has been called
super(); // invokes Inner1() constructor
因为Inner2
的超类本身就是一个内部类,一种晦涩的语言
规则发挥作用。如你所知,内部类的实例化,如
Inner1
,需要将一个封闭实例提供给构造函数。一般,
它是隐式提供的,但也可以使用超类显式提供
{@ 1}}
如果隐式提供封闭实例,编译器将生成表达式:
它使用this引用作为最里面的封闭类
超类是会员。诚然,这是相当满口的,但它是什么
编译器。在这种情况下,超类是expression.super(args)
。因为目前的班级,
Inner1
,间接扩展Outer,它将Inner1作为继承成员。因此,
超类构造函数的限定表达式就是这个。该
编译器提供一个封闭的实例,重写this.super。
默认的Inner2
构造函数尝试引用
在调用超类构造函数之前Inner2
,这是非法的。
解决这个问题的蛮力方法是提供合理的 明确地封闭实例:
this
这是编译,但它很复杂。有一个更好的解决方案:
每当你写一个成员班时,问问自己,这个班级真的需要吗?
一个封闭的实例?如果答案是否定的,请将其设为静态。内部课程是
有时很有用,但它们很容易引入制作程序的复杂功能
很难理解。它们与泛型有很复杂的相互作用,
反思和继承。如果你声明public class Outer
{
class Inner1 extends Outer { }
class Inner2 extends Inner1
{
public Inner2()
{
Outer.this.super();
}
}
}
是静态的,问题就出现了
远。如果你还声明Inner1
是静态的,你实际上可以理解是什么
该计划。
总之,一个类很少适合作为内部类和 另一个的子类。更一般地说,延伸内部很少是合适的 类;如果你必须,请仔细思考封闭的实例。大多数成员类可以而且应该被声明为静态。
答案 3 :(得分:0)
您的示例中只有一个级别的“内部”,因此每个内部类都可以访问Outer
类,如您所述。
以下是一个有趣的例子:
public class Test {
public static void main(String[] args) {
Level1 l1 = new Level1();
Level1.Level2 l2 = l1.new Level2();
Level1.Level2.Level3 l3 = l2.new Level3();
}
public static class Level1 {
private String s = "Level1";
public Level1() {
System.out.println(this + ": " + s);
}
public class Level2 {
private String s = "Level2";
public Level2() {
System.out.println(this + ": " + s);
System.out.println("Level1: " + Level1.this);
}
public class Level3 extends OtherLevel {
private String s = "Level3";
public Level3() {
System.out.println(this + ": " + s);
System.out.println("Level1: " + Level1.this);
System.out.println("Level2: " + Level2.this);
System.out.println("super: " + super.toString());
}
}
}
public class OtherLevel {
private String s = "OtherLevel";
public OtherLevel() {
System.out.println(this + ": " + s);
}
}
}
}
输出:
javaapplication4.Test$Level1@70284ac3: Level1
javaapplication4.Test$Level1$Level2@74a14fed: Level2
Level1: javaapplication4.Test$Level1@70284ac3
javaapplication4.Test$Level1$Level2$Level3@88d00c6: OtherLevel
javaapplication4.Test$Level1$Level2$Level3@88d00c6: Level3
Level1: javaapplication4.Test$Level1@70284ac3
Level2: javaapplication4.Test$Level1$Level2@74a14fed
super: javaapplication4.Test$Level1$Level2$Level3@88d00c6