我在Java中接触泛型已经有一段时间了,我有了这个:
Map<List<MyGenericType>, Set<List<MyGenericType>>> x = new HashMap<>();
事实上,MyGenericType
需要一个通用参数,因为它是这样定义的:
public class MyGenericType<X> {}
我用MyGenericType
的抢占式擦除声明了x
,因为我不想仅仅为了分组而制作一个空的标记接口。为了拥有一个集合,这会对我有利吗?还是我必须制作一个标记接口才能实现这一点?
(编辑(即:
public interface SomeCommonInterface {...}
MyGenericType implements SomeCommonInterface ...
Map<List<SomeCommonInterface>, Set<List<SomeCommonInterface>>> x = new HashMap<>();
回想一下,Integer
和Double
都扩展了Number
,而Number
又扩展了Object
。
List<Number>
决不能用作List<Integer>
,反之亦然。List<Number> x = new ArrayList<Integer>
不编译。这被称为"不变性",它是"正确的",因为如果它真的编译了,你可以在整数列表中添加双精度,这显然是不对的。不过,它往往会让人反感,这就是我提到它的原因。如果你想要协方差或方差,你必须选择这个:List<? extends Number> list = new ArrayList<Integer>();
编译。但list.add(5);
不会,因为如果它这样做了,你就可以再次向整数列表中添加双精度,这是不对的。
一旦你完全省略了一件事的泛型,所有对泛型的类型检查都是不可能的,你不希望这样。你能"逍遥法外"吗?嗯,嗯,编译器会在你面前抛出一堆警告,你会关闭很多类型检查。如果你的意思是"逍遥法外":;它会编译"吗;?是的,确实如此。如果你的意思是:;这段代码会通过任何合理的java程序员的代码审查吗不,不会。
简单的解决方案:在这里使用MyGenericType<?>
有什么问题?
注意:映射中的键应该是不可变的;列表不是。因此,使用它是一个相当糟糕的计划;那应该代表什么?
这不是一个真正的答案,但正如这里的评论中所说,我认为添加通配符不会解决任何问题。
根据Map
的使用地点,您可能会有某种安全性。我有几次站在你的立场上,我知道的唯一解决方案是:
@Getter
static class Box<T> {
private Map<List<MyGenericType<T>>, Set<List<MyGenericType<T>>>> x = new HashMap<>();
}
即:通过"曝光"来曝光CCD_ 19;"包装物";,定义了类型变量。如果调用方在实例化Box
时提供了一个类型,那么您将获得所需的类型安全性:
new Box<Integer>().getX().put(...); // you can only put a MyGenericType<Integer> in here now
否则,当使用原始类型甚至?
时,可以在键和值中放入不同的类型。