代码之家  ›  专栏  ›  技术社区  ›  Chris Martin

“在调用超类型构造函数之前无法引用此”的奇怪情况

  •  14
  • Chris Martin  · 技术社区  · 14 年前

    为什么这段代码不能编译?

    public class A {
        public class B extends A {
            public B(A a) { }
        }
        void foo() {
            A a = new A();
            new B(a) { };
        }
    }
    

    A.java:[7,17] cannot reference this before supertype constructor has been called

    如果进行以下任一更改,则编译成功:

    • B 是私有的而不是公共的
    • new B(A); 而不是 new B(A) { }

    使用javac版本:1.6.0\u 20

    2 回复  |  直到 8 年前
        1
  •  20
  •   Mark Rotteveel    3 年前

    需要注意的是日食, javac 和Intellij IDEA在这些片段方面表现出不同的行为。 爪哇语 以及 Java解惑

    我可以将这个片段缩减为以下内容:

    public class A {
        class B extends A {
        }
        void foo() {
            new B() { }; // DOES NOT COMPILE!!
        }
    }
    

    此场景将在中讨论 Java Puzzlers , 谜题90:太荒谬了,太痛苦了,太超类了!

    给出的代码段如下:

    public class Outer {                   // "A"
        class Inner1 extends Outer  {}     // "B"
        class Inner2 extends Inner1 {}     // "B" anonymous
    }
    // DOES NOT COMPILE!!
    

    问题是,由于默认构造函数是如何定义的,我们实际上有以下几点:

    // Same as above but with default constructor included explicitly
    public class Outer {
        class Inner1 extends Outer  { 
            Inner1() { super(); }
        }
        class Inner2 extends Inner1 {
            Inner2() { super(); }    
        }
    }
    // STILL DOES NOT COMPILE!!
    

    Inner2 的超类本身就是一个内部类 Inner1 ,从而使 内部2

    解决这个问题的“暴力”方法是显式地提供一个限定的- this

    // "brute-force" fix
    public class Outer {
        class Inner1 extends Outer  { 
            Inner1() { super(); }
        }
        class Inner2 extends Inner1 {
            Inner2() { Outer.this.super(); }    
        }
    }
    // NOW COMPILES!
    

    然而,谜团规定,这种复杂的情况是最好避免放在首位。以下是一些引语:

    这很复杂,但却令人麻木。有一个更好的解决方案:每当你编写一个成员类时,问问自己,这个类真的需要一个封闭的实例吗?如果答案是否定的,那就做吧 static . 内部类有时很有用,但它们很容易引入复杂的问题,使程序难以理解。它们与泛型(拼图89)、反射(拼图80)和继承(这个拼图)有复杂的交互。如果你申报 成为 静止的 ,问题就消失了。如果你还申报 内部2 静止的

    总之,一个类既是内部类又是另一个类的子类是不合适的。一般来说,扩展一个内部类是不合适的;如果必须的话,请仔细考虑封闭的实例。另外,更喜欢 静止的 嵌套类到非- . 大多数成员类都可以而且应该声明 静止的

        2
  •  0
  •   David Blevins    14 年前

    不确定目标到底是什么,但试试这个。注意,我还删去了作为参数的传递,因为它们是非静态类,它们已经链接在一起了。我包含了引用外部类“this”的语法,用于那些内部类可能会覆盖外部类字段/方法的情况

    public class A {
    
        protected String field = "a";
    
        public class B extends A {
            protected String field = "b";
    
            public B() {
                System.out.println("" + A.this.field + " " + this.field);
            }
    
            @Override
            void foo() {
                System.out.println("b.foo()");
            }
        }
    
        void foo() {
            A a = new A();
            a.field = "a2";
            B b = a.new B() {
                @Override
                void foo() {
                    System.out.println("b.anon.foo()");
                }
            };
    
            b.foo();
        }
    
        public static void main(String[] args) {
            new A().foo();
        }
    }
    

    运行此命令将输出:

    a2 b
    b.anon.foo()