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

3 16

3 ответа:

Вызов 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 может быть выведена из экземпляра.

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

Я знаю, что это поздно в день.

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

Edit-Редактировать: После повторной попытки следующего кода и вызова getClass () он фактически не компилируется. Поэтому полностью игнорируйте предыдущие утверждения об объекте.getClass () - единственный доступный метод, который можно вызвать до инициализации родителя. Я понятия не имею, как это было упущено., и я прошу прощения за любую путаницу.