当前位置: 首页 > 知识库问答 >
问题:

Java运行时强制转换为泛型接口而不丢失类型信息

公羊伟志
2023-03-14

我有一个泛型接口,可以由抽象基类的不同子类实现。

interface PropertyOne<T> {
  T type();
  List<String> values();
}

在基类中,我定义了一个小的帮助器方法,检查当前实例是否实现了该接口,并在可能的情况下强制转换为该接口:

<T> Optional<T> toProperty(Class<T> clazz){
    if (clazz.isAssignableFrom(this.getClass())){
      return Optional.of(clazz.cast(this));
    }
    return Optional.empty();
}

例如,我使用这个helper方法来获取和打印这些值:

void printValues() {
    List<String> values = toProperty(PropertyOne.class)
      .map(p -> p.values())
      .orElse(Collections.emptyList());
    System.out.println(values);
}

但这会给我一个不安全的强制转换警告,因为values()现在返回的是列表而不是列表 。我知道编译代码后泛型类型信息会丢失,但是由于的返回类型总是字符串类型的列表,所以它应该是安全的?

if ( this instanceof PropertyOne<?>){
   List<String> vs = ((PropertyOne<?>)this).values();
   System.out.println(vs);
}
  1. 为什么列表 类型信息首先丢失?
  2. 是否可以直接动态强制转换为通配符/无界类型,而不在之后手动转换为propertyone

共有1个答案

贺俊杰
2023-03-14

因为上的泛型非常有限,不能以这种方式使用(我想说J.L.class上的泛型被破坏了,但这可能有点苛刻。它们也有一些用途,只是..不多)。泛型可以表示类实例不能表示的东西;类实例(java.lang.class的实例可以表示泛型不能表示的东西。具体来说,list 不能表示为类实例,而int.class是不能用泛型表示的类实例。

换句话说,当您试图在java.lang.class 实例中通信完整的泛型类型(例如propertyone )时,您就失败了--j.l.class中的T只能是一个没有泛型的类型。

所以,这不是怎么做的。

必须使用toProperty方法。不是为了这篇文章中的问题;它是关于尝试在从(可选包装的)toProperty调用派生的PropertyOne实例上调用type()

除此之外,您在values()调用中遇到麻烦的原因似乎没有实际的相关泛型部分,这是因为过时的java规则:一旦您使用“原始”,所有的东西都是原始的,甚至不需要它的东西也是如此。

因此,在toproperty(cropertyone.class)中,最终将返回一个可选 -一个原始类型,因为这不合适;您需要例如propertyone ,这与propertyone不同(最后一个是raw的;前者不是)-但是对于class ,您不能这样做,因为class 是断开的。现在您进入了原始领域,在这个原始类型上调用values()最终将返回一个原始列表(只是list),您可能认为这仍然会给您一个list ,因为values()的返回类型不依赖于propertyone的泛型,但这不是它的工作方式,java lang规范说不是。

有几种方法可以解决这个难题,但大多数情况下你只是在这里滥用泛型,你真的做不到这些。请记住,泛型是编译器想象中的虚构:它们在运行时根本不存在。无法运行时检查任何内容。一旦开始混合泛型和运行时构造,如instanceofx.isassignablefrom,就永远不会成功。

如果必须的话,您可以使用一种叫做“超级类型标记”的东西--您可以在谷歌上搜索它(在'java'中加入关键字),这些标记可以非常精确地表示泛型中的任何内容。但这听起来仍然是个错误;但我不能告诉你们在这里要做什么,你们的问题描述是在谈论一个破碎的解决方案,而不是破碎的解决方案试图解决的问题。

 类似资料:
  • 我有一个父类来处理我所有的自定义异常,父母异常。我希望所有的子异常都有一个方法来向异常添加消息。为了做到这一点,我创建了一个泛型方法,在向其添加消息后返回泛型类型的对象。我在父类方法中使用来添加消息,然后返回,但是由于该方法返回泛型类型,所以我将其转换为泛型类型T。这似乎是可行的,但是给出了警告。我的代码如下: 该行给出的警告是。这种方法似乎确实如预期的那样有效,所以我并不担心,但我想更好地理解为

  • 问题内容: 我不明白为什么在尝试执行以下操作时会收到警告(未经检查的演员表): 我的意思是将castedMap发布到外部代码的危险是什么?两种操作均可在运行时完美运行: 使用SomeType类型的键从castedMap获取元素 使用SomeType类型的键将元素放入castedMap中。 我只是使用@SuppressWarnings(“ unchecked”)取消警告。 问题答案: 答案可能很无聊

  • 问题内容: 我遇到了Java的异常行为,似乎是一个错误。是吗?即使对象不是的实例,也无法将对象强制转换为通用类型(例如)。这是一个例子: 更新 :感谢cletus和Andrzej Doyle的有用答案。因为我只能接受一个,我接受安杰伊·多伊尔的答案,因为它使我一个解决方案,我觉得是不是 太 糟糕。我认为这是在单行代码中初始化小型Map的更好方法。 然后您这样称呼它: 问题答案: 就像cletus所

  • 我正在编写一个泛型方法,它处理泛型接口的请求类型,并返回一个泛型响应。 前面提到的是我的接口、方法和Pojos。 现在,我正在编写一个请求处理程序,其中有一个方法 上述代码的问题是,在调用私有方法 buildResponse 时,我必须强制转换我的响应,但我只是想知道在定义 T 时,我已经指定了 T 扩展响应,而我的私有方法返回实现响应的 MyResponse,那么为什么需要强制转换呢?

  • 我在这里遇到了一个关于带列表的泛型有界类型的小问题。请帮帮我! 有什么方法可以克服这个问题,或者我可以安全地压制警告吗?

  • 有没有一种简单的方法可以做到这一点: 编辑:我写了一份正确答案的工作副本: