Genéricos de Java T vs Objeto

127

Me preguntaba cuál es la diferencia entre las siguientes dos declaraciones de métodos:

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

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

¿Hay algo que puedas / harías con uno pero no con el otro? No pude encontrar esta pregunta en otra parte de este sitio.

Abidi
fuente

Respuestas:

112

Aislado del contexto, no hay diferencia. En ambos ty objsolo puede invocar los métodos de Object.

Pero con contexto: si tiene una clase genérica:

MyClass<Foo> my = new MyClass<Foo>();
Foo foo = new Foo();

Luego:

Foo newFoo = my.doSomething(foo);

Mismo código con objeto

Foo newFoo = (Foo) my.doSomething(foo);

Dos ventajas:

  • sin necesidad de emitir (el compilador lo oculta de usted)
  • Tiempo de compilación de seguridad que funciona. Si Objectse utiliza la versión, no estará seguro de que el método siempre regrese Foo. Si regresa Bar, tendrás un ClassCastException, en tiempo de ejecución.
Bozho
fuente
14

La diferencia aquí es que en el primero, especificamos que la persona que llama debe pasar una instancia de Object (cualquier clase), y obtendrá otro Object (cualquier clase, no necesariamente del mismo tipo).

En el segundo, el tipo devuelto será el mismo tipo que cuando se definió la clase.

Example ex = new Example<Integer>();

Aquí especificamos qué tipo T será el que nos permita imponer más restricciones en una clase o método. Por ejemplo, podemos crear una instancia de LinkedList<Integer>o LinkedList<Example>y sabemos que cuando llamamos a uno de estos métodos, recuperaremos una instancia de Entero o Ejemplo.

El objetivo principal aquí es que el código de llamada puede especificar sobre qué tipo de objetos operará una clase, en lugar de depender de la conversión de tipos para hacer cumplir esto.

Ver Java Generics * de Oracle.

* Enlace actualizado.

Adán
fuente
13

La diferencia es que con los métodos genéricos no necesito emitir y obtengo un error de compilación cuando hago mal:

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;
    }
}

Usando el objeto siempre necesito lanzar y no obtengo ningún error cuando hago mal:

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;
    }
}
usuario1883212
fuente
Solo quiero mencionar que ya no tienes que lanzar objetos, a partir de Android 6.
John Lord
2

No necesitas hacer casting de clase adicional. En el primer caso, siempre obtendrá un objeto de clase java.lang.Object que deberá lanzar a su clase. En el segundo caso, T se reemplazará con la clase definida en la firma genérica y no se necesitará conversión de clase.

Andrey Adamovich
fuente
2

En tiempo de ejecución, nada. Pero en el momento de la compilación, el segundo realizará una verificación de tipo para asegurarse de que el tipo del parámetro y el tipo del valor de retorno coincidan (o sean subtipos de) con cualquier tipo de resolución (el primer ejemplo también realiza la verificación de tipo, pero cada objeto es un subtipo de objeto para que se acepten todos los tipos).

Jonathan
fuente
2

T es un tipo genérico. Lo que significa que puede ser sustituido por cualquier objeto calificado en tiempo de ejecución. Puede invocar dicho método de la siguiente manera:

String response = doSomething("hello world");

O

MyObject response = doSomething(new MyObject());

O

Integer response = doSomething(31);

Como puede ver, aquí hay polimorfismo.

Pero si se declara que devuelve Object, no puede hacer esto a menos que escriba cosas de lanzamiento.

adarshr
fuente
¿Podemos decir que con <T>no hay autoboxing?
SMUsamaShah
0

en el primer caso, toma un parámetro de cualquier tipo egstring y devuelve un tipo foo. En el segundo caso, toma un parámetro de tipo foo y devuelve un objeto de tipo foo.

fastcodejava
fuente