Java Generics - 类型声明

时间:2010-07-15 16:09:27

标签: java generics

class Response<T>
{ ... }

Response response = new Response();

以上代码编译。我不明白隐含的是什么。编译器不应该要求'T'的类型规范吗?例如如下所示:

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

4 个答案:

答案 0 :(得分:6)

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

(请注意,如果您在response对象上调用方法,编译器将警告您使用“原始类型”,这意味着您在非对象中使用泛型类 - 通用方式,因此它不能为您强制执行任何约束。)

编辑:关于向后兼容性,这是一种平衡行为,并且Sun明显牺牲了一些方面来改进/维护其他方面。打破向后兼容性将是一个相当大的问题 - 这意味着迁移到最新版本的Java将是一个非平凡的项目,并且会在企业内部产生更大的阻力来升级。

这里的重大决定是通过擦除来实现泛型,这样它们就是“仅编译时”构造,并且生成的字节码与先前版本相同。这具有以下优点:仍然可以通过1.4编写的代码访问1.5中的java.util.HashMap(当然,这种优势也可以扩展到您自己的类)。但是,有很多批次的视图,尤其是那些习惯使用类似技术的其他语言中的泛型,这不是最好的决定,并且削弱了泛型的有用性。我不会在这里谈论它。

至于它是否颠覆了编译器想要强制执行的检查;我认为这并不像你想象的那么糟糕。 ,您可以编写代码,使编译器不进行任何泛型检查,并且您可以故意破坏预期的语义。但是,编译时检查并不是某种安全功能,它们只是帮助您,作为一种静态分析形式,可以获取某些类型的错误。如果你希望颠覆它们,请随意这样做。但是如果你正确编写了通用类,那么你将得到你想要的编译时检查。

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

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

答案 1 :(得分: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常见问题解答的raw types section

答案 2 :(得分:1)

我认为通过不在底线指定模板类,您将使编译器自动替换类型Object。这没有错,它在执行类型方面效果不是很好。

答案 3 :(得分: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();