【发布时间】:2021-06-30 13:41:59
【问题描述】:
我昨天在回答Applying functions of various types to a value 的问题时发现了一些很奇怪的东西。
我可以将集合定义为O 类型,即使它的实际类型是T。
这可能是因为我使用的是原始类型。
然而,最令人惊讶的部分是我能够从这个List<FileInputStream> 集合中消费,尽管很明显它是List<Integer>。
下面是有问题的代码
public static void main(String[] args) {
String value = "a string with numb3r5";
Function<String, List<String>> fn1 = List::of;
Function<List<String>, String> fn2 = x -> x.get(0);
Function<String, List<Integer>> fn3 = x -> List.of(x.length());
InputConverter<String> converter = new InputConverter<>(value);
List<FileInputStream> ints = converter.convertBy(fn1, fn2, fn3);
System.out.println("ints = " + ints);
System.out.println("ints.get(0) = " + ints.get(0));
System.out.println("ints.get(0).getClass() = " + ints.get(0).getClass());
}
public static class InputConverter<T> {
private final T src;
public InputConverter(T src) {
this.src = src;
}
@SuppressWarnings({"unchecked", "rawtypes"})
public <R> R convertBy(Function... functions) {
Function functionsChain = Function.identity();
for (Function function : functions) {
functionsChain = functionsChain.andThen(function);
}
return (R) functionsChain.apply(src);
}
}
这是结果
ints = [21]
ints.get(0) = 21
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.io.FileInputStream (java.lang.Integer and java.io.FileInputStream are in module java.base of loader 'bootstrap')
at Scratch.main(scratch_8.java:18)
为什么可以从这个集合中消费?
我注意到以下内容在使用时不会引发异常
System.out.println("String.valueOf(ints.get(0)) = " + String.valueOf(ints.get(0)));
System.out.println("((Object) ints.get(0)).toString() = " + ((Object) ints.get(0)).toString());
但是下面的情况
System.out.println("ints.get(0).toString() = " + ints.get(0).toString());
【问题讨论】:
-
你的问题到底是什么?
-
@Turing85 我刚刚编辑它以在末尾添加一个问题。
-
"为什么可以从这个集合中消费*" 因为
+是为(String, Object)对定义的(即列表元素的确切类型确实没关系)。但是,如果我们在假定为FileInputStream的情况下调用列表元素上的某个方法,则它的类型必须由类型转换来保证。 -
好的,但是当我尝试
ints.get(0).toString()时,我得到一个ClassCastException,即使它是来自Object的方法 -
... 因为您访问列表元素 作为实际
FileInputStream(这是列表的泛型类型断言您,请记住:调用的方法由参数的 static 类型确定)并且断言必须由类型转换强制执行。这就是为什么如果我们将System.out.println("ints.get(0).getClass() = " + ints.get(0).getClass());替换为Object o = ints.get(0); System.out.println("ints.get(0).getClass() = " + o.getClass());(Ideone demo),原始程序可以工作的原因。
标签: java generics type-inference