В этом коде, почему он не может быть объявлен как Class<? extends B>
?
public class Foo<B> {
public void doSomething(B argument) {
Class<? extends Object> type = argument.getClass();
}
}
В этом коде, почему он не может быть объявлен как Class<? extends B>
?
public class Foo<B> {
public void doSomething(B argument) {
Class<? extends Object> type = argument.getClass();
}
}
Эта проблема заключается в том, что синтаксис Java не позволяет getClass() сказать, что он возвращает тип, который соответствует классу, определенному в нем, и это не является особым случаем в отношении компилятора. Таким образом, вы вынуждены использовать результат.
Существует много случаев, когда вы хотели бы указать тип this
, например. для цепочки, поэтому я надеюсь, что они включит эту функцию в один прекрасный день.
Вы можете написать
Class<? extends this> getClass();
или
public this clone(); // must return a type of this class.
или
class ByteBuffer {
this order(ByteOrder order);
}
class MappedByteBuffer extends ByteBuffer {
}
// currently this won't work as ByteBuffer defines order()
MappedByteBuffer mbb = fc.map(MapMode.READ_WRITE, 0, fc.size())
.order(ByteOrder.nativeOrder());
Это все о generic type erasure
. Из здесь:
Замените все параметры типа в общих типах их границами или объектом, если параметры типа не ограничены. Таким образом, полученный байт-код содержит только обычные классы, интерфейсы и методы. [во время компиляции]
Таким образом, вы не можете получить Class
фактического типа B
, но только ?
или ? extends Object
.
Если ваши границы будут превращаться в <B extends SomeClass>
вместо <B>
, тогда вы можете получить объект Class
типа <? extends SomeClass>
.
Object.getClass()
определено для возврата класса, где T - статически известный тип получателя (вызывается объект getClass()). Особо обратите внимание на вертикальные полосы, оператор стирания. Стирание переменной типа - это стирание ее левого края. В вашем случае это неявный связанный объект. Поэтому вы возвращаете класс, а не Class<? extends T>
.
Правильный способ сделать это,
abstract class AbstractExecutor<E> {
public void execute() throws Exception {
List<E> list = new ArrayList<E>();
Class<E> cls = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
E e = cls.getConstructor(String.class).newInstance("Gate");
list.add(e);
System.out.println(format(list));
}
// ...
}
Поскольку класс данного объекта не гарантированно совпадает с типом, в котором он хранится.
например.
Object o = "some string";
Class<Object> clazz = o.getClass(); // actually Class<String>
Изучая тип, вы должны ожидать класс для Object
, но на самом деле вы получаете класс для String
. Какую проблему вы можете задать - Object
является суперклассом String
, поэтому String
реализует все методы, реализованные в Object
.
Проблема заключается в том, что при получении Field
класс возвращает поля фактического класса, а не общий тип. Кроме того, пока Method
может вызывать правильный метод, если в данном объекте существует переопределяющий метод, он не может выполнить обратное и найти реализацию метода, который будет работать на данный объект.
Например, Object объявляет hashCode
, поэтому все объекты имеют метод хэш-кода. Однако следующее приведет к исключению во время выполнения:
Object.class.getMethod("hashCode").invoke("some string"); // works
String.class.getMethod("hashCode").invoke(new Object()); // fails
Это связано с тем, что объект Method
для hashCode
ожидает String
. Он ожидает генерировать хэш-код из последовательности символов, но предоставленный объект не имеет массив char для работы метода, поэтому он терпит неудачу.
Значение выглядит следующим образом: он должен работать, но не будет, потому что фактический метод, возвращаемый getMethod
, является методом хеш-кода для String
.
Object obj = "string";
Class<Object> clazz = obj.getClass();
clazz.getMethod("hashCode").invoke("another string");