В такой функции:
<T> void foo(T obj)
Тип obj.getClass()
равен Class<?>
, а не Class<? extends T>
. Почему?
Следующий код работает нормально:
String foo = "";
Class<? extends String> fooClass = foo.getClass();
Таким образом, подпись T#getClass()
, кажется, возвращает Class<? extends T>
, верно?
Почему подпись отличается, если T
действительно является родовым?
Чтобы преодолеть проблему (и чтобы было более понятно, о чем я бродил), я реализовал эту функцию:
@SuppressWarnings("unchecked") static <T> Class<? extends T> classOf(T obj) {
return (Class<? extends T>) obj.getClass();
}
Опять вопрос: зачем нужен актерский состав здесь, а не в случае String
? И почему
SuppressWarnings
нужно? Разве из кода не всегда ясно, что он всегда сможет безопасно выполнить приведение?
Есть ли способ получить Class<? extends T>
от obj
? Если да, то как? Если нет, то почему?
Один из способов - использовать classOf
. Это было бы безопасно, верно? Если это всегда безопасно и дает безопасный способ действительно получить Class<? extends T>
(вместо Class<?>
), почему в Java нет такой функции? Или есть?
Как насчет этого случая:
<T> void bar(T[] array)
array.getClass().getComponentType()
снова возвращает Class<?>
, а не Class<? extends T>
. Почему?
Я реализовал эту функцию:
@SuppressWarnings("unchecked") static <T> Class<? extends T> classOf(T[] array) {
return (Class<? extends T>) array.getClass().getComponentType();
}
Это снова безопасно для использования?
Чтобы уточнить, о чем мне интересно. Рассмотрим этот демонстрационный код:
static interface I<T> {
Class<? extends T> myClass();
}
static class A implements I<A> {
public Class<? extends A> myClass() {
return this.getClass();
}
}
static <T> void foo(I<T> obj) {
Class<? extends T> clazz = obj.myClass(); // this works
}
Это отлично работает. Но то же самое не для Object#getClass()
.
Почему, например, не было возможности иметь общий интерфейс, такой как ClassInstance<T>
, с функцией getClass()
, и каждый Java-объект автоматически реализовывал это? Это будет иметь именно те улучшения, о которых я говорю, по сравнению с решением для расширения его от неуниверсального базового класса Object
.
или имеющий Object
в качестве универсального класса:
static abstract class Object<T> {
abstract Class<? extends T> myClass();
}
static class B extends Object<B> {
public Class<? extends B> myClass() {
return this.getClass();
}
}
static <T> void bar(Object<T> obj) {
Class<? extends T> clazz = obj.myClass(); // this works
}
Теперь представьте myClass()
как getClass()
и подумайте о том, что компилятор автоматически добавит это в каждый класс. Это решило бы много проблем с кастингом.
Главный вопрос, о котором я говорю: почему это не было сделано так?
Или, если выразить это другими словами: Здесь я более подробно опишу решение такой функции classOf
, которая преодолевает проблему. Почему это не было сделано, то есть оригинальная функция не такая?
(Я действительно не хочу получать ответ типа: то, как сейчас работает Java, то есть расширение от неуниверсального Object
, который определяет эту функцию, делает это невозможным. Я спрашиваю, почему решается как-то иначе, чтобы это было возможно.)