class Response<T>
{ ... }
Response response = new Response();
以上代码编译。我不明白隐含的是什么。编译器不应该要求'T'的类型规范吗?例如如下所示:
Response<String> response = new Response<String>();
答案 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();