java - 在java中的方法中使用 钻石 符号。
我目前正在用java开发一个基于组件的架构管理系统。我目前实现的对连接到对象的组件的检索是这样的。
// ...
private final HashMap<Class<? extends EntityComponent>, EntityComponent> components;
// ...
public <T extends EntityComponent> T getComponent(Class<T> component)
{
// ... some sanity checks
if (!this.hasComponent(component))
{
// ... some exception handling stuff
}
return component.cast(this.components.get(component));
}
// ...
现在,这很好用,但它有点让我不爽,因为我必须要写
object.getComponent(SomeComponent.class)
每当我需要访问一个组件时,都会出现这样的情况。能否用一种方式来利用通用性,将语法改为类似于
object.getComponent<SomeComponent>()
利用钻石运算符来指定类,而不是将组件的类作为参数传递给方法?我知道这并不是什么大事,但是把经常使用的代码的语法尽可能的简化,我想这是很有帮助的。
【回答】:
不幸的是不能,因为类型参数在Java中是 "抹去 "的。这意味着它们只在编译时可用(编译器使用它们来检查代码的类型),而不是在运行时。
所以当你的代码运行时, <SomeComponent>
类型参数不再存在,因此你的代码不能基于它的值进行任何操作(ifelse等)。
换句话说。
- 在编译时,你的方法调用是这样的。
object.getComponent<SomeComponent>()
- 但是在编译之后,你的方法调用看起来是这样的
object.getComponent()
. 现在已经没有类型参数了。
所以,是的,不幸的是你仍然需要传递一个 Class
对象,或者类似的东西(例如参见 "超级类型令牌"),如果你需要在运行时做一些依赖于类型参数的事情。
的原因是 Class
的工作原理是它松散地代表了类型参数,因为类型检查器确保它的实例符合类型参数,但它是一个对象,因此在运行时也可以使用--不像类型参数。
注意: 类型检查器的 Class
-技巧对类型参数中的类型参数不起作用,如 Class<List<Something>>
,因为在运行时 List<Something>
和 List<OtherThing>
是同一类,即 List
. 所以你不能做一个 Class
令牌来区分这两种类型。在我的印象中,"超级类型令牌 "可以用来解决这个问题(它们利用了存在擦除异常的事实。对于通用类的子类,当 "扩展 "超级类时使用的类型参数实际上在运行时可以通过反射获得。(还有更多的例外。https:/stackoverflow.coma23207251743225)).
(相关google词:"擦除"、"Reification"、"Reified generics")