2016-09-14 119 views
1

Java的8方法签名如下所示:Java的泛型方法,通配符列表返回类型

public static <E extends CharSequence> List<? super E> m(List<E> list); 

而且在代码的某个地方,方法调用:

result = m(list); 

假设我已经创建参数list为如下:

List<String> list = new ArrayList<>(); 

我的问题是,为什么result可以是理由t raw List,甚至不能是List<Object>

+0

例如,我问为什么我的'结果'不能成为'List '或'List '。它可以只是原始的'List'。 – bladekp

+0

为什么你使用通配符作为返回类型?这是一个相当奇怪的事情... – fge

+0

@fge那是库方法,不是我的。 – bladekp

回答

2

调用带有List<String>作为参数就像调用下面的方法,你的方法:

public static List<? super String> m(List<String> list) { ... } 

考虑以下起始代码:

List<String> list = new ArrayList<>(); 
List<? super String> result = m(list); 

这需要上面提到的方法和存储返回值转换为变量result - 与方法的返回类型完全一致。

现在的问题是:什么变量 - 或更好的什么类型 - 你可以分配这个变量?所以我们谈论的是分配兼容性。

考虑这些任务:

List<String> result1 = result; // compiler error: type mismatch (not assignable) 
List<Object> result2 = result; // compiler error: type mismatch (not assignable) 

List result3 = result; // ok 
List<?> result4 = result; // ok 

List<? super String> result5 = result; // ok 
List<? extends Object> result6 = result; // ok 

要理解这个错误的性质,你必须知道,泛型是不变。这意味着,类型List<String>不是List<Object>的子类型 - 尽管类型StringObject具有这样的子类型层次结构。

所以,我们试图在这里的是:

  1. 分配List<? super String>List<String> =>失败,无分型
  2. 分配List<? super String>List<Object> =>失败,无分型
  3. 分配一个List<? super String>List =>成功,因为使用原始类型通常从类型检查中选择出来
  4. List<? super String>指定为List<?> =>成功,因为List<?>是所有List<...>
  5. 的超分配List<? super String>List<? super String> =>成功,因为...好...
  6. 分配List<? super String>List<? ectends Object> =>成功,因为List<? ectends Object>是基本上与List<?>相同。

注意,即试图分配List<? super String>List<? super CharSequence>List<? extends CharSequence>也将失败。它们不在子类型层次结构中。

这是为什么?编译器不能保证实际列表实例化的类型与约束条件? super/extends CharSequence相匹配。

1

你不能这样做的原因是因为Java泛型不是协变的。也就是,List<Object>而不是超级List<String>。然而,方法m的方法签名会允许返回List<String>,然后您将有一个List<Object>类型的参考指向List<String>。由于泛型类型信息在运行时不可用,因此这不会立即引发异常,但可能会导致无关位置出现类型错误。

例如,假设m被实现如下:

private static List<CharSequence> theResult = new ArrayList<>(); 

public static <E extends CharSequence> List<? super E> m(List<E> list) { 
    theResult.addAll(list); 
    return theResult; 
} 

然后使用方法如下将广告的非CharSequence对象到List<CharSequence>

List<Object> os = m(someList); 
os.add(new Object()); 

幸运的是,上述不不编译。