我试图理解Java泛型,它们似乎很难理解。例如,这很好…
public class Main {
public static void main(String[] args) {
List<?> list = null;
method(list);
}
public static <T> void method(List<T> list) { }
}
…就是这个…
public class Main {
public static void main(String[] args) {
List<List<?>> list = null;
method(list);
}
public static <T> void method(List<T> list) { }
}
… 还有这个 …
public class Main {
public static void main(String[] args) {
List<List<List<?>>> list = null;
method(list);
}
public static <T> void method(List<List<T>> list) { }
}
…但是不能编译:
public class Main {
public static void main(String[] args) {
List<List<?>> list = null;
method(list);
}
public static <T> void method(List<List<T>> list) { }
}
有人可以用简单的语言解释发生了什么吗?
对于泛型类型,主要要了解的是它们不是协变的。
因此,尽管您可以这样做:
final String string = "string";
final Object object = string;
以下内容将无法编译:
final List<String> strings = ...
final List<Object> objects = strings;
这是为了避免您绕过通用类型的情况:
final List<String> strings = ...
final List<Object> objects = strings;
objects.add(1);
final String string = strings.get(0); <-- oops
因此,一一讲解您的示例
您的通用方法采用a
List<T>
,而您采用List<?>
;(基本上是)List<Object>
。T
可以分配给Object
类型,并且编译器满意。
您的通用方法相同,您传入List<List<?>>
。T
可以分配给List<?>
类型,编译器再次感到高兴。
这与 2 基本上相同,但具有另一层嵌套。T
仍然是List<?>
类型。
这是有点梨形的地方,也是我从上面提出的观点。
您的通用方法采用List<List<T>>
。您通过了List<List<?>>
。现在,由于通用类型不是协变的,List<?>
因此无法将其分配给List<T>
。
实际的编译器错误(Java 8)是:
必填:
java.util.List<java.util.List<T>>
找到:
java.util.List<java.util.List<?>>
原因:无法推断类型变量T
(参数不匹配;java.util.List<java.util.List<?>>
无法转换为java.util.List<java.util.List<T>>
)
基本上,编译器告诉您,T
由于必须推断List<T>
外部列表中嵌套的类型,因此找不到分配的对象。
让我们更详细地看一下:
List<?>
是List
的 一些未知类型 -它可以是一个List<Integer>
或一个List<String>
;
我们可以get
这样做Object
, 但是我们不能add
。因为否则我们会遇到我提到的协方差问题。
List<List<?>>
是List
的List
一些未知类型的-
它可能是一个List<List<Integer>>
或一个List<List<String>>
。在情况 1中
,可以分配T
给通配符列表,Object
但不允许add
对通配符列表进行操作。在第 4种 情况下,此操作无法完成-
主要是因为没有通用的构造可以防止add
外部攻击List
。
如果在第二种情况下将编译器分配T
给Object
,则可能会出现如下所示的情况:
final List<List<Integer>> list = ...
final List<List<?>> wildcard = list;
wildcard.add(Arrays.asList("oops"));
因此,由于协方差,不可能安全地将a分配List<List<Integer>>
给 任何其他 泛型List
。
问题内容: 我正在刷新有关Java泛型的知识。因此,我转向了Oracle的优秀教程……并开始为我的同事编写一个演示文稿。我在本教程中遇到了有关通配符的部分,内容为: 考虑以下方法,printList: printList的目标是打印任何类型的列表,但未能实现该目标- 它仅打印Object实例的列表;它不能打印,,,等等,因为它们不是的亚型。要编写通用的printList方法,请使用: 我知道那是行
我正在刷新我关于Java泛型的知识。所以我转向甲骨文的优秀教程...并开始为我的同事准备一个演示文稿。我在教程中遇到了通配符部分,上面写着: 考虑以下方法,打印列表: printList的目标是打印任何类型的列表,但它无法实现该目标-它只打印对象实例的列表;无法打印列表 我明白那个
在了解Java泛型的过程中,我遇到了以下问题: 假设我有下面的方法来添加列表的元素,只限于包含数字的列表。 但是这段代码和这段代码有什么不同: 它们都按预期编译和执行。这两者之间有什么区别?除了语法之外?什么时候我更喜欢使用通配符而不是前者? 是的,使用通配符方法,我不能在列表中添加除null之外的新元素,否则它将无法编译。除此之外呢?
所以我看了官方的java教程,https://docs.oracle.com/javase/tutorial/java/generics/index.html,也搜索了stackoverflow,结果发现使用
可以使用泛型将返回类型与参数类型匹配吗? 实例案例: 我有一个抽象类,可以从不同的POJO导入数据,这个类包含一个abstract方法importData。 importData返回的对象必须与传递给该方法的对象类型相同。 由于抽象方法的每个实现的对象类型不同,并且类型不扩展另一个,如何定义抽象方法,以便实现返回类型和传递类型必须匹配? 经过考验: 结果: 方法的返回类型不必与传递的对象类型匹配。
问题内容: 我有一个方法以a 作为参数。 在中,我如何知道a 是还是a 是? 问题答案: 根据用户omain的回答“如果使用<?>,则意味着您将不会在任何地方使用参数化类型。要么转到特定类型(在您的情况下,似乎是),要么转到非常通用的“ 另外,我相信如果您使用问号,编译器将在运行时(类型;有效Java的第119页)消除类型不匹配的情况,绕过擦除,并有效地消除了使用泛型类型所带来的好处? 要回答发问