为什么必须使用泛型类型Map<?, ? extends List<?>>而不是更简单Map<?, List<?>>的test()方法?
public static void main(String[] args) {
Map<Integer, List<String>> mappy =
new HashMap<Integer, List<String>>();
test(mappy);
}
public static void test(Map<?, ? extends List<?>> m) {}
// Doesn't compile
// public static void test(Map<?, List<?>> m) {}
Run Code Online (Sandbox Code Playgroud)
注意到以下工作,并且三种方法无论如何都具有相同的擦除类型.
public static <E> void test(Map<?, List<E>> m) {}
Run Code Online (Sandbox Code Playgroud) 以下类定义了两种方法,两种方法都直观地具有相同的功能.使用两个类型列表List<? super Integer>和一个布尔值调用每个函数,该值指定应将哪些列表分配给局部变量.
import java.util.List;
class Example {
void chooseList1(boolean choice, List<? super Integer> list1, List<? super Integer> list2) {
List<? super Integer> list;
if (choice)
list = list1;
else
list = list2;
}
void chooseList2(boolean choice, List<? super Integer> list1, List<? super Integer> list2) {
List<? super Integer> list = choice ? list1 : list2;
}
}
Run Code Online (Sandbox Code Playgroud)
根据javac 1.7.0_45,chooseList1有效而chooseList2不是.它抱怨说:
java: incompatible types
required: java.util.List<? super java.lang.Integer>
found: java.util.List<capture#1 of ? extends …Run Code Online (Sandbox Code Playgroud) 无界通配符<?>和绑定通配符之间是否有区别Object,例如<? extends Object>?
我记得曾经在某处看过,仿制药的早期草稿有所不同,但是找不到那个来源了.
我是Java新手.在本 文档中,他们将此作为使用通配符的用例:
static void printCollection(Collection c) {
Iterator i = c.iterator();
for (int k = 0; k < c.size(); k++) {
System.out.println(i.next());
}
}
Run Code Online (Sandbox Code Playgroud)
这是他们的解决方案:
static void printCollection(Collection<?> c) {
for (Object e : c) {
System.out.println(e);
}
}
Run Code Online (Sandbox Code Playgroud)
但是我可以在没有外卡的情况下做同样的事情:
static <T> void printCollection(Collection<T> c) {
Iterator i = c.iterator();
for (int k = 0; k < c.size(); k++) {
System.out.println(i.next());
}
}
Run Code Online (Sandbox Code Playgroud)
有人可以告诉我一个简单的用例,常规的泛型不起作用,但外卡会吗?
更新:此处的答案何时在Java Generics中使用通配符?不要告诉我们需要通配符.事实上,它是另一种方式.
Java通常可以根据参数推断泛型(甚至在返回类型上,与例如C#相反).
例证:我有一个Pair<T1, T2>只存储一对值的泛型类,可以按以下方式使用:
Pair<String, String> pair = Pair.of("Hello", "World");
Run Code Online (Sandbox Code Playgroud)
该方法of看起来像这样:
public static <T1, T2> Pair<T1, T2> of(T1 first, T2 second) {
return new Pair<T1, T2>(first, second);
}
Run Code Online (Sandbox Code Playgroud)
非常好.但是,这不再适用于以下需要使用通配符的用例:
Pair<Class<?>, String> pair = Pair.of((Class<?>) List.class, "hello");
Run Code Online (Sandbox Code Playgroud)
(注意显式强制转换以List.class生成正确的类型.)
代码失败,出现以下错误(由Eclipse提供):
类型不匹配:无法转换
TestClass.Pair<Class<capture#1-of ?>,String>为TestClass.Pair<Class<?>,String>
但是,显式调用构造函数仍然按预期工作:
Pair<Class<?>, String> pair =
new Pair<Class<?>, String>((Class<?>) List.class, "hello");
Run Code Online (Sandbox Code Playgroud)
有人可以解释这种行为吗?它是按设计的吗?它需要吗?我做错了什么,或者我偶然发现编译器中的设计/错误存在缺陷?
狂野猜测:"捕获#1-of?"似乎暗示通配符由动态编译器填充,使类型为a Class<List>,从而使转换失败(从)Pair<Class<?>, String>到Pair<Class<List>, String>.这是正确的吗?有办法解决这个问题吗?
为了完整起见,这里是Pair该类的简化版本:
public final class Pair<T1, T2> {
public …Run Code Online (Sandbox Code Playgroud) 我已经阅读过各种各样的地方,包括在方法返回类型中使用有界通配符是一个坏主意.但是,我无法找到一种方法来避免与我的班级.我错过了什么吗?
情况看起来像这样:
class EnglishReaderOfPublications {
private final Publication<? extends English> publication;
EnglishReaderOfPublications(Publication<? extends English> publication) {
this.publication = publication;
}
void readPublication() {
publication.omNomNom();
}
Publication<? extends English> getPublication() {
return publication;
}
}
Run Code Online (Sandbox Code Playgroud)
总之,我希望能够使用某些版本的英语版本的类.该类需要允许从外部访问该发布,但理想情况下,调用者getPublication不希望将结果作为有界通配符.他们会很高兴Publication<English>.
这有什么方法吗?
假设类B继承自类A.以下是合法的Java:
List<A> x;
List<? super B> y = x;
Run Code Online (Sandbox Code Playgroud)
就规范而言,这意味着List<A>assignsTo List<? super B>.但是,我无法找到说这是合法的规范部分.特别是,我认为我们应该有子类型关系
List<A> <: List<? super B>
Run Code Online (Sandbox Code Playgroud)
但是Java 8规范的4.10节将子类型关系S >1 T定义为直接超类型关系的传递闭包,并且它根据计算一组超类型的有限函数来定义直接超类型关系T.由于可能存在任意数量的s继承,因此输入List<A>可以产生无限制函数,因此spec的子类型定义似乎为超级通配符分解.关于"类和接口类型之间的子类型"的第4.10.2节确实提到了通配符,但它只处理通配符出现在潜在子类型中的另一个方向(此方向适合计算的直接超类型机制).List<? super B>BA
问题:规范的哪一部分说上面的代码是合法的?
动机是针对编译器代码的,因此仅仅理解它为何直观合法或者提出一种处理它的算法是不够的.由于Java中的一般子类型问题是不可判定的,我想处理与规范完全相同的情况,因此需要处理此案例的规范部分.
我知道已经发布了类似的问题,虽然我认为我的情况有所不同......
假设您有两种方法:
// Bounded type parameter
private static <T extends Number> void processList(List<T> someList) {
}
// Upper bound wildcard
private static void processList2(List<? extends Number> someList) {
// ...
}
Run Code Online (Sandbox Code Playgroud)
据我所知,这两种方法接受参数,是List类型Number或List的亚型的Number.
但毕竟这两种方法有什么区别?
简单的课程:
class Pair<K,V> {
}
Run Code Online (Sandbox Code Playgroud)
还有一些任务:
Collection<Pair<String,Long>> c1 = new ArrayList<Pair<String,Long>>();
Collection<Pair<String,Long>> c2 = c1; // ok
Collection<Pair<String,?>> c3 = c1; // this does not compile
Collection<? extends Pair<String,?>> c4 = c1; // ok
Run Code Online (Sandbox Code Playgroud)
为什么第三个子弹不能编译而第四个完全合法?
编译错误:
Type mismatch: cannot convert from Collection<Pair<String,Long>> to Collection<Pair<String,?>>
Run Code Online (Sandbox Code Playgroud)