9阅网

您现在的位置是:首页 > 知识 > 正文

知识

java - 在java中的方法中使用 钻石 符号。

admin2022-10-02知识30

我目前正在用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")