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.