Ответы:
Изолировано от контекста - без разницы. На обоих 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
во время выполнения.Разница здесь в том, что в первом мы указываем, что вызывающий должен передать экземпляр объекта (любой класс), и он вернет другой объект (любой класс, не обязательно того же типа).
Во втором случае возвращаемый тип будет того же типа, что и при определении класса.
Example ex = new Example<Integer>();
Здесь мы указываем, какой будет тип T, что позволяет нам наложить больше ограничений на класс или метод. Например, мы можем создать экземпляр LinkedList<Integer>
или LinkedList<Example>
и знаем, что когда мы вызываем один из этих методов, мы возвращаем экземпляр Integer или Example.
Основная цель здесь состоит в том, что вызывающий код может указывать, с каким типом объектов будет работать класс, вместо того, чтобы полагаться на приведение типов для обеспечения этого.
См. Java Generics * от Oracle.
* Обновлена ссылка.
Разница в том, что с универсальными методами мне не нужно приводить, и я получаю ошибку компиляции, когда делаю неправильно:
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;
}
}
Вам не нужно выполнять дополнительное приведение классов. В первом случае вы всегда получите объект класса java.lang.Object, который вам нужно будет преобразовать в свой класс. Во втором случае T будет заменен классом, определенным в универсальной сигнатуре, и преобразование классов не потребуется.
Во время выполнения ничего. Но во время компиляции второй будет выполнять проверку типа, чтобы убедиться, что тип параметра и тип возвращаемого значения совпадают (или являются подтипами) любого типа T (первый пример также выполняет проверку типа, но каждый объект является подтип объекта, поэтому будут приняты все типы).
T - универсальный тип. Это означает, что он может быть заменен любым подходящим объектом во время выполнения. Вы можете вызвать такой метод следующим образом:
String response = doSomething("hello world");
ИЛИ
MyObject response = doSomething(new MyObject());
ИЛИ
Integer response = doSomething(31);
Как видите, здесь есть полиморфизм.
Но если объявлено, что он возвращает Object, вы не сможете этого сделать, если не наберете cast.
<T>
автобоксом нет?
в первом случае он принимает параметр любого типа egstring и возвращает тип foo. Во втором случае он принимает параметр типа foo и возвращает объект типа foo.
Есть несколько причин, по которым вы можете рассматривать Generics over Object в Java: