Java generics T vs Object
Мне было интересно, в чем разница между следующими двумя объявлениями метода:
public Object doSomething(Object obj) {....}
public <T> T doSomething(T t) {....}
Есть ли что-то, что вы можете сделать с одним, а не с другим? Я не мог найти этот вопрос в другом месте на этом сайте.
Ответы
Ответ 1
Изоляция от контекста - никакой разницы. На t
и obj
вы можете ссылаться только на методы Object
.
Но с контекстом - если у вас есть общий класс:
MyClass<Foo> my = new MyClass<Foo>();
Foo foo = new Foo();
Тогда:
Foo newFoo = my.doSomething(foo);
Тот же код с объектом
Foo newFoo = (Foo) my.doSomething(foo);
Два преимущества:
- нет необходимости в кастинге (компилятор скрывает это от вас)
- Сэкономить время на сборку. Если используется версия
Object
, вы не будете уверены, что метод всегда возвращает Foo
. Если он вернет Bar
, во время выполнения вы получите ClassCastException
.
Ответ 2
Разница здесь в том, что в первом мы указываем, что вызывающий должен передать экземпляр объекта (любой класс), и он вернет другой объект (любой класс, не обязательно одного и того же типа).
Во втором возвращенном типе будет тот же тип, что и при определении класса.
Example ex = new Example<Integer>();
Здесь мы укажем, какой тип T будет, который позволяет нам применять больше ограничений для класса или метода. Например, мы можем создать экземпляр LinkedList<Integer>
или LinkedList<Example>
, и мы знаем, что при вызове одного из этих методов мы вернем экземпляр Integer или Example.
Основная цель здесь состоит в том, что вызывающий код может указывать тип объектов, на которых будет действовать класс, вместо того, чтобы полагаться на литье типов для обеспечения этого.
См. Java Generics * от Oracle.
* Обновленная ссылка.
Ответ 3
Разница в том, что с помощью общих методов мне не нужно бросать, и я получаю ошибку компиляции, когда я делаю неправильно:
public class App {
public static void main(String[] args) {
String s = process("vv");
String b = process(new Object()); // Compilation error
}
public static <T> T process(T val) {
return val;
}
}
Использование объекта мне всегда нужно делать, и я не получаю никаких ошибок, если ошибаюсь:
public class App {
public static void main(String[] args) {
String s = (String)process("vv");
String b = (String)process(new Object());
}
public static Object process(Object val) {
return val;
}
}
Ответ 4
Во время выполнения ничего. Но во время компиляции вторая проведет проверку типов, чтобы убедиться, что тип параметра и тип возвращаемого значения соответствуют (или являются подтипами) любого типа T, разрешаемого (первый пример также проверяет тип, но каждый объект является подтип объекта, поэтому каждый тип будет принят).
Ответ 5
T - общий тип. Это означает, что он может быть заменен любым квалификационным объектом во время выполнения. Вы можете вызвать такой метод следующим образом:
String response = doSomething("hello world");
ИЛИ
MyObject response = doSomething(new MyObject());
ИЛИ
Integer response = doSomething(31);
Как вы можете видеть, здесь существует полиморфизм.
Но если он объявлен для возврата Object, вы не сможете этого сделать, если не набираете вещи.
Ответ 6
Вам не нужно делать дополнительное классное литье. В первом случае вы всегда получите объект класса java.lang.Object, который вам нужно будет применить к вашему классу. Во втором случае T будет заменен классом, определенным в общей сигнатуре, и не требуется классификация классов.
Ответ 7
в первом случае он принимает параметр любого типа, например, string и возвращает тип foo. Во втором случае он принимает параметр типа foo и возвращает объект типа foo.