Pregunta

public void wahey(List<Object> list) {}

wahey(new LinkedList<Number>());

La llamada al método no va a escribir-cheque. Ni siquiera puedo emitir el parámetro como sigue:

wahey((List<Object>) new LinkedList<Number>());

De mi investigación, he deducido que la razón para no permitir este tipo es la seguridad. Si se nos permitió hacer lo anterior, entonces podríamos tener lo siguiente:

List<Double> ld;
wahey(ld);

Dentro de la wahey método, se podría añadir algunas cadenas a la lista de entrada (como el parámetro mantiene una referencia List<Object>). Ahora, después de la llamada al método, LD se refiere a una lista con un List<Double> tipo, pero la actual lista contiene algunos objetos String!

Esto parece diferente a la forma normal de Java funciona sin los genéricos. Por ejemplo:

Object o;
Double d;
String s;

o = s;
d = (Double) o;

Lo que estamos haciendo aquí es esencialmente el mismo, excepto que esto pasará controles de tiempo de compilación y sólo un error en tiempo de ejecución. La versión con listas no se compilará.

Esto me lleva a creer que esto es puramente una decisión de diseño con respecto a las restricciones de tipos sobre los genéricos. Tenía la esperanza de conseguir algunos comentarios sobre esta decisión?

¿Fue útil?

Solución

Lo que está haciendo en el ejemplo "sin genéricos" es un molde, lo que deja claro que usted está haciendo algo tipo inseguro. El equivalente con los genéricos sería:

Object o;
List<Double> d;
String s;

o = s;
d.add((Double) o);

que se comporta de la misma manera (compila, pero falla en tiempo de ejecución). La razón para no permitir que el comportamiento que está pidiendo alrededor es porque permitiría acciones de tipo inseguro implícitos, que son mucho más difíciles de notar en el código. Por ejemplo:

public void Foo(List<Object> list, Object obj) {
  list.add(obj);
}

Esto se ve perfectamente bien y con seguridad de tipos hasta que llame así:

List<Double> list_d;
String s;

Foo(list_d, s);

Lo que también se ve con seguridad de tipos, ya que como la persona que llama no necesariamente sabe lo Foo va a hacer con sus parámetros.

Así que en ese caso de tener dos bits aparentemente con seguridad de tipos de código, que en conjunto terminan siendo de tipo inseguro. Eso es malo, porque es oculto y por lo tanto difícil de evitar y más difícil de depurar.

Otros consejos

Considere si era ...

List<Integer> nums = new ArrayList<Integer>();
List<Object> objs = nums
objs.add("Oh no!");
int x = nums.get(0); //throws ClassCastException

Usted sería capaz de añadir algo del tipo de los padres a la lista, que puede no ser lo que fue declarado anteriormente como, que en el ejemplo anterior demuestra, provoca todo tipo de problemas. Por lo tanto, no está permitido.

No son subtipos de la forma en sí debido genéricos trabajo. Lo que se quiere es declarar su función como esta:

public void wahey(List<?> list) {}

A continuación, se aceptará una lista de cualquier cosa que se extiende de objetos. También puede hacer:

public void wahey(List<? extends Number> list) {}

Esto le permitirá tomar en las listas de algo que es una subclase de Número.

Me gustaría recomendar que recoger una copia de "Java Genéricos y Colecciones" de Maurice Naftalin y Philip Wadler.

Hay esencialmente dos dimensiones de la abstracción aquí, la lista de la abstracción y la abstracción de su contenido. Está perfectamente bien para variar a lo largo de la lista de abstracción - a decir, por ejemplo, que es un LinkedList o un ArrayList - pero no está bien para restringir aún más el contenido, para decir: Esta (la lista que contiene los objetos) es una (lista enlazada cuales sostiene sólo números). Debido a que cualquier referencia que se conoce como (lista que contiene los objetos) entiende, por el contrato de este tipo, que puede contener cualquier objeto.

Esto es muy diferente de lo que ha hecho en el ejemplo de código que no son genéricos, donde se ha dicho: el tratamiento de esta cadena como si se tratara de un doble. Usted está en su lugar tratando de decir: tratar esta (lista que contiene sólo números) como (lista que contiene nada). Y no lo hace, y el compilador puede detectar, por lo que no le permite salirse con la suya.

  

"Lo que estamos haciendo aquí es esencialmente   lo mismo, excepto que esta pasará   tiempo de compilación cheques y sólo fallar en   en tiempo de ejecución. La versión con listas no lo hará   compilar ".

Lo que estamos observando tiene mucho sentido si tenemos en cuenta que el objetivo principal de genéricos de Java es conseguir incompatibilidades de tipo fallen en tiempo de compilación en lugar de tiempo de ejecución.

java.sun.com

  

Los genéricos proporciona una manera para que usted pueda   comunicar el tipo de una colección   para el compilador, por lo que puede ser   comprobado. Una vez que el compilador sabe la   tipo de elemento de la colección, el   compilador puede comprobar que ha utilizado   la colección constantemente y pueden   insertar los moldes sobre los valores correctos   siendo sacado de la colección.

En Java, List<S> no es un subtipo de List<T> cuando S es un subtipo de T. Esta norma proporciona seguridad de tipos.

Supongamos que permitimos que un List<String> a ser un subtipo de List<Object>. Consideremos el siguiente ejemplo:

public void foo(List<Object> objects) {
    objects.add(new Integer(42));
}

List<String> strings = new ArrayList<String>();
strings.add("my string");
foo(strings); // this is not allow in java
// now strings has a string and an integer!
// what would happen if we do the following...??
String myString = strings.get(1);

Así, obligando a que esto proporciona seguridad de tipos, pero también tiene un inconveniente, que es menos flexible. Consideremos el siguiente ejemplo:

class MyCollection<T> {
    public void addAll(Collection<T> otherCollection) {
        ...
    }
}

Aquí tienes una colección de de T, que desea añadir todos los artículos de otra colección. No se puede llamar a este método con un Collection<S> para un subtipo de S T. Idealmente, esto está bien, ya que sólo está añadiendo elementos en su colección, no se está modificando la colección de parámetros.

Para solucionar este problema, Java proporciona lo que ellos llaman "comodines". Los comodines son una forma de proporcionar covarianza / contravarianza. Ahora considere lo siguiente utilizando comodines:

class MyCollection<T> {
     // Now we allow all types S that are a subtype of T
     public void addAll(Collection<? extends T> otherCollection) {
         ...

         otherCollection.add(new S()); // ERROR! not allowed (Here S is a subtype of T)
     }
} 

Ahora, con comodines permitimos covarianza en el tipo T y bloqueamos operaciones que no son de tipo caja de seguridad (por ejemplo la adición de un elemento en la colección). De esta manera obtenemos la flexibilidad y el tipo de seguridad.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top