【问题标题】:Java generics casting to <?>Java 泛型转换为 <?>
【发布时间】:2012-11-23 10:31:07
【问题描述】:

我有以下课程

public class DBField<T>
{
  protected String fieldName;
  protected FieldConverter c;
  protected T value;
  protected DataObject dataObject;

  public T getValue()
  {
    return value;
  }

  public void setValue(T value)
  {
    this.value = value;
  }

  public DBField(DataObject dataObject, String fieldName, FieldConverter c)
  {
    this.fieldName = fieldName;
    this.c = c;
    this.dataObject = dataObject;
  }
}

T 应该是布尔值、浮点数、字符串等。

protected void ValuesToFields(List<Object> values, List<DBField<?>> fields) throws Exception
  {
    if (values.size() != fields.size())
      throw new Exception("Length does not match.");
    for (int i = 0; i < values.size(); i++)
    {
      Class valueClass = values.get(i).getClass();
      Class fieldClass = fields.get(i).getValue().getClass();
      if (valueClass.equals(fieldClass))
      {
        fields.get(i).setValue(values.get(i));
      }
      else
        throw new Exception("type mismatch");
    }
  }

Object 也应该包含 Boolean、Float、String 等。

这段代码的问题是

fields.get(i).setValue(values.get(i));

语法检查器告诉我需要转换 values.get(i) (到?我怀疑)。我该怎么做呢?我已经尝试过 valueClass.cast(values.get(i)) 但没有运气。

【问题讨论】:

    标签: java generics casting


    【解决方案1】:

    为了您的代码安全,对于每个i,values 的第 i 个元素必须是 DBField 的类型参数的实例,即@987654324 的第 i 个元素@。您的代码不保证这成立,实际上没有办法在 Java 中声明它们以确保对应元素之间的这种关系是真实的。而且由于类型擦除,您甚至无法在运行时检查元素是否正确,因为给定一个字段,您不知道它的类型参数。所以肯定有一些未经检查的强制转换,我们必须相信这些论点是正确的。

    最简单的做法是将每个字段转换为DBField&lt;Object&gt;:

    ((DBField<Object>)fields.get(i)).setValue(values.get(i));
    

    这有点像“相信我们,我们知道这个字段可以接受任何Object”,因此它可以接受任何类型的值。这有点撒谎,因为我们知道应该有类型参数不是Object 的字段,但是由于无论如何我们都必须进行某种未经检查的强制转换,这种“不安全强制转换”并不比其他解决方案差。

    或者,如果你不想做这个可以说是可疑的强制转换,一个更“合法”的方法是编写一个私有帮助器方法——一个“包装器帮助器”——它显式地命名字段的类型参数,允许我们简单地将值转换为这种类型:

    private <T> static void ValueToField(Object value, DBField<T> field) {
        field.setValue((T)value);
    }
    
    //...
    ValueToField(values.get(i), fields.get(i));
    

    请注意,这里的演员表也是未经检查的演员表。这种方法的缺点是需要编写额外方法的开销。

    附:您对valueClass 和fieldClass 的检查不是很好。首先,如果某个字段的值当前为null,则会导致空指针异常。此外,DBField&lt;T&gt; 的值是T 的任何实例,其实际类可能是T 的子类;所以如果你用它来检查,它可能会导致不好的结果。最好DBField包含T的类的类对象,这样就可以用来检查了。此外,您不应该将相等性与值的实际类进行比较,因为 T 的子类也可以工作,因此您应该检查 fieldClass.isInstance(values.get(i))。

    【讨论】:

      【解决方案2】:

      if(values.get(i) instanceof valueClass)?

      【讨论】:

      • 这有什么帮助?仅在该行之前放置一个 if 并不能解决以这种方式保持不变的错误的行。问题是 setValue 需要 Boolean、String 等,而 values.get(i) 是一个对象。
      • 我的意思是用我的替换你的if。我认为语法检查器可能存在问题,即检查 2 个类彼此相等还不够好。
      【解决方案3】:

      你有一个List&lt;Object&gt;。

      您应该有一个 List&lt;DBField&lt;Object&gt;&gt; 来匹配它,或者将您的第一个列表更改为 List&lt;?&gt;

      【讨论】:

      • 这没有帮助。问题是 setValue 需要 Boolean、String 等,而 values.get(i) 是一个对象。
      • 我想说把你的list参数改成list>,基本上意思一样,语法警告应该消失
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-18
      • 1970-01-01
      相关资源
      最近更新 更多