2015-06-29 4 views
3

Почему этот код возвращает только имя класса C. Когда я использую это, он должен возвращать имя класса конструктора, из которого я его использую.Каким будет тип объекта в цепочке конструкторов?

class A{ 
    public A() { 
     System.out.println(this.getClass().getName()); 
    } 
} 
class B extends A{ 
    public B() { 
     System.out.println(this.getClass().getName()); 
    } 
} 
class C extends B{ 
    public C() { 
     System.out.println(this.getClass().getName()); 
    } 
} 
class Main{ 
    public static void main(String[] args){ 
     new C(); 
    } 
} 
+5

Этот код ничего не возвращает.У него нет функции 'main', поэтому нет способа сказать, что именно вы используете. –

+1

Итак, вы создали объект типа 'C' и ожидали трех разных распечаток? Это не то, как работает наследование объектов. – Keppil

+0

Вы получите сообщение 'c', потому что вы переопределяете конструктор и объявляете экземпляр' c', – Ahmad

ответ

0

Прежде всего, при вызове new Child(), поскольку в классе Child нет объявленного конструктора без аргументов, это будет простой вызов super(), который вызывает конструктор родителя.

Затем, при выполнении this.getClass(). GetName(), здесь это означает экземпляр Child, поэтому в качестве результата вы получаете «Child». Помните, что объект # getClass() возвращает наиболее специфический класс, к которому принадлежит объект. см. больше от here.

4

this.getClass().getName() возвращает имя типа выполнения экземпляра this. Если вы создадите экземпляр C (new C()), он всегда будет возвращать «packagename.C». Не имеет значения, называете ли вы его кодом кода C или кодом в суперклассах C.

1

Некоторых родственные пункты:

1) Компилятор автоматически вставляет вызов на нет аргумента супер конструктор класса в любом конструкторе, который не содержит явный вызов конструктора суперкласса. (Я рекомендую вам выбирать явное поведение по неявному поведению при написании кода, но это спорная точка стиля). Во всяком случае компилятора ваш код будет выглядеть следующим образом:

class A{ 
    public A() { 
     System.out.println(this.getClass().getName()); 
    } 
} 

class B extends A{ 
    public B() { 
     super(); 
     System.out.println(this.getClass().getName()); 
    } 
} 

class C extends B{ 
    public C() { 
     super(); 
     System.out.println(this.getClass().getName()); 
    } 
} 

class Main{ 
    public static void main(String[] args){ 
     new C(); 
    } 
} 

Это дает понять, что System.out.println называют три отдельные раза.

2) Использование этого внутри конструктора для вызова методов может в целом привести к довольно странному поведению. См. Например: this. Это связано с тем, что инициализация работает следующим образом:

1) Вызывается конструктор класса C. В этот момент память выделяется для объекта класса C, а метаданные объектов, включая его класс, реализованные интерфейсы заполняются внутри виртуальной машины. Все поля, , включая унаследованные поля, инициализируются до их значением по умолчанию.

2) Вызывается конструктор класса B. Внутри конструктора это относится к объекту класса C, но ни одно из полей, инициализированных в конструкторе C, еще не было инициализировано. Это немедленно вызовет конструктор класса A.

3) Выполняется конструктор класса A. Поля, заданные в этом конструкторе, инициализируются. Конструктор выполняет методы и инициализации и возвращает, и стек возвращается к конструктору B.

4) Конструктор B выполняет свои методы и возвращает управление конструктору C.

5) Конструктор C возвращается.

Итак, теперь мы понимаем, что происходит: эта цепочка печатает C три раза. Я подозреваю, что вы хотите написать:

class A{ 
    public A() { 
     System.out.println(A.class.getName()); 
    } 
} 

class B extends A{ 
    public B() { 
     super(); 
     System.out.println(B.class.getName()); 
    } 
} 

class C extends B{ 
    public C() { 
     super(); 
     System.out.println(C.class.getName()); 
    } 
} 

class Main{ 
    public static void main(String[] args){ 
     new C(); 
    } 
} 

который распечатает A, B, C.

+1

* «Его плохой стиль, чтобы пропустить вызов super() в конструкторе подкласса» * Это, к счастью, неверно. Btw: http://stackoverflow.com/questions/2712971/do-you-put-a-super-call-a-the-beginning-of-your-constructors – Tom

+0

Ну, люди могут не согласиться на элементы стиля. Я бы решительно возражал, что вы всегда должны выбирать явное поведение по неявному поведению. Подобно тому, как положить окончательные определения аргументов, я думаю, что это помогает младшим программистам, и я поощряю это. –

+1

Иначе отредактируйте ответ, чтобы быть более дипломатичным. –

Смежные вопросы