在子类构造函数中调用getClass()总是安全的吗?

时间:2014-08-29 04:49:56

标签: java class constructor classloader jls

An article on classloading表示不应在构造函数中调用方法getClass(),因为:

  

对象初始化仅在出口处完成   构造函数代码。

他们给出的例子是:

public class MyClassLoader extends ClassLoader{
    public MyClassLoader(){
        super(getClass().getClassLoader()); // should not call getClass() because object
                                            //    initialization will be complete only at
                                            //    the exit of the constructor code.
    }
}

但据我所知,本机最终方法getClass()将始终返回该对象实例的java.lang.Class对象,而不管其中被调用(在构造函数内或不)。

在构造函数中调用getClass() 会给我们带来问题吗?

如果是这样,在构造函数中调用getClass()会给我们带来错误的一些例子是什么?

3 个答案:

答案 0 :(得分:10)

  

在构造函数中调用getClass()会给我们带来问题吗?     如果是这样,在构造函数中调用getClass()的示例是什么     给我们错误?

以这种方式在构造函数中使用getClass()始终导致编译错误,因为在this被调用之前无法引用super()

Main.java:17: error: cannot reference this before supertype constructor has been called
        super(getClass().getClassLoader()); // should not call getClass() because object
              ^
1 error

您可以在http://ideone.com/B0nYZ1上自行测试。

Class已准备就绪,但实例尚未用于引用Class

尽管如此,你可以在构造函数中使用Class引用,但你必须以稍微不同的方式执行:super(MyClassLoader.class.getClassLoader())

此外,在调用超类型构造函数之后,您可以在构造函数中自由使用getClass() - 正如您已经指出的那样,该对象基本上已准备就绪并且{{ 1}}引用可以从实例中推断出来。

答案 1 :(得分:1)

至少在super()调用中你不应该调用父类方法的原因是,由于尚未构建父对象,因此无法知道方法是否能正确运行。你必须记住,调用是在父构造函数有机会准备它的数据之前发生的。

在super()调用之后,在合理范围内使用父方法应该是相当安全的,因为父对象已经完成了他们需要被认为可以使用的所有内容。我在合理范围内看到,因为父方法可能会调用覆盖子方法,您必须确保在构造期间可以安全地调用它们。

不安全:

public static class Base {
    public final void print() {
        System.out.println( this.get() );
    }

    public int get() {
        return 2;
    }
}

public static final class Sub extends Base {

    private int x;

    public Sub() {
        super();
        this.print();

        this.x = 1;
    }

    public int get() {
        return this.x;
    }
}

安全:

public static class Base {
    public final void print() {
        System.out.println( this.get() );
    }

    public int get() {
        return 2;
    }
}

public static final class Sub extends Base {

    private int x;

    public Sub() {
        super();
        this.x = 1;

        this.print();
    }

    public int get() {
        return this.x;
    }
}

编辑 - 编辑: 在重试以下代码并调用getClass()之后,它实际上没有编译。因此,完全忽略先前关于Object.getClass()的语句是在父初始化之前调用的唯一可用方法。我不知道如何错过,我很抱歉任何混乱。

答案 2 :(得分:1)

$ javac whose/MyClassLoader.java
whose/MyClassLoader.java:5: error: cannot reference this before supertype constructor has been called
        super(getClass().getClassLoader());
              ^
1 error

我知道现在已经很晚了。