А знаете ли Вы, что возвращает .getClass()?

от автора

Я думаю, почти любого Java разработчика когда-то спрашивали на собеседовании: «Какие есть методы у класса Object?»
Меня, по крайней мере, спрашивали неоднократно. И, если в первый раз это было неожиданностью (кажется, забыл про clone), то потом я был уверен, что уж методы Object’а-то я знаю;)

И каково же было мое удивление, когда спустя несколько лет разработки я наткнулся на собственное незнание сигнатуры метода getClass()

Под катом пара слов про Class, .class, .getClass и, собственно, сюрприз, на который я наткнулся.

Итак, у нас есть класс А и объект этого класса a:

public class A { } ... A a = new A(); 

0. a.class vs a.getClass()

Java позволяет обращаться к статическим методам / полям через объекты. Причем никакого полиморфизма тут нет, метод определяется на стадии компиляции:

a.class; // то же самое, что A.class ((Object)a).class; // то же самое, что Object.class 

Скрытый текст

Как я недавно писал тут, можно пойти дальше:

((A)null).class; // то же самое, что A.class 

Отсюда вытекает основное отличие class и getClass:

public class B extends A { { ...  A b = new B(); b.class; // то же самое, что A.class b.getClass(); // то же самое, что B.class 

Но это так, цветочки. Идем дальше.

1. А что такое этот ваш Class?

A.class — объект класса Class. Смотрим в Class.java:

public final class Class<T> implements ...  

Это дженерик. Причем типизирован он, очевидно, этим самым A — классом, у которого вызвали .class

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

public <T> T foo(Class<T> clazz); 

A.class возвращает объект класса Class:

Class<A> result = A.class; // Compilation successfull 

2. А что же возвращает a.getClass()?

Собрав воедино все вышесказанное, можно догадаться, что:

Class<A> result1 = a.getClass(); // Compilation error! 

Действительно, ввиду полиморфизма нужно не забывать, что фактический класс объекта a — не обязательно A — это может быть любой подкласс:

Class<? extends A> result = a.getClass(); // Compilation successfull 

3. А что же написано в Object.java?

Все эти дженерики — это, конечно, замечательно, но как записать сигнатуру метода getClass синтаксисом java в классе Object?
А никак:

public final native Class<?> getClass(); 

А на вопрос, почему не компилировался пример выше, ответит Максим Поташев джавадок к методу:

The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called.

ссылка на оригинал статьи http://habrahabr.ru/post/197802/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *