2010-07-15 163 views
2
class Response<T> 
{ ... } 

Response response = new Response(); 

上面的代码编译。我不明白什么是暗示。编译器是否需要'T'的类型规范?例如如下所示:Java泛型 - 类型声明

Response<String> response = new Response<String>(); 
+0

另请参阅:http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it – polygenelubricants 2010-07-16 08:11:01

回答

6

从技术上讲,它应该/应该。但是,为了向后兼容Java 5,这不会完成,因此不需要通用参数。而且由于无论如何泛型都是通过擦除来实现的,所以无论您是否声明参数,发出的字节码都是相同的 - 您错过了一些编译时检查。

(请注意,如果你打电话给你response对象的方法,编译器会发出警告有关使用“原始类型”,这意味着你在一个非通用的方式使用泛型类,因此它不能)

编辑:关于向后兼容性,这是一种平衡行为,Sun已经明确牺牲了某些方面以改善/维护他人。打破向后兼容性将是一笔相当大的交易 - 这意味着迁移到最新版本的Java将是一个不平凡的项目,并会在企业内部对升级产生更大的阻力。

这里的一个重大决定是通过擦除来实现泛型,使得它们是“仅编译时”构造,生成的字节码与先前的版本相同。这具有如下优点:例如,在1.5中的java.util.HashMap仍然可以通过1.4编写的代码访问(当然,这个优点也延伸到你自己的类)。然而,有很多观点,特别是那些习惯于其他语言的泛型的人,他们想要使用类似的技术,这不是最好的决定,并且已经削弱了泛型的有用性。我不打算在这里斟酌。

至于它是否会破坏编译器想要执行的检查;我认为这不像你想象的那么糟糕。 是的,您可以编写代码,以便编译器不会执行任何泛型检查,并且可以故意颠覆预期的语义。然而,编译时检查并不意味着某种安全特性,它们仅仅是为了帮助你,作为一种静态分析的形式,它将挑选某些类别的错误。如果你颠覆他们,请随时这样做。但是如果你正确地编写泛型类,那么你会得到你想要的编译时检查。

特别是因为编译器(可以)给你关于原始类型的警告,所以有一个从1.4到5的清晰升级路径。升级你的JDK - 你的旧代码仍然会编译,尽管有警告。然后使用这些警告追查违规行为,并在需要时生成旧代码。在我看来,这比仅仅拒绝编译旧的(推测是功能性的)代码要好得多,直到每个语句都添加了适当的泛型。

大多数IDE将允许您对不同警告类型的严重程度进行分类,例如,如果您从头开始开发Java 5应用程序,则可以告诉它将所有原始类型警告视为完全停止构建错误。

+0

Java 5添加了泛型,向后兼容性为pre-version 5 – 2010-07-15 16:32:31

+0

感谢您回复Andrzej。我添加了编译器选项-Xlint:未选中,由Jon在下面提出。似乎这应该是默认设置。我是错误的还是为了向后兼容的努力似乎规避了程序员试图强加于仿制药的那种类型? – Bruce 2010-07-15 17:04:48

+0

可以说这应该是默认设置,但我认为你会遇到同样的问题 - 一个人一直在使用Java 1.4升级到Java 5,并且突然之间会发出数百条警告(在这种情况下无关紧要)。请参阅我的编辑以了解我对向后兼容性的看法,因为在那里写明确的段落会更容易! – 2010-07-16 07:56:02

1

我认为,通过在底部行中没有指定模板类,会导致编译器自动替换类型Object。这并没有错,它在执行类型时不是很有效。

+1

实际上它甚至不等同于用''代替,更类似于用''代替具体实例(如果你自己声明它,这将不合法)。由于泛型不是协变的,*任何*具体类型,甚至是“对象”都会限制某些方法调用。例如,一个通用的方法'addToCollection(Collection c)'只会在您声明的情况下接受'Collection '的参数,但实际上使用原始类型时,它们将允许任何Collection。 – 2010-07-15 16:15:33

0

这将编译得很好。如果没有,你会遇到遗留代码的问题。例如,由于HashMap现在被声明为HashMap<K, V>,您将如何处理声明(未参数化)散列表的所有代码?

当您尝试使用该参数值你只会得到错误:

class Response<T> 
{ public T get()... } 

String s= new Reponse().get(); //breaks - or requires a cast 
String s= new Response<String>().get(); 
2

这就是所谓的原始类型。你应该能够打开警告,让它对你投诉 - 听取这些警告。

例如,这里是我所得到的,当我运行

javac -Xlint Test.java 

与您的代码(包装原始类型引用转换成Test类):

C:\Users\Jon\Test>javac -Xlint Test.java 
Test.java:7: warning: [rawtypes] found raw type: Response 
    Response response = new Response(); 
    ^
    missing type parameters for generic class Response<T> 
    where T is a type-variable: 
    T extends Object declared in class Response 
Test.java:7: warning: [rawtypes] found raw type: Response 
    Response response = new Response(); 
          ^
    missing type parameters for generic class Response<T> 
    where T is a type-variable: 
    T extends Object declared in class Response 
2 warnings 

如果你没有这些警告,我建议你尽一切努力在你的环境中看到它们。这将取决于您使用的IDE /编译器,但如果您找不到相关设置,请告诉我们您正在使用哪一个,我确信有人能够为您找到它。

请参阅Angelika Langer的Java Generics FAQ的raw types section了解更多信息。

+0

感谢Jon,我更新了NetBeans以使用-Xlint:未选中。您提供的链接非常有帮助。 – Bruce 2010-07-15 17:05:34