【问题标题】:Java generics - assigning Object to a typed valueJava 泛型 - 将 Object 分配给类型化的值
【发布时间】:2022-12-08 01:28:15
【问题描述】:

我有以下设置。

interface Initializable<T> {
   T getValue();
   void setValue(T value);
}

class BaseClass {
  
  private final String code; // has getter and setter

  ///
}

class StringValue extends BaseClass implements Initializable<String> {

   private final String value;

   @Override
   public void setValue(String value) {
      this.value = value;
   }

   @Override
   public String getValue() {
      return value;
   }
}

class IntValue extends BaseClass implements Initializable<Integer> {
   
   private final Integer value;

   @Override
   public void setValue(Integer value) {
      this.value = value;
   }

   @Override
   public Integer getValue() {
      return value;
   }
}

class NotInitializable extends BaseClass {

   /////
}

我有一个 BaseClass 实例列表,我想为 Initializable 实例设置值字段,如下所示。我希望能够在没有原始使用的情况下做到这一点。我似乎无法完成这项工作。任何帮助表示赞赏。 TIA

List<BaseClass> fields; // populated
Map<String, Object> vauleByCode; // populated

for (final BaseClass bc : fields) {
   if (bc instanceof Initializable) {
     
      // I would like to set this value of type Object to the value field in Initializable
      final Object value = valueByCode.get(bc.getCode());

      // I would not like to use Raw variable here (i. e without the generic ?)
      Initializable<?> init = (Initializable<?>) bc;
      init.setValue(value) // set value here 
   }
}

【问题讨论】:

  • 第二个代码 sn-p 可能不是您“拥有”的实际“设置”:它有基本的拼写错误 (vaule),并且它使用的是 setValue,没有任何参数。您究竟在哪里检查您从地图中获取的 Objects 的实际运行时类型是否与 bc-field 的类型相匹配?如果它试图将一个整数设置到 String 字段中怎么办,然后呢?
  • 谢谢你的评论!没错,我希望能够使用通用方法或其他方式动态设置它而无需显式检查。
  • 此外,自 generics are erased 起,如果不强制转换(因此放弃类型安全),这将无法工作。绑定的&lt;?&gt; 也会产生问题,因为我们无法在运行时确定泛型参数的类型。
  • “我希望能够在不明确检查的情况下动态设置”- 好吧,你告诉编译器的方式是强行将bc转换为Initializable&lt;Object&gt;,然后调用bc.setValue(value)

标签: java generics


【解决方案1】:

我必须假定,您的目标是检测类型错误,其中在 valueByCode 中找到的值与您的 Initializable 实例的通用类型不匹配。例如,您要确保不将某人引用为 Initializable&lt;Integer&gt; 的对象上的 String 传递给 setValue(),因为这会在某个遥远的时间和地点,在调用站点上导致 ClassCastException没有明确的演员表。那将是此分配中的错误,而不是调用者中的错误;分配应该失败,而不是默默地忽略类型不匹配。

如果类实现 Initializable 如问题所示,则类型参数不被擦除,并且可以在运行时用于检查类型。也就是说,当您定义一个像 class StringValue extends BaseClass implements Initializable&lt;String&gt; 这样的类时,String 会被编译到该类中,并可用于在运行时强制执行类型安全。

您可以使用反射(通过 ParameterizedType)找到 Initializable 实现的泛型类型参数,但由于这些实现可能有很大差异,处理所有可能性会使该代码相对复杂。

相反,使用原始类型(正如你在问题中所说的那样)。如果存在类型不匹配,当您调用 setValue() 时将引发 ClassCastException。这保留了泛型类型安全,因此通过泛型方法调用 getValue() 的任何人都不会遇到 ClassCastException,即使他们没有向下转换结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-22
    • 1970-01-01
    • 2014-11-25
    • 1970-01-01
    • 1970-01-01
    • 2021-07-02
    • 2020-06-12
    • 1970-01-01
    相关资源
    最近更新 更多