我使用泛型编写了一些代码,我遇到了以下我无法理解的情况:
我有IpRange接口,以及以下类:
public class Scope<IpRange<T extends IP>> {
List<IpRange<T>> rangesList;
public List<IpRange<T>> getRangesList() {return rangesList;}
}
现在从一些测试类中,如果我写下以下内容:
Scope<Ipv4> myScope = new Scope<Ipv4>();
scope.getRangesList().get(0)
我正在获取IpRange类型的对象,但是如果我使用的是原始类型并执行此操作:
Scope myScope = new Scope();
scope.getRangesList().get(0)
我正在使用Object,除非我明确地将它转换为Range,否则我无法使用ipRange方法。
如果它是List<T>
我得到它,因为我使用原始类型,编译器无法知道列表项的实际类型是什么,但在这种情况下它将始终是IpRange类型,那我为什么不拿对象?
问题在于,当我创建示波器时,我不一定知道实际的范围类型。考虑这个构造函数:public Scope(String rangeStringList);据我所知,字符串可以是“16.59.60.80”或“fe80 :: 10d9:159:f:fffa%”。但我所知道的是,我将一些IpRange对象传递给编译器,我希望能够使用此接口,无论是ipv4还是ipv6。并且由于即使我使用了行类型,编译器也可以确定这是ipRange,我想知道为什么java选择这样做
答案 0 :(得分:2)
人们已经指出在使用原始类型时会剥离所有泛型类型信息,并暗示这与向后兼容性有关。我想如果没有解释,这可能不会令人满意,所以我将尝试解释像你这样的代码会遇到这样的问题。
首先,想象一下您编写的代码是旧库的一部分,并且您正在通过添加泛型来升级库。也许它是一个受欢迎的图书馆,很多人都使用旧代码。
有人可能会使用你库中的类来做这样的事情:
private void someMethod(Scope scope, Object object) {
scope.getRangesList().add(object);
}
现在,看看这个我们知道Object可能不是IpRange类型,但这是一个私有方法,所以让我们假设类型检查是通过调用someMethod的任何方法有效地执行的。这可能不是很好的代码,但没有泛型它会编译,它可能会正常工作。
想象一下,写这个的人升级到你的库的新版本以获得一些新功能或未实现的错误修复,以及他们现在可以使用你的泛型类访问更多的类型安全。但是,他们可能不想使用它,像使用原始类型的代码上面提取的太多遗产。
你实际建议的是,即使'scope'是一个原始类型,从getRangesList()返回的List必须始终是List&lt; IpRange&lt;?扩展IP&gt;&gt;,因此编译器应注意这一点。
如果是这种情况,那么上面添加一个Object的遗留代码将不再编译而不进行编译。这是向后兼容性的一种方式,而不会忽略原始类型的所有可用泛型类型信息。
答案 1 :(得分:1)
是的,如果您使用原始类型,则所有泛型都会在该方法的其余部分中“关闭”,而所有泛型类型都会变为原始类型,即使它们不会受到原始缺失的泛型参数的影响类型。
答案 2 :(得分:0)
如果使用原始类型,则从类中剥离所有泛型类型信息,包括在实例上调用的静态方法。
这样做的原因是为了向后兼容java 1.4。