Почему кастинг основан на Class.class, но не getClass?
У меня есть следующие 3 теста. Первые две работы, а последняя - нет. Моей мотивацией для этого вопроса является то, что я хотел бы использовать объект A
, чтобы он имел тот же класс, что и объект B
, когда A
известен подтипом B
.
@Test
public void testWorks() {
Object bar = "foobar";
String blah = (String) bar;
System.out.println(blah); // Outputs foobar
}
@Test
public void testAlsoWorks() {
Object bar = "helloworld";
String blah = String.class.cast(bar);
System.out.println(blah); // Outputs helloworld
}
@Test
public void testfails() {
Object bar = "foobar";
String thetype = "hello";
Class stringclass = thetype.getClass();
String blah = stringclass.cast(bar); // Compiler error: incompatible types: Object cannot be converted to String
System.out.println(blah);
}
Может ли кто-нибудь объяснить, почему последний случай терпит неудачу, когда первые два успеха, и почему это так? И что было бы лучшим подходом к достижению этого?
Ответы
Ответ 1
Вам нужно указать параметр типа Class
:
Class<String> stringclass = (Class<String>) thetype.getClass();
или
Class<? extends String> stringclass = thetype.getClass();
java.lang.Class.cast(Object obj)
задает объект классу или интерфейсу, представленному этим объектом класса.
Без указания типа вы не сообщаете компилятору, какой класс или интерфейс представлен экземпляром Class
stringclass
.
Когда вы вызываете String.class
, объект Class
неявно параметризуется с типом String
.
Ответ 2
Спецификация языка Java содержит
Тип C.class
, где C
- это имя класса, интерфейса или тип массива (§4.3), Class<C>
.
Итак, тип выражения
String.class
- Class<String>
. Class
- это общий класс, в котором метод cast
использует переменную типа generic в возвращаемом типе. Таким образом, результат
String.class.cast(bar);
- выражение типа T
, где T
привязано к String
в этом вызове.
Возвращаемый тип Object#getClass()
является Class<? extends T>
, где T
- это стертый тип выражения, на которое он вызывается.
В этом случае это
Class<? extends String>
Однако вы назначаете его исходной ссылке.
Class stringclass = thetype.getClass();
Так как переменная stringclass
raw, любые применения ее методов, зависящие от общей переменной типа, стираются.
Итак, Class#cast(Object)
теперь имеет тип возврата Object
, который не может быть назначен переменной String
.
Если бы вы сделали
Class<? extends String> stringclass = thetype.getClass();
вам будет хорошо.