2011-03-05 11 views
77

Me preguntaba ¿cuál es la diferencia entre las declaraciones siguientes dos métodos:los genéricos de Java T vs Objeto

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

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

¿Hay algo que se puede/haría con uno pero no el otro? No pude encontrar esta pregunta en otro lugar de este sitio.

Respuesta

65

Aislado del contexto - no hay diferencia. En ambos t y obj puede invocar solo los métodos de Object.

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

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

continuación:

Foo newFoo = my.doSomething(foo); 

mismo código con objeto

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

dos ventajas:

  • sin necesidad de fundición (el compilador lo oculta)
  • compile time safety that works. Si se utiliza la versión Object, no estará seguro de que el método siempre devuelva Foo. Si devuelve Bar, tendrá un ClassCastException, en tiempo de ejecución.
1

No es necesario hacer un casting de clase adicional. En el primer caso, siempre obtendrás un objeto de la clase java.lang.Object que deberás enviar a tu clase. En el segundo caso, T será reemplazado por la clase definida en la firma genérica y no se necesitará ninguna clase de fundición.

2

En tiempo de ejecución, nada. Pero en tiempo de compilación, el segundo hará una comprobación de tipo para asegurarse de que el tipo del parámetro y el tipo del valor de retorno coincidan (o sean subtipos de) cualquier tipo de T que resuelva (el primer ejemplo también verifica el tipo, pero cada objeto es subtipo de Object, por lo que se aceptará cada tipo).

2

T es un tipo genérico. Lo que significa que puede ser sustituido por cualquier objeto calificado en tiempo de ejecución. Es posible invocar un procedimiento tal como sigue:

String response = doSomething("hello world");

O

MyObject response = doSomething(new MyObject());

O

Integer response = doSomething(31);

Como se puede ver, no hay polimorfismo aquí.

Pero si se declara que se devuelve Object, no se puede hacer a menos que escriba cosas de fundición.

7

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

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

Example ex = new Example<Integer>(); 

Aquí especificamos qué tipo de T será que nos permite 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, obtendremos una instancia de Integer o Example.

El objetivo principal aquí es que el código de llamada pueda especificar el tipo de objetos sobre los que operará una clase, en lugar de depender del tipo de conversión para aplicar esto.

Ver Java Generics * de Oracle.

* Enlace actualizado.

0

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

5

La diferencia es que con los métodos genéricos que no necesito para emitir y me sale un error de compilación cuando lo haga 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 objeto Siempre necesito para emitir y yo no nos llevamos ningún errores 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; 
    } 
}