Всегда ли безопасно вызывать getClass() внутри конструктора подкласса?

В статье о загрузке классов указано, что метод 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() внутри конструктора даст нам ошибки?

Ответы

Ответ 1

Будет ли вызов 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() в своем конструкторе после того, как конструктор супертипа был вызван - как вы уже указывали, после этого объект в основном готов, а ссылка Class может быть выведена из экземпляра.

Ответ 2

Причина, по которой вы не должны вызывать методы родительских классов, по крайней мере в вызове 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;
    }
}

Safe:

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() является единственным доступным методом для вызова перед инициализацией родителя. Я понятия не имею, как это пропустило, и я сожалею о какой-либо путанице.

Ответ 3

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

Я знаю это в конце дня.