当前位置: 首页 > 知识库问答 >
问题:

为什么一个内部类的子类需要一个封闭的实例?

年文柏
2023-03-14

考虑类<代码> OuterClass < />代码> <代码> InnerClass < /代码>

public class OuterClass {
    class InnerClass {

    }
}

第二个类,它试图扩展外部类的内部类

public class Clazz extends OuterClass.InnerClass {
    public Clazz(OuterClass outerClass) {
        outerClass.super();
    }
}

到目前为止还不错,这个代码会工作,编译器不应该给出警告。

但我试图理解-为什么有必要传递给OuterClass的构造函数引用?为什么需要调用它的超级构造函数?

我想知道为什么必须这样精确?

此外,考虑这个类(与前几类无关),其中类<代码>公寓和 Hall 是内部类,即 建筑< /Cord>类,其内部是“代码>解决方案< /代码>(内嵌)。

public class Solution {
    public class Building {
        public class Hall {
            private BigDecimal square;

            public Hall(BigDecimal square) {
                this.square = square;
            }
        }

        public class Apartments {
        }
    }
}

然后是顶层教室,它试图扩建内部教室大厅

class BigHall extends Solution.Building.Hall {
    public BigHall(Solution.Building building, BigDecimal square)
    {
        building.super(square);
    }
}

看看这一团糟。最后两个类也应该编译,但您能帮我澄清一下吗,为什么在扩展内部类时,BigHallclass需要将对Building对象的引用传递给构造函数,而不是解决方案对象?

如果你能提供JLS的报价,那就太好了!


共有3个答案

公孙令秋
2023-03-14

考虑以下几点

public class Outer {
    String outerString;

    class Inner { 
        public void doStuff() {
            System.out.println("Outer string is " + outerString);
        }
    }


    static class StaticInner { 
        public void doStuff() {
            // can't access outerString here
        }
    }
}

在这个例子中...每个内部需要一个外部才能存在。内部可以从外部访问所有字段

但是StaticInner不需要Outer来存在。它无法从外部访问字段

杨成礼
2023-03-14

为什么必须传递给OuterClass的构造函数引用?

这仅仅是因为InnerClass的实例只能存在于OuterClass的实例中,并且可以直接访问其封闭实例的方法和字段。这就是Java中内部(非静态)类的设计方式。

UPD当您要求JLS参考时,亲爱的@Boris蜘蛛在评论中提供了两次,它是JLS 8.1.3。但我个人觉得JLS对这件事的描述相当混乱。官方的Java文档教程以更简单的方式解释了这些内容。

澹台景辉
2023-03-14
匿名用户

您的InnerClass是一个内部类。

内部类是未显式或隐式声明为静态的嵌套类。

内部类可能有封闭实例

类或接口的直接内部类C[yourInnerClass]O[yourOuterClass]的实例iO的实例关联,称为i的直接封闭实例。

只有在静态上下文中声明的内部类没有封闭实例。

声明发生在静态上下文中的内部类I的实例没有词汇封闭的实例。

示例的内部类不在静态上下文中,因此需要一个封闭实例。

然后,Java语言规范声明

非私有内部成员类的构造函数隐式声明一个变量作为第一个形式参数,该变量表示该类的直接封闭实例

(如果你感兴趣,它会进一步详细说明原因)。换句话说,您的InnerClass构造函数看起来真的像

public InnerClass(OuterClass OuterClass.this){} // this is valid syntax for entirely different reasons

它希望使用OuterClass类型的参数作为其封闭实例。子类化这个InnerClass类型不会改变这一点,特别是因为任何子类型都必须调用其超类型的超级构造函数。

关于施工人员,本规范还规定:

如果构造函数体不是以显式构造函数调用开始的,并且被声明的构造函数不是原始类Object的一部分,那么构造函数体隐式地以超类构造函数调用超级();开始,这是对它的直接超类不接受参数。

很明显没有参数你的代码就无法工作

public class Clazz extends OuterClass.InnerClass {
    public Clazz() {
        // implicit super() invocation
    }
}

这个super()构造函数调用不起作用。在这种情况下,这是因为它的语法错误。但其思想是,超级构造函数期望为表示封闭实例的形式参数提供一个参数,但您没有提供。正确的语法是您已有的语法。让我们来定义它。

有多种类型的构造函数调用。你的

public Clazz(OuterClass outerClass) {
    outerClass.super();
}

是一个合格的超类构造函数调用,定义为

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

第一章解释表达式是如何计算的

如果超类构造函数调用是合格的,则将计算表达式或紧接在""之前的ExpressionNamep

否则,该求值的结果是关于Si的立即封闭实例。

换句话说,由outerClass引用的对象成为您的Clazz实例所需的封闭实例。

简而言之,忽略内部类的情况,您的示例可以归结为

public class Foo {}
public class Bar {
    public Bar(Foo foo){}
}
public class SubBar extends Bar {
    public SubBar(Foo foo) {
        super(foo);
    }
}

SubBar必须满足需要Foo实例的Bar超级构造函数。这与您的Clazz类型发生的情况相同,只是它的超级类型的构造函数是隐式的。

 类似资料:
  • 问题内容: 术语“ 内部类” 通常被认为是“需要一个封闭实例的嵌套类”。但是,JLS声明如下: 8.1.3。内部类和封闭实例 […] 内部类包括本地(第14.3节),匿名(第15.9.5节)和非静态成员类(第8.5节)。 […] 内部类的声明发生在静态上下文中的实例没有词法包围的实例。 也, 15.9.5。匿名类声明 […] 匿名类始终是内部类(第8.1.3节);从来没有(§8.1.1,§8.5.

  • (我一直在重读那个问题标题,思考它看起来有多荒谬,但我向你保证,这是对问题的最佳描述,我有一个实际的应用程序,其中这是最好的结构。我发誓我没有疯。) 考虑以下内容。每个块都是一个单独的文件: 注意,enclosinstance业务是为了解决涉及中间构造函数调用的问题。请参阅“为什么外部类不能扩展内部类?”。 我希望输出为“2”。但是相反,我在System.out.println(a.this.I)

  • 我已经完成了一些Java教程,它们都说在调用类时创建一个新变量。这是为什么?我已经测试了一些代码,但它没有这样做。我已经使用python很长一段时间了,所以我习惯于使用动态语言。 请看下面我一直在玩的一些代码: 谢谢你的时间。

  • 我试图实现双向一对一映射,并从父实体(Project.java)插入子实体(ProjectDetails.java)。但是,实体管理器正在尝试插入null作为子实体(ProjectDetails)的id。 错误日志: 我已经尝试从@OneToOne中删除insertable=false和updatable=false,但是它给我一个错误,同一个列不能被引用两次。 我有以下实体类。 类别:项目 类:

  • 问题内容: 我正在使用Java 6。 我无法让内部类使用与其包含的类相同的泛型类。目前我有 现在我得到警告 类型参数T隐藏了类型T 如果我从内部类中删除类型参数(即从行中删除),则会在该行上出现编译错误。 我怎样才能使一切正确? 问题答案: 您可以: 从(即,使其成为非泛型的)中移除类型参数-仍然可以访问external 。 将class中的type参数重命名为(say)。 [更新] 下面是四种重

  • 在阅读java Doc时,我得到了以下东西。 内部类C是类O的直接内部类,如果O是C的直接词汇封闭类,并且C的声明不发生在静态上下文中 所以如果我写信 我的问题是在这两个内部类中,哪一个是O的直接内部类? 我也有一些观点。 2.如果类O是C的第n-1个词汇封闭类的直接封闭类,则它是C的第n个词汇封闭类。 3.类O的直接内部类C的实例i与O的实例关联,称为i的直接封闭实例。对象的直接封闭实例(如果有