ral*_*los 8 java generics java-stream
我正在尝试构建一个List实现特定接口的类Interface:
List<Class<? extends Interface>> myList= myMap.entrySet().stream()
.filter(entry -> entry.getValue().equals(myValue))
.map(Map.Entry::getKey) // Stream<Interface>
.map(Interface::getClass) // Stream<Class<capture of ? extends Interface>>
.distinct()
.toList();
Run Code Online (Sandbox Code Playgroud)
map()我添加了调用后 Stream 中元素的类型作为注释。
该代码迭代映射中的所有条目,如果它们的值等于myValue,则:
Interface(这是条目的键)Class实施Interface。myMap定义为:
Map<Interface, Integer> myMap = new HashMap<>()
Run Code Online (Sandbox Code Playgroud)
我收到的错误:
Incompatible types.
Found: 'java.util.List<java.lang.Class<capture<? extends application.interfaces.Interface>>>',
required: 'java.util.List<java.lang.Class<? extends application.interfaces.Interface>>'
Run Code Online (Sandbox Code Playgroud)
我显然错过了关于泛型在 Java 中如何工作的一些内容,但我在这里不知所措。我想这与编译器无法正确具体化我的通配符这一事实有关?。
Ale*_*nko 11
正如@Slaw在评论中指出的那样,在这种情况下getClass()能够向编译器提供有关泛型类型的信息。
根据文档:
实际结果类型是调用 getClass 的表达式的静态类型的擦除位置
Class<? extends |X|>。|X|
因此,在编译时,我们会有一个类型,并且观察到的行为的原因仅与 Java 中类型推断? extends Interface的特性相关。
在这种情况下,当我们在操作后链接方法时map(),编译器无法Interface::getClass根据流返回的结果类型正确推断方法引用的类型。
如果我们替换toList,它需要类型的元素T并生成List<T>,与collect(Collectors.toList()),其中收集器的类型为Collector<? super T, A, R>,编译器将能够完成其工作(这是一个证明):
List<Class<? extends Interface>> myList = myMap.entrySet().stream()
.filter(entry -> Objects.equals(entry.getValue(), myValue))
.map(Map.Entry::getKey) // Stream<Interface>
.map(Interface::getClass) // Stream<Class<? extends Interface>>
.distinct()
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
但是为了使类型推断起作用,我们需要显式地toList()提供泛型类型。
例如,这段代码可以编译,因为 的类型Interface::getClass可以从赋值上下文中推断出来(这里 后没有任何操作map(),因此myStream直接说明 的返回类型应该是什么map()):
Stream<Class<? extends Interface>> myStream = myMap.entrySet().stream()
.filter(entry -> Objects.equals(entry.getValue(), myValue))
.map(Map.Entry::getKey)
.map(Interface::getClass);
List<Class<? extends Interface>> myList = myStream.distinct().toList();
Run Code Online (Sandbox Code Playgroud)
更方便的方法是使用所谓的类型见证:
Map<Interface, Integer> myMap = Map.of(new ClasA(), 1, new ClasB(), 1);
int myValue = 1;
List<Class<? extends Interface>> myList = myMap.entrySet().stream()
.filter(entry -> Objects.equals(entry.getValue(), myValue))
.map(Map.Entry::getKey) // Stream<Interface>
.<Class<? extends Interface>>map(Interface::getClass) // Stream<Class<? extends Interface>>
.distinct()
.toList();
myList.forEach(c -> System.out.println(c.getSimpleName()));
Run Code Online (Sandbox Code Playgroud)
输出:
ClasA
ClasB
Run Code Online (Sandbox Code Playgroud)
虚拟类:
interface Interface {}
class ClasA implements Interface {}
class ClasB implements Interface {}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
793 次 |
| 最近记录: |