Java:非静态嵌套类和instance.super()

发布于 2024-09-01 15:56:32 字数 636 浏览 2 评论 0原文

我很难理解 Java 中的非静态嵌套类。考虑以下示例,它先打印“Inner”,然后打印“Child”。

class Outer {
    class Inner {
        Inner() { System.out.println("Inner"); }
    }
}

public class Child extends Outer.Inner {
    Child(Outer o) {
        o.super();
        System.out.println("Child");
    }
    public static void main(String args[]) {
        new Child(new Outer());
    }
}

我知道 Inner 的实例始终必须与 Outer 实例关联,这也适用于 Child,因为它扩展了 Inner。我的问题是 o.super() 语法的含义是什么 - 为什么它调用内部构造函数?

我只见过一个简单的 super(args) 用于调用超类构造函数和 super.method() 用于调用重写方法的超类版本,但从未见过形式为instance.super()

I'm having a hard time wrapping my head around non-static nested classes in Java. Consider the following example, which prints "Inner" and then "Child".

class Outer {
    class Inner {
        Inner() { System.out.println("Inner"); }
    }
}

public class Child extends Outer.Inner {
    Child(Outer o) {
        o.super();
        System.out.println("Child");
    }
    public static void main(String args[]) {
        new Child(new Outer());
    }
}

I understand that instances of Inner always have to be associated with an Outer instance, and that that applies to Child too since it extends Inner. My question is what the o.super() syntax means - why does it call the Inner constructor?

I've only seen a plain super(args) used to call the superclass constructor and super.method() to call the superclass version of an overridden method, but never something of the form instance.super().

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

流星番茄 2024-09-08 15:56:32

这称为“合格的超类构造函数调用”。

引用自此处 :

显式构造函数调用语句可以分为两种:

  • 备用构造函数调用以关键字 this 开头(可能以显式类型参数开头)。它们用于调用同一类的备用构造函数。

  • 超类构造函数调用以关键字 super(可能以显式类型参数开头)或主表达式开始。它们用于调用直接超类的构造函数。超类构造函数调用可以进一步细分:

<块引用>

  • 非限定超类构造函数调用以关键字 super 开头(可能以显式类型参数开头)。

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

It's called a "qualified superclass constructor invocation".

Citing from here:

Explicit constructor invocation statements can be divided into two kinds:

  • Alternate constructor invocations begin with the keyword this (possibly prefaced with explicit type arguments). They are used to invoke an alternate constructor of the same class.

  • Superclass constructor invocations begin with either the keyword super (possibly prefaced with explicit type arguments) or a Primary expression. They are used to invoke a constructor of the direct superclass. Superclass constructor invocations may be further subdivided:

  • Unqualified superclass constructor invocations begin with the keyword super (possibly prefaced with explicit type arguments).

  • Qualified superclass constructor invocations begin with a Primary expression . They allow a subclass constructor to explicitly specify the newly created object's immediately enclosing instance with respect to the direct superclass (§8.1.3). This may be necessary when the superclass is an inner class.

紫罗兰の梦幻 2024-09-08 15:56:32

内部类(非静态子类)本质上是嵌套类(静态子类),具有返回其父对象的隐式链接。这是上面的代码,使用静态嵌套类编写:

class Outer {
    static class Inner {
        final Outer outer;
        Inner(Outer outer) {
            this.outer = outer;
            System.out.println("Inner");
        }
    }
}

public class Child extends Outer.Inner {
    Child(Outer o) {
        super(o); // o.super();
        System.out.println("Child");
    }

    public static void main(String args[]) {
        new Child(new Outer());
    }
}

看看这个,您应该能够理解 o.super() 在做什么。

Inner Classes (non-static child classes) are essentially Nested Classes (static child classes) with implicit links back to their parent objects. Here is your above code, written instead using a static nested class:

class Outer {
    static class Inner {
        final Outer outer;
        Inner(Outer outer) {
            this.outer = outer;
            System.out.println("Inner");
        }
    }
}

public class Child extends Outer.Inner {
    Child(Outer o) {
        super(o); // o.super();
        System.out.println("Child");
    }

    public static void main(String args[]) {
        new Child(new Outer());
    }
}

Looking at this, you should be able to understand what o.super() was doing.

口干舌燥 2024-09-08 15:56:32

为什么 Child 中的 o.super() 最终会调用 Outer.Inner 构造函数?这很简单:因为 Child 扩展了 Outer.Inner,并且构造函数调用始终在层次结构中链接起来。

下面是对您的代码片段的稍微扩展以进行说明:

class Outer {
    Outer() {
        System.out.println("Outer");
    }
    void outerMethod() { }
    class Inner {
        Inner() {
            System.out.println("OuterInner");
            outerMethod();              
        }
        String wealth;
    }
}
class OuterChild extends Outer {
    OuterChild() {
        System.out.println("OuterChild");
    }
}
public class OuterInnerChild extends Outer.Inner {
    OuterInnerChild(Outer o) {
        o.super();
        System.out.println("OuterInnerChild");
        this.wealth = "ONE MILLION DOLLAR!!!";
    }
    public static void main(String args[]) {
        System.out.println(new OuterInnerChild(new Outer()).wealth);
        new OuterChild();
    }
}

这将打印:

Outer
OuterInner
OuterInnerChild
ONE MILLION DOLLAR!!!
Outer
OuterChild

一些关键观察结果:

  • 因为 OuterInnerChild 扩展了 Outer.Inner,所以它继承了 wealth,就像正常的子类语义一样
    • 就像正常的子类语义一样,OuterInnerChild 的构造函数链接到 Outer.Inner 的构造函数
  • 因为 OuterChild 扩展了 Outer,其构造函数链,即使没有显式调用
    • 无论是隐式还是显式,构造函数都会将层次结构链接起来

但是为什么编译器要求 OuterInnerChild 构造函数采用 Outer o,并且调用 o.super() ? p>

现在这是特定于内部类语义的:这样做是为了确保 OuterInnerChild 的所有实例都有一个 Outer.Inner 的封闭 Outer 实例, OuterInnerChild 的超类。否则,Outer.Inner 的构造函数将不会有一个 Outer 的封闭实例来调用 outerMethod()

Why does o.super() in Child ends up invoking Outer.Inner constructor? It's simple: because Child extends Outer.Inner, and constructor calls are always chained up the hierarchy.

Here's a slight expansion to your snippet to illustrate:

class Outer {
    Outer() {
        System.out.println("Outer");
    }
    void outerMethod() { }
    class Inner {
        Inner() {
            System.out.println("OuterInner");
            outerMethod();              
        }
        String wealth;
    }
}
class OuterChild extends Outer {
    OuterChild() {
        System.out.println("OuterChild");
    }
}
public class OuterInnerChild extends Outer.Inner {
    OuterInnerChild(Outer o) {
        o.super();
        System.out.println("OuterInnerChild");
        this.wealth = "ONE MILLION DOLLAR!!!";
    }
    public static void main(String args[]) {
        System.out.println(new OuterInnerChild(new Outer()).wealth);
        new OuterChild();
    }
}

This prints:

Outer
OuterInner
OuterInnerChild
ONE MILLION DOLLAR!!!
Outer
OuterChild

Some key observations:

  • Because OuterInnerChild extends Outer.Inner, it inherits wealth, just like normal subclass semantics
    • And just like normal subclass semantics, the constructor of OuterInnerChild chains to the constructor of Outer.Inner
  • Because OuterChild extends Outer, its constructor chains, even when not invoked explicitly
    • Whether implicitly or explicitly, the constructor chains up the hierarchy

But why does the compiler demand that OuterInnerChild constructor takes an Outer o, and that o.super() is invoked?

Now that is specific to inner class semantics: it's done to ensure that all instances of OuterInnerChild has an enclosing Outer instance for Outer.Inner, the super class of OuterInnerChild. Otherwise, the constructor of Outer.Inner would not have an enclosing instance of Outer to invoke outerMethod() on.

烈酒灼喉 2024-09-08 15:56:32

从概念上讲,非静态内部类“属于”特定对象。这有点像每个类都有自己的版本,就像非静态字段或方法属于特定对象一样。

这就是为什么我们有有趣的语法,如 instance.new Inner()instance.super() - 对于问题的答案“but whose<”的上下文/em> 内部?”并不是立即显而易见的。 (在外部类的非静态方法中,您可以只说 new Inner(),并且像往常一样,它是 this.new Inner() 的缩写。)

Conceptually, a non-static inner class “belongs” to a particular object. It's sorta like each one gets its own version of the class, much like a non-static field or method belongs to a particular object.

So that's why we have funny syntax like instance.new Inner() and instance.super() — for contexts where the answer to the question “but whose Inner?” isn't immediately obvious. (In a non-static method of the outer class, you can just say new Inner(), and as usual that's short for this.new Inner().)

贵在坚持 2024-09-08 15:56:32

永远不要忘记基本原则,在调用子类构造函数的过程中,无论内部/外部类如何,总是首先实例化父类。在您的场景中,当您扩展内部类并且您的内部类是父类的成员时,需要实例化然后调用实际的内部类构造函数。

Always not to forget basic principles, in process of calling a sub class constructor it's always the parent class is instantiated first irrespective of inner/outer classes. In your scenario, as you are extending inner class and your inner class is a member of parent class which needs to be instantiated then followed by calling the actual inner class constructor.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文