为什么我需要提供封闭的类对象而不是封闭的类对象

时间:2015-03-26 19:17:09

标签: java inheritance inner-classes

class OuterA {
    class InnerA {
    }
}
class SubclassC extends OuterA.InnerA { 
    SubclassC(OuterA outerRef) {
        outerRef.super(); 
    }
}
class XYZ {
    public static void main(String[] args) {
        new SubclassC(new OuterA());
    }
}

在上面的代码中

  1. 为什么我需要将OuterA对象引用传递给。SubclassC构造函数以进行编译?
  2. 为什么InnerA对象引用不需要传递给SubclassC构造函数?

4 个答案:

答案 0 :(得分:6)

  

为什么我需要将OuterA对象引用传递给SubclassC构造函数才能编译.java文件?

因为SubclassC 扩展了 InnerA类的定义。同时,InnerA绑定OuterA(即InnerA的所有实例都将绑定到OuterA的相应实例。因此,要获取SubclassC的实例,您需要OuterA的实例。

  

为什么不需要将InnerA对象引用传递给SubclassC构造函数?

因为在创建SubclassC时,首先会创建其超类的实例,即会有InnerA的实例。您实际上可以将SubclassC视为特殊InnerA

答案 1 :(得分:4)

  
      
  1. 为什么我需要将OuterA对象引用传递给SubclassC构造函数以便编译.java文件?
  2.   

因为InnerAOuterA的内部类。这意味着OuterA.InnerA类型的对象或其任何子类型(例如SubclassC)只能存在于封闭类(在本例中为OuterA)实例的上下文中。

这称为合格的超类构造函数调用。来自JLS

  

合格的超类构造函数调用以Primary表达式开头。它们允许子类构造函数显式指定新创建的对象关于直接超类(第8.1.3节)的直接封闭实例。 当超类是内部类时,这可能是必要的。

如果您不需要将SubclassC实例链接到已存在的OuterA实例,则可以在OuterA构造函数中创建新的SuperclassC对象:

static class SubclassC extends OuterA.InnerA {
    SubclassC() {
        new OuterA().super();
    }
}
  
      
  1. 为什么不需要将InnerA对象引用传递给SubclassC构造函数?
  2.   

由于SubclassC延伸OuterA.InnerA执行outerRef.super()时,您正在调用OuterA.InnerA构造函数。要查看是这种情况,请考虑以下代码:

public class Example {
    static class OuterA {
        OuterA() {
            System.out.println("Call OuterA constructor");
        }
        class InnerA {
            InnerA() {
                System.out.println("Call InnerA constructor");
            }

        }
    }

    static class SubclassC extends OuterA.InnerA {
        SubclassC(OuterA outerRef) {
            outerRef.super();
            System.out.println("Call SuperclassC constructor");
        }
    }

    public static void main(String[] args) {
        OuterA outerA = new OuterA();
        System.out.println("Before new SuperclassC()");
        new SubclassC(outerA);
    }
}

输出:

Call OuterA constructor
Before new SuperclassC()
Call InnerA constructor
Call SuperclassC constructor

答案 2 :(得分:2)

1.Why do I need to pass OuterA object reference to SubclassC constructor for the .java file to compile? 

因为您需要知道该类实例的名称才能调用该函数,因为SubclassC扩展了类OuterA.InnerASubclassC extends OuterA.InnerA {

SubclassC(OuterA outerRef) {
        outerRef.super(); 

第二

2. Why is InnerA object reference not required to be passed to SubclassC constructor?

因为Innera在你创建对象new SubclassC(new OuterA());时正在调用的Outtera内部(即你不需要创建单独的对象,因为InnerA位于OuterA内在这种情况下,创建OuterA就足够了

答案 3 :(得分:2)

我们期望在构造函数运行之前发生两件事:

  • 基类(Object如果未使用extends)构造函数应该已经运行
  • 封闭的实例(如果有的话)应该已经完全构建,并且在程序中对它的引用正在进行中

Java通过在构造函数的开头自动放置super()调用来强制实施第一条规则。请注意,没有任何内容可以作为父实例:当您执行new File()时,您不需要提供Object - 所以没有您需要的谜InnerA 1}}在构建SubclassC时。

当在另一个类的词法范围中定义非静态类时,它可以访问封闭对象的字段:

class Outer {
  int val;
  class Inner {
    int val() {
      return val; // <-- we can access val, it's in scope
    }
  }
}

所以很明显我们需要一个链接。以下是通常创建链接的方式:

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // baroque, I admit

同样的事情发生在扩展Inner的类的第一行:

class InnerExtended extends Outer.Inner {
  public InnerExtended(Outer outer) {
    outer.super(); // <-- calls Outer.Inner ctor
  }
}

即使看到相似之处也不容易:

super();            // plain superclass ctor call
outer.new Inner();  // instantiation of inner class
outer.super();      // super() call in class extending inner