繁体   English   中英

有多少外**这个**会有这个内心阶级?

[英]How many outer **this** will have this inner class?

我有以下内部类的情况。

class Outer {
   private class Inner1 extends InnerBase {
   }
   private class Inner2 extends InnerBase {
   }
   private class InnerBase {
   }
}

通常我认为内部类有一个额外的,隐藏的“this”到外部类。

但是,会发生什么是内部类派生自另一个内部类?

所有内部类(Inner1,Inner2,InnerBase)都应该有一个额外的。

Inner1,Inner2会有自己的外部引用吗? 或者只是重用InnerBase中的那个,导致一个略有不同的行为?

(隐藏此= =指向外类实例的引用)

内部层次结构中的每个非静态内部类将有自己的参照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);
}

顺便说一句,如果你真的想要,你可以利用一些不起眼的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

每个都将引用同一个Outer实例。 它们每个都有自己对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());
    }
}

我们来看看这个节目:

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的实例化需要将封闭实例提供给构造函数。 通常,它是隐式提供的,但它也可以使用表单expression.super(args)的超类构造函数调用显式提供。

如果隐式提供了封闭实例,则编译器将生成表达式:它将此引用用于超类所属的最内层封闭类。 诚然,这是相当令人满意的,但它正是编译器所做的。 在这种情况下,超类是Inner1 因为当前类Inner2间接扩展了Outer,所以它将Inner1作为继承成员。 因此,超类构造函数的限定表达式就是这样。 编译器提供一个封闭的实例,重写super到this.super。

默认的Inner2构造函数尝试在调用超类构造函数之前引用this ,这是非法的。

解决此问题的蛮力方法是明确提供合理的封闭实例:

public class Outer
{
    class Inner1 extends Outer { }
    class Inner2 extends Inner1 
    {
        public Inner2() 
        {
            Outer.this.super();
        }
    }
}

编译,但它很复杂。 有一个更好的解决方案: 每当你编写一个成员类时,问问自己,这个类真的需要一个封闭的实例吗? 如果答案是否定的,请将其设为静态 内部类有时是有用的,但它们很容易引入使程序难以理解的复杂性。 它们与泛型,反射和继承有着复杂的相互作用。 如果将Inner1声明为静态,则问题就会消失。 如果你还声明Inner2是静态的,你实际上可以理解程序的作用。

总之,一个类很少适合作为另一个类的内部类和子类。 更一般地说,扩展内部阶级很少是合适的; 如果你必须,请仔细思考封闭的实例。 大多数成员类可以而且应该被声明为static。

在您的示例中只有一个级别的“内部”,因此每个内部类都可以像您提到的那样访问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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM