Почему Class.getClass () может отличаться от возвращаемого типа Class.cast ()? - PullRequest
9 голосов
/ 27 октября 2011

Я надеюсь, что вы можете помочь мне в этом вопросе.

Я искал ответы на этот вопрос, но все, что я мог найти, было связано с использованием универсального типа или общими инструкциями об отражении.1004 * Скажем, у нас есть родительский класс и дочерний класс, который расширяет этот родительский класс.Итак, смотрите ниже:

Parent v = new Child();

Если я сделаю v.getClass(), он вернет Child.Однако, если я сделаю v.getClass().cast(), он вернет объект типа Parent.

Кто-нибудь знает, почему это происходит?Я также взглянул на документацию по API Java и не смог найти причину ...

Спасибо за любые мысли.

Ответы [ 3 ]

19 голосов
/ 27 октября 2011

Существует важное различие между типом объекта во время выполнения и типом переменной или выражения во время компиляции.Тип выражения времени компиляции может только быть определенным из типов времени компиляции его компонентов.Типы времени выполнения объектов, которые являются значениями этих выражений, могут быть определены из типов времени выполнения параметров выражения, если они совместимы с типами времени компиляции.

Чтобы проиллюстрировать это, вВаш конкретный пример кода:

  • Переменная v имеет время компиляции тип Parent, но время выполнения тип значения, присвоенногоэто будет Child.
  • Выражение v.getClass() будет иметь тип времени компиляции тип Class<? extends Parent> (объект класса, представляющий тип Parent или один из его подклассов.).Его значение в время выполнения будет Child.class типа Class<Child>.
  • Выражение v.getClass().cast(obj) будет иметь время компиляции тип Parent,Его тип runtime будет типом времени выполнения obj, поскольку его значение во время выполнения фактически будет obj.(То есть, если obj имеет тип, который может быть назначен переменной типа Child, в противном случае cast() выдаст ClassCastException)
1 голос
/ 27 октября 2011

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

Вы получаете Class<Parent> как таковоеэто тип времени компиляции.

//compiletime v is of type Parent
Parent v = new Child(); 
//The class of a Parent object is either the Parent class or a child Class
Class<? extends Parent> cls = v.getClass();
//The return type of cast is the at compile time known upper bound, here it is 
//Parent, which is true since every Child object is also a Parent object.  
cls.cast(...);
//Note that this will throw a runtime exception, since it will perform a 
//cast to child at runtime. The cast uses the Child class at runtime and
//fails for other instances of Parent.
cls.cast(new Parent());

Вот упрощенный пример того, как вы можете его использовать.

class Test<T>{
  public Test(Class<T> cls){clazz = cls;}
  ArrayList<T> list = ...;
  Class<T> clazz;
  void add(Object o){
     list.add((T)o);//Cast does nothing at runtime
     list.add(clazz.cast(o)); //casts o to T
  }
}

Обычное приведение в форме (T) o не работает в Javaтак как универсальный тип T не известен во время выполнения.Jvm видит только приведенную верхнюю границу (объект), которая никогда не выходит из строя.Вместо этого можно использовать метод cast со ссылкой на реальный класс.

0 голосов
/ 27 октября 2011

Это связано с дизайном метода getClass () и обобщений.

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

Class<?> 

не

Class<Child> 

как и следовало ожидать.

Class<?> 

означает универсальный тип с параметром типа Object.

Итак, тип возвращаемого значения

Class<?>.cast() 

метод - Объект. То есть Общая природа этого метода не работает.

Вы можете написать

v3 = ( (Class<Child>) v.getClass() ).cast(v2);

но это бессмысленно, так как вы можете просто написать

v3 = ( Child ) v.getClass().cast(v2);

Кроме того, вы должны помнить, что генерики работают только во время компиляции. То есть genercis предназначены только для проверки типов в вашей IDE. Во время выполнения все генерики

<?>

Итак, на самом деле метод cast () ничего не делает во время выполнения. Это только заглушка для использования, когда у вас есть экземпляры типа

Class<something>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...