2016-08-31 2 views
0

я следующие классы, определенные:.Использование GetClass() GetName() в ToString() методы

class BaseClass { 
    public String toString() 
    { 
     return "I am a: " + getClass().getName(); 
    } 
} 

class DerivedClass { 
    public String toString() 
    { 
     return super.toString(); 
    } 
} 

В моей основной функции() У меня есть следующий код:

BaseClass b = new BaseClass(); 
DerivedClass d = new DerivedClass(); 

System.out.println(b); 
System.out.println(d); // not sure why/how this works! 

As ожидается, я получаю правильные типы классов во время выполнения при выполнении этого кода:

I am a: BaseClass 
I am a: DerivedClass 

Мой вопрос, как именно вызов toString() в моей работе DerivedClass? В моем переопределении DerivedClass от toString() я звоню в super.toString(), который кажется, что он должен фактически вернуть «Я: BaseClass», потому что мы вызываем toString() в родительский класс.

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

Извините, если это звучит как вопрос о нобе, но я все еще обнимаю концепцию полиморфизма. Если бы кто-нибудь мог объяснить, почему это работает так, как я понимаю, я был бы признателен за любое понимание.

+0

'getClass(). GetName()' вернет тип ** runtime **. –

+1

https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#getClass-- –

+0

Когда вы вызываете метод экземпляра, в него неявно передается объект с именем 'this' , В этом случае 'this' является экземпляром' DerivedClass'. Поэтому вызов 'this.getClass()' (который вы вызываете) возвращает класс для 'DerivedClass'. – khelwood

ответ

2

getClass() является полиморфным методом. Он возвращает фактический конкретный класс объекта, на который он вызывается. С d идентификатор типа DerivedClass, его метод getClass() возвращает DerivedClass.class.

Вы получите результат, который вы ожидаете, если реализация метода был

return "I am a: " + BaseClass.class.getName(); 
+0

Спасибо за ответ! Кто-то еще указал (и я забыл) этот «этот» параметр, который также был отправлен в вызов super.toString(), поэтому теперь я вижу, что getClass() фактически вызывается на объекте DerivedClass через «этот» параметр. Еще раз спасибо! – ChicoMarx

0

Представьте ваши классы выглядел следующим образом:

class BaseClass { 
    @Override 
    public String toString() { 
     return "I am a: " + getClass().getName(); 
    } 

    public Class<?> getClass() { 
     return BaseClass.class; 
    } 
} 

class DerivedClass extends BaseClass { 
    @Override 
    public Class<?> getClass() { 
     return DerivedClass.class; 
    } 
} 

Из-за способа временной отмены работ, getClass() всегда будет возвращать DerivedClass.class когда вызывается на экземпляр DerivedClass, даже если он вызван из суперкласса BaseClass. Вызов super.toString() не меняет этого и на самом деле совершенно не нужен, так как реализация суперкласса наследуется по умолчанию.

Обратите внимание, что это всего лишь демонстрация того, что вы можете ожидать при вызове getClass(). В реальной жизни, getClass() на самом деле final native метод. Переопределение невозможно или необходимо.

+0

Спасибо за подробный ответ - меня вызвало вызов super.toString() в моем методе toString() DerivedClass. Я не был уверен, как Java знал (правильно) распечатать DerivedClass, поскольку он вызывается из базового класса toString(). Но я также забыл о «этом» параметре, который идентифицировал правильный объект для вызова метода toString(). Еще раз спасибо! – ChicoMarx

0

Ваш первый вопрос:

System.out.println (д); // не знаю, почему и как это работает!

И это хороший вопрос! В конце концов, вы передаете метод println ссылку, d, на экземпляр DerivedClass. Почему это приведет к фактическому вызову метода, который называется toString()?

Ответ на этот вопрос лежит в Javadoc для соответствующего метода println.Компилятор (javac) правильно компилирует ваш код, чтобы сказать, что вы заинтересованы в вызове метода println, который принимает Object. Обратите внимание, что println является перегруженным методом, и компилятор должен разрешить правильный метод на основе переданных аргументов. В этом случае метод разрешается до println(Object x), который содержит:

Распечатывает объект, а затем завершает линию. Этот метод вызывает сначала String.valueOf (x), чтобы получить строковое значение печатного объекта, а затем ведет себя так, как будто он вызывает печать (String), а затем println().

Затем вы посетите метод String.valueOf() и посмотреть:

public static String valueOf(Object obj) { 
    return (obj == null) ? "null" : obj.toString(); 
} 

Бинго! Это закрывает первый цикл, либо вызывается BaseClasstoString(), либо DerivedClass.

Фактическая причина, по которой вызван dgetClass(), имеет значение this. Как вы, возможно, знаете, каждый метод экземпляра в Java (например, toString()) получает невидимый параметр, называемый ссылкой this, в дополнение к аргументам, которые были объявлены. В этом конкретном случае, так как ссылкауказывает на d, все методы вызываются в этой ссылке. класс of d, очевидно, DerivedClass.

+0

Благодарим вас за подробный ответ! Другими словами, вызов super.toString() вызовет метод toString() в моем суперклассе (который в моем примере является BaseClass.toString()) ... Я забыл о «этом» параметре. Я не был уверен, почему getClass(). GetName() привел к печати «DerivedClass», но с учетом «этого» параметра это имеет большее значение. Еще раз спасибо! – ChicoMarx

+0

Справа. 'd.toString()' вызывает 'DerivedClass toString()', который вызывает 'getClass()' on 'd', потому что' this' указывает на 'd' в этой точке. И, очевидно, 'd.getClass()' должен возвращать ссылку на объект _class_, который представляет 'DerivedClass'. –

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