将运行时解析参数传递给具有多个绑定类型的编译错误的方法 [英] Passing a runtime resolved parameter to a method which has multiple bound type, compilation error

查看:121
本文介绍了将运行时解析参数传递给具有多个绑定类型的编译错误的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个如下所示的方法:

  public static< T extends Enum< T> &安培; Marshallable> String foo(Collection< T> collection,Class< ;? extends Marshallable> ... marshallables); 

所以我期待收集的是一个Enum实现的Marshallable接口。
如果我在运行时具有具体的Enum类型,但是我写了一个测试方法,它会从类对象中动态创建一个Enum列表(实现Marshallable),并且无法将此列表传递给上面的方法。 p>

  @Test 
public void fooTest(){
...
if(clazz.isEnum ()){// collection enum xml
List< ;?扩展Enum <?扩展可编排>> enumList =(List< ;? extends Enum<?extends Marshallable>>)Arrays.asList(clazz.getEnumConstants());
- > String enumListXml = foo(enumList,clazz);
...

标记行会导致编译错误。我无法弄清楚如何在不改变方法签名的情况下传递列表。

解决方案

您需要使用通用帮助程序方法与未经检查的转换:

  private static< T extends Enum< T> &安培; Marshallable> void fooHelper(Class< ;? extends Marshallable> type){
if(type.isEnum()){

//这是安全的,因为isEnum检查,我们不返回任何
//带有T的类型(重要的是因为调用者可以指定T是什么)。
@SuppressWarnings(unchecked)
final Class< T> enumType =(Class< T>)类型;

最终列表< T> enumConstants = Arrays.asList(enumType.getEnumConstants());
foo(enumConstants);




$ b $ p
$ b

你的版本不起作用的原因是因为 T扩展Enum< T> &安培;可控制的 T 是递归绑定的 - 只能用类型参数表示。 中的通配符类型参数?扩展Enum <?



警告:

不会返回包含 T 的类型,因为这可能会导致堆污染。例如:

  private static< T extends Enum< T> &安培; Marshallable>列表与LT; T> unsafeFooHelper(Class< ;? extends Marshallable> type){
if(type.isEnum()){

//不再安全!
@SuppressWarnings(unchecked)
final Class< T> enumType =(Class< T>)类型;

返回Arrays.asList(enumType.getEnumConstants());
}
返回Collections.emptyList();
}

enum Enum1实现了Marshallable {ONE,TWO}

枚举Enum2实现了Marshallable {A,B}

...

//关于T是什么的调用者谎言:
List< Enum2> enumConstants = Main。< Enum2> unsafeFooHelper(Enum1.class);

//稍后...
Enum2 enumConstant = enumConstants.get(0); // ClassCastException


I have a method which looks like this:

public static <T extends Enum<T> & Marshallable> String foo(Collection<T> collection, Class<? extends Marshallable>... marshallables);

So I'm expecting the collection passed to be a Enum implementing Marshallable interface. It works fine if I have the concrete Enum types at runtime but I wrote a test method which creates an Enum list(implementing Marshallable) dynamically from class object, and I am having trouble passing this list into method above.

@Test
public void fooTest() {
...
if (clazz.isEnum()) { // collection enum xml
    List<? extends Enum<? extends Marshallable>> enumList = (List<? extends Enum<? extends Marshallable>>) Arrays.asList(clazz.getEnumConstants());
--> String enumListXml = foo(enumList, clazz);
...

Marked line will give compilation error. I couldn't figure out how to pass the list without changing method signatures.

解决方案

You'll need to use a generic helper method with an unchecked cast:

private static <T extends Enum<T> & Marshallable> void fooHelper(Class<? extends Marshallable> type) {
    if (type.isEnum()) {

        //This is safe because of the isEnum check, and we don't return any
        //type with T (important because the caller can specify what T is).
        @SuppressWarnings("unchecked")
        final Class<T> enumType = (Class<T>)type;

        final List<T> enumConstants = Arrays.asList(enumType.getEnumConstants());
        foo(enumConstants);
    }
}

The reason your version doesn't work is because with T extends Enum<T> & Marshallable, T is recursively bound - something that can only be expressed with type parameters. The wildcard type arguments in ? extends Enum<? extends Marshallable> no longer specify that relationship.

WARNING: It's imperative that fooHelper doesn't return a type containing T because this could cause heap pollution. For example:

private static <T extends Enum<T> & Marshallable> List<T> unsafeFooHelper(Class<? extends Marshallable> type) {
    if (type.isEnum()) {

        //no longer safe!
        @SuppressWarnings("unchecked")
        final Class<T> enumType = (Class<T>)type;

        return Arrays.asList(enumType.getEnumConstants());
    }
    return Collections.emptyList();
}

enum Enum1 implements Marshallable { ONE, TWO }

enum Enum2 implements Marshallable { A, B }

...

//caller lies about what T is:
List<Enum2> enumConstants = Main.<Enum2>unsafeFooHelper(Enum1.class);

//sometime later...
Enum2 enumConstant = enumConstants.get(0); //ClassCastException

这篇关于将运行时解析参数传递给具有多个绑定类型的编译错误的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆