简体   繁体   English

Java Generics - 类型声明

[英]Java Generics - type declaration

class Response<T>
{ ... }

Response response = new Response();

The above code compiles. 上面的代码编译。 I don't understand what's implied though. 我不明白隐含的是什么。 Shouldn't the compiler require a type specification for 'T'? 编译器不应该要求'T'的类型规范吗? eg something like the following: 例如以下内容:

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

Technically, it should/ought to. 从技术上讲,它应该/应该。 However, for backwards compatibility with Java 5, this is not done and so a generic parameter is not required. 但是,为了向后兼容Java 5,这没有完成,因此不需要通用参数。 And since generics are implemented by erasure anyway, the bytecode emitted is identical regardless of whether you declare the parameters or not - all you're missing out on is some compile-time checks. 而且由于泛型是通过擦除实现的,所以无论你是否声明参数,所发出的字节码都是相同的 - 你所缺少的只是一些编译时检查。

(Note that if you call methods on your response object, the compiler will warn you about using "raw types", meaning that you're using a generic class in a non-generic way so it can't enforce any of the constraints for you.) (请注意,如果在response对象上调用方法,编译器将警告您使用“原始类型”,这意味着您以非泛型方式使用泛型类,因此它不能强制执行任何约束。您。)

Edit: Regarding backwards compatibility, it's a balancing act, and Sun have clearly sacrificed some aspects in order to improve/maintain others. 编辑:关于向后兼容性,这是一种平衡行为,并且Sun明显牺牲了一些方面来改进/维护其他方面。 Breaking backwards compatibility would be quite a big deal - it would mean that migrating to the latest version of Java would be a non-trivial project, and would create even more resistance within businesses to upgrading. 打破向后兼容性将是一件非常重要的事情 - 这意味着迁移到最新版本的Java将是一个非常重要的项目,并且会在企业内部产生更大的阻力来升级。

The big decision here was to implement generics via erasure, such that they're a "compile-time only" construct and the generated bytecode is identical to the previous version. 这里的重大决定是通过擦除来实现泛型,这样它们就是“仅编译时”构造,并且生成的字节码与先前版本相同。 This has the advantage that eg java.util.HashMap in 1.5 can still be accessed by code written in 1.4 (and of course this advantage extends to your own classes too). 这样做的好处是,例如1.5 java.util.HashMap仍然可以用1.4编写的代码访问(当然这个优点也可以扩展到你自己的类)。 However, there are lots of view, especially from those used to generics in other languages who want to use similar techniques, that this was not the best decision and has crippled the usefulness of generics. 但是,有很多观点,特别是那些习惯使用类似技术的其他语言中的仿制药,这不是最好的决定,并且削弱了仿制药的实用性。 I'm not going to weigh in on that here. 我不会在这里谈论它。

As for whether it subverts the checks the compiler wants to enforce; 至于它是否颠覆了编译器想要强制执行的检查; I don't think it's quite as bad as you think. 我认为这并不像你想象的那么糟糕。 Yes , you can write code such that the compiler doesn't do any generics checks, and such that you can deliberately subvert the intended semantics. 是的 ,您可以编写代码,使编译器不进行任何泛型检查,并且您可以故意破坏预期的语义。 However, the compile-time checks aren't meant to be some sort of security feature, they're simply there to help you, as a form of static analysis that will pick up certain classes of error. 但是,编译时检查并不是某种安全功能,它们只是帮助您,作为一种静态分析形式,可以获取某些类型的错误。 If you want to subvert them, feel free to do so. 如果你颠覆它们,请随意这样做。 But if you write your generic classes properly, then you'll get the compile-time checks that you desire. 但是如果你正确编写了通用类,那么你将得到你想要的编译时检查。

Especially since the compiler (can) give you warnings about raw types, there's a clear upgrade path from 1.4 to 5. Upgrade your JDK - your old code still compiles albeit with warnings. 特别是因为编译器(可以)给你关于原始类型的警告,所以有一个明确的升级路径从1.4到5.升级你的JDK - 你的旧代码仍然编译,尽管有警告。 Then use these warnings to chase down violations, and generify your old code as and when needed. 然后使用这些警告来追踪违规行为,并在需要时生成旧代码。 In my opinion, that's much better than simply refusing to compile the old (presumably functional!) code until every statement has had appropriate generics added. 在我看来,这比简单地拒绝编译旧的(可能是功能性的!)代码要好得多,直到每个语句都添加了适当的泛型。

Most IDEs will let you classify the severity of different warning types, such that if you're developing a Java 5 application from scratch, you can tell it to treat all raw type warnings as full-on stop-the-build errors. 大多数IDE都允许您对不同警告类型的严重性进行分类,这样,如果您从头开始开发Java 5应用程序,则可以告诉它将所有原始类型警告视为完全停止构建错误。

This is called a raw type . 这称为原始类型 You should be able to turn on warnings to make it complain at you - listen to those warnings. 你应该能够打开警告让它向你抱怨 - 听听那些警告。

For example, here's what I get when I run 例如,这是我跑步时得到的

javac -Xlint Test.java

with your code (wrapping the raw type reference into a Test class): 使用您的代码(将原始类型引用包装到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

If you don't have those warnings at the moment, I suggest you do whatever it takes to see them in your environment. 如果您此刻没有这些警告,我建议您尽一切努力在您的环境中查看它们。 That will depend on the IDE / compiler you're using, but if you can't find the relevant setting, let us know which one you're using and I'm sure someone will be able to find it for you. 这取决于您正在使用的IDE /编译器,但如果您找不到相关设置,请告诉我们您使用的是哪一个,我相信有人能够为您找到它。

See the raw types section of Angelika Langer's Java Generics FAQ for more information. 有关更多信息,请参阅Angelika Langer的Java Generics FAQ的原始类型部分

I think that by not specifying a template class in the bottom line, you are causing the compiler to automatically substitute type Object . 我认为通过不在底线中指定模板类,您将使编译器自动替换Object类型。 That's not wrong, it's just not very effective at enforcing a type. 这没有错,它在执行类型方面不是很有效。

This will compile fine. 这将编译好。 If it didn't you'd have issues with legacy code. 如果不是,那么遗留代码就会出现问题。 For example, since HashMap is now declared as HashMap<K, V> , what would you do with all of that code that declares an (unparameterized) hashmap? 例如,由于HashMap现在被声明为HashMap<K, V> ,您将如何处理声明(未参数化)hashmap的所有代码?

You'll only get the error when you try to use the parameterized value: 您只会在尝试使用参数化值时收到错误:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM