奇怪的情况是“在调用超类型构造函数之前不能引用它” [英] Odd situation for "cannot reference this before supertype constructor has been called"

查看:142
本文介绍了奇怪的情况是“在调用超类型构造函数之前不能引用它”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 公共类A {
公共类B扩展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 Puzzlers 行为在本讨论中用作参考。


我能够将代码段减少到以下内容:

 公共类A {
B类延伸A {
}
void foo(){
new B(){}; //没有编译!!
}
}

此方案在 Java Puzzlers 拼图90:这是荒谬的,这是一种痛苦,它是超类!



给出的片段如下:

  public class Outer {//A
class Inner1 extends Outer {} //B
class Inner2 extends Inner1 {} //Banonymous
}
//没有编译!!

问题是由于定义了默认构造函数,我们确实有以下内容:

  //与上面相同但显式包含默认构造函数
public class Outer {
class Inner1 extends Outer {
Inner1(){super(); }
}
类Inner2扩展Inner1 {
Inner2(){super(); }
}
}
//仍然没有编译!

问题在于 Inner2 的超类本身是一个内部类 Inner1 ,从而使 Inner2 的默认构造函数非法,因为它需要提供一个封闭的实例到了构造函数。



修复问题的强力方法是明确地提供一个限定的 - this 表达式:

  //暴力破解修复
公共类外部{
class Inner1扩展了外部{
Inner1(){super(); }
}
类Inner2扩展Inner1 {
Inner2(){Outer.this.super(); }
}
}
//现在编译!

然而,这个谜题规定最好避免这种复杂的情况。以下是一些引用:


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

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



Why doesn't this code compile?

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

Compilation is successful if either of these changes are made:

  • B is private instead of public
  • line 7 reads new B(A); instead of new B(A) { }

Using javac version: 1.6.0_20

解决方案

It should be noted that Eclipse, javac, and Intellij IDEA exhibit differences in behaviors with regards to these snippets. javac and the Java Puzzlers behavior is used for reference in this discussion.

I was able to cut down the snippet to the following:

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

This scenario is discussed in Java Puzzlers, Puzzle 90: It's Absurd, It's a Pain, It's Superclass!

The snippet given is the following:

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

The problem is that due to how default constructor is defined, we really have the following:

// 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!!

The problem is that Inner2's superclass is itself an inner class Inner1, thus making Inner2's default constructor illegal since it requires an enclosing instance to be supplied to the constructor.

The "brute-force" way to fix the problem is to provide this explicitly with a qualified-this expression:

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

However, the puzzle prescribes that such complicated situation is best avoided in the first place. Here are some quotes:

This compiles, but it is mind-numbingly complex. There is a better solution: Whenever you write a member class, ask yourself, Does this class really need an enclosing instance? If the answer is no, make it static. Inner classes are sometimes useful, but they can easily introduce complications that make a program difficult to understand. They have complex interactions with generics (Puzzle 89), reflection (Puzzle 80), and inheritance (this puzzle). If you declare Inner1 to be static, the problem goes away. If you also declare Inner2 to be static, you can actually understand what the program does: a nice bonus indeed.

In summary, it is rarely appropriate for one class to be both an inner class and a subclass of another. More generally, it is rarely appropriate to extend an inner class; if you must, think long and hard about the enclosing instance. Also, prefer static nested classes to non-static. Most member classes can and should be declared static.

这篇关于奇怪的情况是“在调用超类型构造函数之前不能引用它”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆