从子类隐式调用私有超类构造函数会导致随机行为

时间:2015-04-05 11:27:28

标签: java inheritance constructor

package pack1;
public class Outer{
    private Outer(){}
}

package pack2;
import pack1.*;
public class ExtendedOuter extends Outer{
        //compiler adds default no-args constructor, something like this
        /*
        public ExtendedOuter(){
             super(){}
        }
        */
}

now from a third class

import pack1.Outer;
import pack2.ExtendedOuter;
class InnerClasses{
    public static void main(String[] args){
        ExtendedOuter o=new ExtendedOuter();
    }
}
但是,嘿, Outer的构造函数是私有的,所以你希望这段代码不能编译,但编译得很好 只有在运行时我们知道我们在抛出IllegalAccessError时会搞砸 但这有时只会发生! 有时您会收到错误Outer() is private,有时您不会收到错误 如何解释这种随机行为?

但是在编译时警告私有方法调用。那么为什么不提到有意义的添加构造函数呢? PS:如果在Outer() is private in Outer class类中明确添加构造函数ExtendedOuter(){},编译器会抛出错误ExtendedOuter

修改----------------------

我很抱歉,但这没有任何意义。它确实不可预测,结果从一个汇编到另一个汇总不同 惊喜
好的,如果这不起作用,请尝试将外部构造函数的修饰符从private切换到public 好的,现在它可以工作并编译 现在再次将修改器切换到private,再次编译!它应该没有,不是吗?但是运行它,你会遇到IllegalAccessError

现在过了一段时间后,它甚至无法编译private,显示典型的消息Outer() is not public in Outer class 好极了现在再次将Outer()构造函数的修饰符切换为public,编译!现在再次将其切换到private,编译(而以前没有编译)

亲自尝试一下,让我知道 但不要忘记用-cp

编译javac

2 个答案:

答案 0 :(得分:0)

这个问题实际上是两个问题。不幸的是,由于问题的性质,这些答案有些推测。以下是我认为您想要回答的问题:

  

私有构造函数的编译机制是什么   从自动生成的默认构造函数引用?

如果您创建类private的构造函数,则该类不能进行子类化。 private构造函数是防止子类化为final关键字的有效方法;将强制所有子类通过super()尝试调用无法访问的构造函数。因为ExtendedOuter类仅隐式引用private类的Outer构造函数(通过生成的构造函数代码),编译器似乎并不知道您正在尝试调用无法访问的构造函数。

看起来您的编译器无法考虑默认构造函数生成的副作用。但是,在重新编译类时,编译器可能会采用以前编译中使用可用类字节码的快捷方式。字节码重用可以解释后续重新编译如何正确识别无法访问的构造函数。您的编译器无法通过代码分析确定它可以通过字节码分析来确定(假设当然,我不能确定无法访问您的确切编译器/机器/等)。

  

为什么我生成的提供的类结构的执行   尽管没有改变,IllegalAccessError仍然是非确定性的   编译代码?

如果查看Outer类,构造函数不包含任何分支或方法调用,以防止将其作为优化删除。生成的ExtendedOuter默认构造函数也可能受到JIT编译器的乐观删除。要完全回答这个问题,需要确定JIT编译器可能确定的方法和构造函数调用。

JIT编译器是一个复杂的主题,但JIT编译器透明地将内部构造函数调用内联或甚至完全替换为无操作符也不太可能。如果JIT编译器正在进行代码替换和优化,那么很容易导致程序的多次执行中的代码路径不一致。 JVM及其JIT编译器无法保证产生确定性输出。

答案 1 :(得分:-1)

如果尝试创建具有私有构造函数的类的对象,则编译器会抛出错误,因为在编译期间检测到对象创建是不可能的。在您的情况下,必须调用构造函数以验证对象创建。当创建类ExtendedOuter的对象时,编译器检查其可用的默认构造函数。在编译期间不调用任何方法。在运行时,调用类Outer的构造函数,结果为IllegalAccessError。 编译器的随机行为对我来说仍然不清楚。您在编译之前是否正在进行任何代码更改?您能否详细说明您正在执行的步骤以测试您的代码?