useful type parameter method generic example are java generics

java - type - ¿Es posible resolver la advertencia del compilador "Una matriz genérica de T se crea para un parámetro varargs"?



java generics parameter (8)

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

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

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

class Assembler<X, Y> { void assemble(X container, Y... args) { ... } } class Component<T> { void useAssembler(T something) { Assembler<String, T> assembler = new Assembler<String, T>(); //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.




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

public static <T> List<T> 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 compilador necesita averiguar qué tipo concreto de matriz crear. Si el método no es genérico, el compilador 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 compilador 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<Object> 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<X, Y> { @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<X, Y> { 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) { ... } }


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<T> implements Iterable<T> { private final List<T> args = new ArrayList<T>(); public ArgBuilder<T> and(T arg) { args.add(arg); return this; } @Override public Iterator<T> iterator() { return args.iterator(); } public static <T> ArgBuilder<T> with(T firstArgument) { return new ArgBuilder<T>().and(firstArgument); } }

Usándolo

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


Tom Hawtin señaló esto en un comentario, pero para ser más explícito: sí, puedes resolverlo en el sitio de declaración (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.