Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java “的奇怪情况;在调用超类型构造函数之前无法引用此;_Java - Fatal编程技术网

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

Java “的奇怪情况;在调用超类型构造函数之前无法引用此;,java,Java,为什么这段代码不编译 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]在调用超类型构造函数之前无法引用此 如果进行以下任一更改,则编译成功: B是私有的,而不是公共的 第7行显示为新的B(A)而不是新的B(A){}

为什么这段代码不编译

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]在调用超类型构造函数之前无法引用此

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

  • B
    是私有的,而不是公共的
  • 第7行显示为新的B(A)而不是
    新的B(A){}
使用javac版本:1.6.0_20

应该注意,Eclipse、
javac
和Intellij IDEA在这些代码片段方面表现出不同的行为
javac
和Java谜题行为在本讨论中用作参考

我能够将该片段缩减为以下内容:

public class A {
    class B extends A {
    }
    void foo() {
        new B() { }; // DOES NOT COMPILE!!
    }
}
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!!
这个场景在《谜题90》中进行了讨论:它是荒谬的,它是痛苦的,它是超类

给出的代码段如下所示:

public class A {
    class B extends A {
    }
    void foo() {
        new B() { }; // DOES NOT COMPILE!!
    }
}
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!!
问题在于,由于默认构造函数是如何定义的,我们实际上有以下几点:

public class A {
    class B extends A {
    }
    void foo() {
        new B() { }; // DOES NOT COMPILE!!
    }
}
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
,因此使得
Inner2
的默认构造函数非法,因为它需要向构造函数提供一个封闭实例

解决此问题的“暴力”方法是使用限定的-
this
表达式显式提供:

// "brute-force" fix
public class Outer {
    class Inner1 extends Outer  { 
        Inner1() { super(); }
    }
    class Inner2 extends Inner1 {
        Inner2() { Outer.this.super(); }    
    }
}
// NOW COMPILES!
然而,这个谜题规定,首先最好避免这种复杂的情况。以下是一些引文:

这是一个汇编,但它是令人麻木的复杂。有一个更好的解决方案:每当您编写一个成员类时,问问自己,这个类真的需要一个封闭的实例吗?如果答案为否,则将其设置为静态。内部类有时是有用的,但它们很容易引入使程序难以理解的复杂性。它们与泛型(谜题89)、反射(谜题80)和继承(这个谜题)有复杂的交互作用。如果将
Inner1
声明为
static
,则问题将消失。如果您还将
Inner2
声明为
static
,您实际上可以理解该程序的功能:这确实是一个不错的奖励

总之,将一个类同时作为另一个类的内部类和子类是不合适的。更一般地说,扩展一个内部类是不合适的;如果必须,请仔细考虑封闭实例。另外,与非
静态类相比,更喜欢
静态类
嵌套类。大多数成员类可以而且应该声明为静态的


不确定目标到底是什么,但试试这个。注意,我还删除了作为参数传递的非静态类,因为它们已经链接。我包括了引用外部类“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()

希望这有帮助

你认为新的B(a){}
有什么作用?新的B(a){}应该实例化一个匿名的B子类,它的默认构造函数调用super(a)。显然,我试图编写的实际代码在该块中有重写方法-新的B(a){/*东西在这里*/}-但是为了简化这个问题,我删除了不必要的代码。这在Joshua Bloch的Java拼图中是90。在其示例章节中以#9的形式提供:。就我个人而言,即使在阅读了解决方案之后,我也无法理解它。我还将注意到Intellij IDEA与每个人都不一致——它认为所有这些代码都很好。axtavt链接的文档进一步简化了这一点。仅使用命名类:公共类A{class B扩展A{}类C扩展B{}这一次,即使IDEA也注意到了一些错误:“在调用超类型构造函数之前无法引用C.This”这是一个很好的答案-这在技术上是有意义的,而且,它的结论是绝对正确的:我遇到了麻烦,最终,因为B本来应该是静态的。我最终把我真实代码中的“B”变成了一个顶级类。