考虑具有OuterClass
InnerClass
public class OuterClass {
class InnerClass {
}
}
第二节课,试图扩展InnerClass
OuterClass
public class Clazz extends OuterClass.InnerClass {
public Clazz(OuterClass outerClass) {
outerClass.super();
}
}
到目前为止这么好,这段代码会起作用,编译器不应该发出警告。
但我想了解 - 为什么需要传递给 OuterClass 的构造函数引用?为什么有必要称它为超级构造函数?
我想明白为什么必须这样确切?
另外,考虑这个类(与以前的类无关),其中类Apartments
和Hall
是Building
类的内部类,它是Solution
的内部类(内部感知) )。
public class Solution {
public class Building {
public class Hall {
private BigDecimal square;
public Hall(BigDecimal square) {
this.square = square;
}
}
public class Apartments {
}
}
}
然后是顶级类,它试图扩展内部内部类Hall
class BigHall extends Solution.Building.Hall {
public BigHall(Solution.Building building, BigDecimal square)
{
building.super(square);
}
}
看看这个烂摊子。最后两个类也应该编译,但是你可以为我清除它,为什么BigHall
类在扩展内部内部类Hall
时确实需要传递给构建对象而不是解决方案对象? / p>
如果你能提供JLS的报价,那就太好了!
答案 0 :(得分:7)
您的InnerClass
是inner class。
内部类是一个非显式或隐式的嵌套类 声明
static
。
内部类可能包含实例
直接内部班级
i
[您的C
] 的实例InnerClass
类或接口O
[您的OuterClass
] 与O
的实例,称为立即封闭i
的实例。
只有在静态上下文中声明的内部类才没有封闭实例。
内部类
I
的实例,其声明在静态中发生 上下文没有词汇封闭的实例。
您的示例的内部类不在静态上下文中,因此需要一个封闭的实例。
Java Language Specification然后陈述
隐式地使用非私有内部成员类的构造函数 声明,作为第一个形式参数,表示一个变量 立即封闭类的实例
(如果你感兴趣,它会进一步详细说明原因)。换句话说,您的InnerClass
构造函数看起来非常像
public InnerClass(OuterClass OuterClass.this){} // this is valid syntax for entirely different reasons
它期望类型OuterClass
的参数用作其封闭实例。对此InnerClass
类型进行子类化不会改变这种情况,特别是因为任何子类型都必须调用其超类型的超级构造函数。
关于构造函数的主题,specification also states
如果构造函数体不以显式构造函数开头 调用和声明的构造函数不是 原始类
Object
,然后构造函数体隐式开始 使用超类构造函数调用“super();”,调用 它的直接超类的构造函数,不带参数。
很明显,如果没有参数,您的代码将无效
public class Clazz extends OuterClass.InnerClass {
public Clazz() {
// implicit super() invocation
}
}
此super()
构造函数调用不起作用。在这种情况下,这是因为它是错误的语法。但是这个想法是超级构造函数期望表示封闭实例的形式参数的参数,但是你没有提供。正确的语法是您已有的语法。我们来定义它。
有multiple kinds of constructor invocations。此致
public Clazz(OuterClass outerClass) {
outerClass.super();
}
是限定的超类构造函数调用,defined为
合格的超类构造函数调用以
Primary
开头 表达式或ExpressionName
。 它们允许子类构造函数 显式指定新创建的对象立即封闭 关于直接超类的实例(第8.1.3节)。这可能是 当超类是内部类时必需。
chapter用来解释如何评估表达式
如果超类构造函数调用是合格的,那么
Primary
表达式或前一个ExpressionName
评估“.super
”,p
[...]否则,此评估的结果是立即封闭 关于
i
的S
的实例。
换句话说,outerClass
引用的对象成为Clazz
实例所需的封闭实例。
简单来说,忽略内部类的情况,你的例子归结为类似
public class Foo {}
public class Bar {
public Bar(Foo foo){}
}
public class SubBar extends Bar {
public SubBar(Foo foo) {
super(foo);
}
}
SubBar
必须满足期望Bar
实例的Foo
超级构造函数。这与你的Clazz
类型相同,只是它的超类型的构造函数是隐式的。
答案 1 :(得分:3)
为什么需要传递给OuterClass的构造函数引用?
仅仅因为InnerClass
的实例只能存在于OuterClass
的实例中,并且可以直接访问其封闭实例的方法和字段。这就是内部(非静态)类are designed in Java的方式。
UPD 当您要求提供JLS参考时,亲爱的@Boris,Spider在评论中提供了两次,它是JLS 8.1.3。但我个人觉得JLS对这件事的描述相当混乱。官方Java Doc教程以更简单的方式解释这些内容。
答案 2 :(得分:0)
考虑以下
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
}
}
}
在此示例中...每个Inner
都需要Outer
才能存在。 Inner
可以访问Outer
但StaticInner
不需要存在Outer
。它无法访问Outer
答案 3 :(得分:0)
内部类可以由其外部类之外的另一个类扩展。如果要扩展静态内部类(静态嵌套类),那么它是一个直接的实现。如果要扩展非静态内部类,则子类构造函数必须使用外部类的实例显式调用超类构造函数。因为,如果没有外部类的实例,则无法访问非静态内部类。
示例代码
class OuterClass
{
class InnerClassTwo
{
//Class as a non-static member
}
}
//Extending non-static inner class or member inner class
class AnotherClassTwo extends OuterClass.InnerClassTwo
{
public AnotherClassTwo()
{
new OuterClass().super(); //accessing super class constructor through OuterClass instance
}
}
编译器生成的内部代码
class Outer$Inner
{
final Outer this$0;
Outer$Inner()
{ super();
this$0 = Outer.this;
}
}