3

我使用泛型编写了一些代码,但遇到了以下我无法理解的情况:

我有接口 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)

我得到了对象,除非我明确地将它转换为范围,否则我不能使用 ipRange 方法。

如果是List<T>我明白了,因为我使用原始类型,编译器无法知道列表项的实际类型是什么,但在这种情况下,它将始终是 IpRange 类型,所以为什么我没有得到 Object ?

问题是,当我创建范围时,我不一定知道实际的范围类型。考虑这个构造函数: public Sc​​ope(String rangeStringList); 据我所知,字符串可能是“16.59.60.80”或“fe80::10d9:159:f:fffa%”。但我所知道的是,我将一些 IpRange 对象传递给编译器,我希望能够使用这个接口,无论是 ipv4 还是 ipv6。而且由于即使我使用行类型,编译器也可以确定这是 ipRange,我想知道为什么 java 选择这样做

4

3 回答 3

2

人们指出,在使用原始类型时,所有泛型类型信息都会被剥离,并暗示这与向后兼容性有关。我想如果没有解释,这可能不会令人满意,所以我将尝试解释像您这样的代码如何遇到这样的问题。

首先,假设您在那里编写的代码是旧库的一部分,并且您正在通过添加泛型来升级库。也许它是一个流行的库,很多人都使用过旧代码。

有人可能使用您库中的类做了类似的事情:

private void someMethod(Scope scope, Object object) {
  scope.getRangesList().add(object);
}

现在,看这个我们知道 Object 可能不是 IpRange 类型,但这是一个私有方法,所以让我们假设类型检查是由调用 someMethod 的任何方法有效执行的。这可能不是好的代码,但如果没有泛型,它确实可以编译并且它可能工作得很好。

想象一下,写这篇文章的人升级到你的库的新版本以获得一些新功能或未实现的错误修复,与此同时,他们现在可以使用你的泛型类获得更多的类型安全性。但是,他们可能不想使用它,例如使用原始类型提取上述代码的太多遗留问题。

您实际上建议的是,即使“范围”是原始类型,从 getRangesList() 返回的列表也必须始终是 List<IpRange<? 扩展 IP>>,所以编译器应该注意到这一点。

If this were the case though, the legacy code above which adds an Object to the list will no longer compile without being edited. This is one way backwards compatibility would be broken without disregarding all available generic type information for raw types.

于 2012-11-22T11:24:28.213 回答
1

是的,如果您使用原始类型,则在该方法的其余部分中所有泛型都将“关闭”,并且所有泛型类型都将变为原始类型,即使它们不会受到原始类型缺少的泛型参数的影响。

于 2012-11-22T01:02:40.257 回答
0

如果使用原始类型,则所有泛型类型信息都会从类中剥离,包括在实例上调用的静态方法。

这样做的原因是为了向后兼容 java 1.4。

于 2012-11-22T01:38:32.663 回答