¿Es posible resolver la advertencia del comstackdor “Una matriz genérica de T se crea para un parámetro varargs”?

Esta es una versión simplificada del código en cuestión, una clase genérica usa otra clase con parámetros de tipo generics y necesita pasar uno de los tipos generics a un método con parámetros varargs:

class Assembler { void assemble(X container, Y... args) { ... } } class Component { void useAssembler(T something) { Assembler assembler = new Assembler(); //generates warning: // Type safety : A generic array of T is // created for a varargs parameter assembler.assemble("hello", something); } 

}

¿Hay alguna forma correcta de pasar el parámetro genérico a un método varargs sin encontrar esta advertencia?

Por supuesto, algo así como

 assembler.assemble("hello", new T[] { something }); 

no funciona ya que no puede crear matrices genéricas.

Además de agregar @SuppressWarnings("unchecked") , no lo creo.

Este informe de errores tiene más información, pero se reduce a que al comstackdor no le gustan las matrices de tipos generics.

Tom Hawtin señaló esto en un comentario, pero para ser más explícito: sí, puedes resolverlo en el sitio de statement (en lugar de en los sitios de llamadas (potencialmente muchos)): cambia a JDK7.

Como puede ver en la publicación de blog de Joseph Darcy , el ejercicio Project Coin para seleccionar algunas pequeñas mejoras de lenguaje incrementales para Java 7 aceptó la propuesta de Bob Lee de permitir algo como @SuppressWarnings("varargs") en el lado del método para hacer que esta advertencia desaparezca en situaciones donde se sabía que era seguro.

Esto se ha implementado en OpenJDK con este compromiso .

Esto puede o no ser útil para su proyecto (¡muchas personas no estarían felices de cambiar a una versión inestable de la JVM!) Pero tal vez lo sea – o tal vez alguien que encuentre esta pregunta más tarde (después de que JDK7 esté fuera ) lo encontrará útil.

Si buscas una interfaz de tipo fluido, puedes probar el patrón del generador. No es tan conciso como varargs pero es seguro.

Un método estático de tipado genérico puede eliminar algunos de los estándares cuando se usa el constructor, al tiempo que se conserva el tipo de seguridad.

El constructor

 public class ArgBuilder implements Iterable { private final List args = new ArrayList(); public ArgBuilder and(T arg) { args.add(arg); return this; } @Override public Iterator iterator() { return args.iterator(); } public static  ArgBuilder with(T firstArgument) { return new ArgBuilder().and(firstArgument); } } 

Usándolo

 import static com.example.ArgBuilder.*; public class VarargsTest { public static void main(String[] args) { doSomething(new ArgBuilder().and("foo").and("bar").and("baz")); // or doSomething(with("foo").and("bar").and("baz")); } static void doSomething(Iterable args) { for (String arg : args) { System.out.println(arg); } } } 

La creación explícita de parámetros en Object in vararg method invocation hará feliz al comstackdor sin recurrir a @SuppressWarnings.

 public static  List list( final T... items ) { return Arrays.asList( items ); } // This will produce a warning. list( "1", 2, new BigDecimal( "3.5" ) ) // This will not produce a warning. list( (Object) "1", (Object) 2, (Object) new BigDecimal( "3.5" ) ) // This will not produce a warning either. Casting just the first parameter to // Object appears to be sufficient. list( (Object) "1", 2, new BigDecimal( "3.5" ) ) 

Creo que el problema aquí es que el comstackdor necesita averiguar qué tipo concreto de matriz crear. Si el método no es genérico, el comstackdor puede usar información de tipo del método. Si el método es genérico, intenta averiguar el tipo de matriz en función de los parámetros utilizados en la invocación. Si los tipos de parámetros son homogéneos, esa tarea es fácil. Si varían, el comstackdor intenta ser demasiado inteligente en mi opinión y crea una matriz genérica tipo unión. Entonces se siente obligado a advertirte sobre eso. Una solución más simple hubiera sido crear Objeto [] cuando el tipo no se puede reducir mejor. La solución anterior obliga a eso.

Para entender esto mejor, juegue con las invocaciones al método de la lista anterior en comparación con el siguiente método de la lista2.

 public static List list2( final Object... items ) { return Arrays.asList( items ); } 

Puede agregar @SafeVarargs al método desde Java 7, y no tiene que anotar en el código del cliente.

 class Assembler { @SafeVarargs final void assemble(X container, Y... args) { //has to be final... } } 

Puedes sobrecargar los métodos. Esto no resuelve tu problema, pero minimiza el número de advertencias (¡y sí, es un truco!)

 class Assembler { void assemble(X container, Y a1) { ... } void assemble(X container, Y a1, Y a2) { ... } void assemble(X container, Y a1, Y a2, Y a3) { ... } void assemble(X container, Y a1, Y a2, Y a3, Y a4) { ... } void assemble(X container, Y... args) { ... } } 

Es un problema muy fácil de resolver: Use List !

Deben evitarse las matrices de tipo de referencia.

En la versión actual de Java (1.7), puede marcar el método con @SafeVargs que eliminará la advertencia de la persona que llama. Sin embargo, ten cuidado con eso, y aún estás mejor sin arreglos heredados.

Consulte también las advertencias y compiler errors mejorado al usar parámetros formales no recuperables con la nota técnica de Varargs Methods .

Cuando funciono con arreglos de tipo genérico, me veo forzado a pasar una referencia al tipo genérico. Con eso, puedo hacer el código genérico, usando java.lang.reflect.Array.

http://java.sun.com/javase/6/docs/api/java/lang/reflect/Array.html