Дженерики Java T vs Object

127

Мне было интересно, в чем разница между следующими двумя объявлениями методов:

public Object doSomething(Object obj) {....}

public <T> T doSomething(T t) {....}

Есть ли что-то, что вы можете сделать с одним, но не с другим? Я не мог найти этот вопрос где-либо еще на этом сайте.

Abidi
источник

Ответы:

112

Изолировано от контекста - без разницы. На обоих 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во время выполнения.
Bozho
источник
14

Разница здесь в том, что в первом мы указываем, что вызывающий должен передать экземпляр объекта (любой класс), и он вернет другой объект (любой класс, не обязательно того же типа).

Во втором случае возвращаемый тип будет того же типа, что и при определении класса.

Example ex = new Example<Integer>();

Здесь мы указываем, какой будет тип T, что позволяет нам наложить больше ограничений на класс или метод. Например, мы можем создать экземпляр LinkedList<Integer>или LinkedList<Example>и знаем, что когда мы вызываем один из этих методов, мы возвращаем экземпляр Integer или Example.

Основная цель здесь состоит в том, что вызывающий код может указывать, с каким типом объектов будет работать класс, вместо того, чтобы полагаться на приведение типов для обеспечения этого.

См. Java Generics * от Oracle.

* Обновлена ​​ссылка.

Адам
источник
13

Разница в том, что с универсальными методами мне не нужно приводить, и я получаю ошибку компиляции, когда делаю неправильно:

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;
    }
}
user1883212
источник
просто хочу упомянуть, что вам больше не нужно кастовать объекты,
Джон Лорд
2

Вам не нужно выполнять дополнительное приведение классов. В первом случае вы всегда получите объект класса java.lang.Object, который вам нужно будет преобразовать в свой класс. Во втором случае T будет заменен классом, определенным в универсальной сигнатуре, и преобразование классов не потребуется.

Андрей Адамович
источник
2

Во время выполнения ничего. Но во время компиляции второй будет выполнять проверку типа, чтобы убедиться, что тип параметра и тип возвращаемого значения совпадают (или являются подтипами) любого типа T (первый пример также выполняет проверку типа, но каждый объект является подтип объекта, поэтому будут приняты все типы).

Джонатан
источник
2

T - универсальный тип. Это означает, что он может быть заменен любым подходящим объектом во время выполнения. Вы можете вызвать такой метод следующим образом:

String response = doSomething("hello world");

ИЛИ

MyObject response = doSomething(new MyObject());

ИЛИ

Integer response = doSomething(31);

Как видите, здесь есть полиморфизм.

Но если объявлено, что он возвращает Object, вы не сможете этого сделать, если не наберете cast.

adarshr
источник
Можно ли сказать, что с <T>автобоксом нет?
SMUsamaShah
0

в первом случае он принимает параметр любого типа egstring и возвращает тип foo. Во втором случае он принимает параметр типа foo и возвращает объект типа foo.

fastcodejava
источник
0

Есть несколько причин, по которым вы можете рассматривать Generics over Object в Java:

  1. Дженерикс гибок и безопасен. В то же время работа с Object, требующим преобразования типов, подвержена ошибкам.
  2. Приведение типов в Java происходит медленно ref: [1]: https://www.infoworld.com/article/2076555/java-performance-programming--part-2--the-cost-of-casting.html
biddut
источник