泛型和原始类型 [英] Generics and raw types

查看:93
本文介绍了泛型和原始类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我有IpRange接口和以下类:

  public class Scope< IpRange< T extends IP>> {
列出< IpRange< T>> rangesList;
public List< IpRange< T>> getRangesList(){return rangesList;}
}

现在从一些测试类如果我写以下内容:

 范围< Ipv4> myScope = new Scope< Ipv4>(); 
scope.getRangesList()。get(0)

我得到IpRange的对象类型,但是如果我使用原始类型并执行此操作:

 范围myScope = new Scope(); 
scope.getRangesList()。get(0)

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



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

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

解决方案

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

首先,想象一下您在那里编写的代码是旧库的一部分,您正在通过添加泛型来升级库。也许这是一个很受欢迎的图书馆,很多人都使用旧的代码。



有人可能使用库中的类来做这样的事情:

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





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



想象一下,写这个的人升级到了你的库的新版本对于一些新功能或未实现的错误修复,随着这些,他们现在可以使用泛型类访问更多的类型安全。他们可能不想使用它,但是,像上面的代码使用原始类型提取的代码太多了。



你有效地提出的是,即使'范围'是原始类型,从getRangesList()返回的List必须始终是List< IpRange< ;?类型的?因此编译器应该注意到这一点。



如果是这种情况,上面的遗留代码会将一个Object添加到列表中,不再编译没有被编辑。这是一种方式向后兼容性将被打破,而不会忽略原始类型的所有可用的泛型类型信息。


I wrote some code using generics and I got into the following situation I didn't manage to understand:

I have the interface IpRange, and the following class:

public class Scope<IpRange<T extends IP>> {
     List<IpRange<T>> rangesList;
     public List<IpRange<T>> getRangesList() {return rangesList;}
}

Now from some test class if i write the following:

Scope<Ipv4> myScope = new Scope<Ipv4>(); 
scope.getRangesList().get(0)

I'm getting object of IpRange type, but if I'm using a raw type and doing this:

Scope myScope = new Scope();
scope.getRangesList().get(0)

I'm getting Object, and I can't use the ipRange methods unless i explicitly cast it to Range.

If it would have been List<T> i get it, since i used raw type the compiler has no way to know what is the actual type of the list items, but in this case it will be always IpRange type, so why I'm not getting Object?

The thing is that when I'm creating the scope I don't necessarily know the actual range type. Consider this constructor: public Scope(String rangeStringList); for all I know, the string could be "16.59.60.80" or "fe80::10d9:159:f:fffa%". But what I do know is that I passed some IpRange object to the compiler and I would expect to be able to use this interface whether this is ipv4 or ipv6. And since the compiler can know for sure that this is ipRange even if I used row type, i wonder why java chose to do it this way

解决方案

People have pointed out that all generic type information is stripped when using raw types, and hinted that this is to do with backwards compatibility. I imagine this might not be satisfactory without an explanation, so I'll try to explain how such a problem might be encountered with code like yours.

First of all, imagine the code you have written there is part of an old library, and you're in the process of upgrading the library by adding generics. Perhaps it's a popular library and lots of people have used the old code.

Someone may have done something like this using the classes from your library:

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

Now, looking at this we know that Object might not be of the type IpRange, but this is a private method, so let's assume that type checking is effectively performed by whatever methods call someMethod. This might not be good code, but without generics it does compile and it might work just fine.

Imagine that the person who wrote this upgraded to the new version of your library for some new features or unrealted bug fixes, along with this they now have access to more type safety with your generic classes. They might not want to use it, though, too much legacy like the extract above code using raw types.

What you are effectively suggesting is that even though 'scope' is a raw type, the List returned from getRangesList() must always be of type List<IpRange<? extends IP>>, so the compiler should notice this.

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.

这篇关于泛型和原始类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆