Обобщения Java T против Object - PullRequest
108 голосов
/ 06 марта 2011

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

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

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

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

Ответы [ 7 ]

93 голосов
/ 06 марта 2011

Изолировано от контекста - без разницы. На 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 во время выполнения.
10 голосов
/ 06 марта 2011

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

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

Example ex = new Example<Integer>();

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

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

См. Обобщение Java * от Oracle.

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

7 голосов
/ 02 октября 2015

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

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;
    }
}
2 голосов
/ 06 марта 2011

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

String response = doSomething("hello world");

OR

MyObject response = doSomething(new MyObject());

OR

Integer response = doSomething(31);

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

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

2 голосов
/ 06 марта 2011

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

1 голос
/ 06 марта 2011

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

0 голосов
/ 06 марта 2011

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

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