Почему класс не имеет хорошего общего типа в этом случае?

В этом коде, почему он не может быть объявлен как Class<? extends B>?

public class Foo<B> {
    public void doSomething(B argument) {
        Class<? extends Object> type = argument.getClass();
    }
}

Ответ 1

Эта проблема заключается в том, что синтаксис 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());

Ответ 2

Это все о generic type erasure. Из здесь:

Замените все параметры типа в общих типах их границами или объектом, если параметры типа не ограничены. Таким образом, полученный байт-код содержит только обычные классы, интерфейсы и методы. [во время компиляции]

Таким образом, вы не можете получить Class фактического типа B, но только ? или ? extends Object.

Если ваши границы будут превращаться в <B extends SomeClass> вместо <B>, тогда вы можете получить объект Class типа <? extends SomeClass>.

Ответ 3

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));
}

// ...

}

Ответ 4

Поскольку класс данного объекта не гарантированно совпадает с типом, в котором он хранится.

например.

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");