这是有问题的代码的简化版本,一个泛型类使用具有泛型类型参数的另一个类,并且需要将一个泛型类型传递给具有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);
}
Run Code Online (Sandbox Code Playgroud)
}
有没有正确的方法将泛型参数传递给varargs方法而不会遇到此警告?
当然有点像
assembler.assemble("hello", new T[] { something });
Run Code Online (Sandbox Code Playgroud)
由于无法创建通用数组,因此无效.
Cow*_*wan 57
Tom Hawtin在评论中指出了这一点,但更明确一点:是的,您可以在声明站点(而不是(可能很多)呼叫站点)解决此问题:切换到JDK7.
正如您在Joseph Darcy的博客文章中所看到的那样,项目硬币练习为Java 7选择了一些小的增量语言改进,接受了Bob Lee的建议,允许类似@SuppressWarnings("varargs")方法方面的事情在已知的情况下使这个警告消失安全.
这已在OpenJDK中通过此提交实现.
这可能对您的项目有用,也可能没有用(很多人不愿意切换到JVM的预发布不稳定版本!)但也许是 - 或者可能是稍后发现此问题的人(在JDK7出局之后) )会发现它很有用.
npg*_*all 16
如果您使用的是流畅的类型界面,则可以尝试使用构建器模式.不像varargs那样简洁,但它是类型安全的.
静态一般类型的方法可以在使用构建器时消除一些样板,同时保持类型安全性.
建设者
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);
}
}
Run Code Online (Sandbox Code Playgroud)
使用它
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在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" ) )
Run Code Online (Sandbox Code Playgroud)
我相信这里的问题是编译器需要弄清楚要创建的具体类型的数组.如果该方法不是通用的,则编译器可以使用该方法中的类型信息.如果该方法是通用的,它会尝试根据调用时使用的参数计算出数组类型.如果参数类型是同源的,那么该任务很容易.如果它们不同,编译器会在我看来太聪明并创建一个union-type泛型数组.然后它感到有必要警告你.当类型无法更好地缩小时,更简单的解决方案就是创建Object [].上述解决方案就是这样.
为了更好地理解这一点,请与以下list2方法相比,调用上面的列表方法.
public static List<Object> list2( final Object... items )
{
return Arrays.asList( items );
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
53002 次 |
| 最近记录: |