是否有可能解决“为可变参数创buildTgenerics数组”编译器警告?
这是所讨论代码的简化版本,一个generics类使用另一个具有genericstypes参数的类,并需要将其中一个genericstypes传递给具有可变参数参数的方法:
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); }
}
有没有任何正确的方法将通用parameter passing给可变参数方法而不会遇到此警告?
当然有点像
assembler.assemble("hello", new T[] { something });
不能工作,因为你不能创build通用数组。
除了添加@SuppressWarnings("unchecked")
,我不这么认为。
这个错误报告有更多的信息,但归结为不喜欢数组types的编译器。
Tom Hawtin在评论中指出了这一点,但要更明确一点:是的,您可以在声明站点(而不是(可能是多个)呼叫站点)解决此问题:切换到JDK7。
正如你可以在Joseph Darcy的博客文章中看到的那样,Project Coin练习为Java 7select了一些小的增量语言改进,接受了Bob Lee的build议 ,在方法方面允许@SuppressWarnings("varargs")
这个警告消失已知情况是安全的。
这个提交已经在OpenJDK中实现了。
这对你的项目可能有用也可能没有用(很多人不愿意切换到JVM的预发行不稳定版本!),但也许是 – 或者是稍后发现这个问题的人(在JDK7出来之后)会觉得很有用。
如果你在stream利的界面之后,你可以尝试一下builder模式。 不像可变参数那么简洁,但它是安全的。
一个静态的一般types的方法可以消除使用build造者时的一些样板,同时保持types安全。
build设者
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); } }
使用它
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); } } }
在vararg方法调用中将参数明确地转换为Object将使编译器感到高兴,而不诉诸于@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" ) )
我相信这里的问题是,编译器需要找出要创build的具体types的数组。 如果该方法不是通用的,则编译器可以使用方法中的types信息。 如果该方法是通用的,它将尝试根据调用时使用的参数找出数组types。 如果参数types是同质的,那么这个任务很容易。 如果它们有所不同,编译器会试图在我看来太聪明,并创build一个联合types的generics数组。 然后感觉不得不提醒你。 一个更简单的解决scheme就是在types无法更好地缩小的时候创buildObject []。 上面的解决scheme强制这一点。
为了更好地理解这一点,与以下list2方法相比,可以调用上面的list方法。
public static List<Object> list2( final Object... items ) { return Arrays.asList( items ); }
你可以重载方法。 这并不能解决你的问题,但它最大限度地减less了警告的数量(是的,这是一个黑客!)
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) { ... } }
当使用genericstypes的数组时,我被迫传递一个genericstypes的引用。 通过这个,我可以使用java.lang.reflect.Array来实现generics代码。
http://java.sun.com/javase/6/docs/api/java/lang/reflect/Array.html
这是一个很容易解决的问题:使用List<T>
!
应避免使用参考types的数组。
在Java(1.7)的当前版本中,您可以使用@SafeVargs
标记方法,这将删除调用者的警告。 小心,虽然,你还没有传统arrays更好。
使用可变参数方法使用不可维护forms参数时的改进编译器警告和错误技术说明。
从Java 7开始,您可以添加@SafeVarargs方法,而不必在客户端代码上进行注释。
class Assembler<X, Y> { @SafeVarargs final void assemble(X container, Y... args) { //has to be final... } }