【问题标题】:Generic method returns the correct Object while assigning to variable but not when used with a method通用方法在分配给变量时返回正确的对象,但在与方法一起使用时不返回
【发布时间】:2012-10-21 04:41:54
【问题描述】:

我正在使用一些带有泛型的代码,我不确定为什么会引发编译错误。

  public static void main(String[] args) {

    System.out.print("s");
    setInteger(prepareNumber("1")); // Error here! solved by casting: setInteger((Integer)prepareNumber("1"))
    Integer c = prepareInteger("1");
    System.out.print(c);

  }

  public static Integer prepareInteger(Object number) {
    return prepareNumber(number).intValue();
  }

  private static <T extends Number> T prepareNumber(Object number) {

    T returnValue = null;

    // handle a blank number
    if (number == null || !NumberUtils.isNumber(number.toString())) {
      returnValue = null;
    } else {
      if (number.toString().contains(".")) {
        returnValue = (T) Double.valueOf(number.toString());
      } else {
        returnValue = (T) Integer.valueOf(number.toString());
      }
    }

    return returnValue;
  }

  private static void setInteger(Integer a){    
  }

只需进行强制转换即可轻松解决此问题,但这是不希望的,因为泛型应该检测到方法需要 Integer 并且应该提供返回值本身而不是超类型。

PS:不要介意解析代码,只是测试的东西。

谢谢!

【问题讨论】:

  • 错误信息说明了什么?这不是不言自明吗?
  • prepareNumber 返回一个数字,它可能不是整数。事实上,如果number.toString().contains("."),您的“修复”将引发 ClassCastException。真正的问题是,为什么要传递 setInteger 可能不是 Integer 的东西?
  • 实际上, T method() 本质上说:“此方法返回的东西可以在编译时转换为每种引用类型”,因此该方法可能返回的唯一值是 null。事实上,您的代码会引发与泛型相关的警告 (javac -Xlint:unchecked);并且 Java 不保证出现泛型相关警告时的类型安全。 prepareNumber 实际上没有理由是通用的:普通的 Number prepareNumber(Object number) 就可以了。
  • @JB : 该方法引发以下错误:Test 类型中的方法 setInteger(Integer) 不适用于参数 (Number)
  • @Ignis :希望它是通用的原因基本上是因为我将整数或双精度数作为字符串,我需要解析它们并将它们放入对象的设置器中,无论是属性.

标签: java generics


【解决方案1】:

编译器无法推断在这种情况下prepareNumber("1") 应该返回什么类型。您可以通过将结果放在临时变量中来正确推断:

Integer value = prepareNumber("1");        
setInteger(value);

或者如果parseNumberYourClass 类中的静态方法,你可以明确地告诉编译器你期望什么类型:

setInteger(YourClass.<Integer>prepareNumber("1"));

或者,如果您可以更改方法签名以帮助编译器:

setInteger(prepareNumber("1", Integer.class));

private static <T extends Number> T prepareNumber(Object number, Class<T> classType) {
   ....
}

【讨论】:

  • 是的,我知道编译器无法确定返回对象的类型,但是在我控制的方法中,它会根据条件是 Integer 或 Double,所以我期待它使用方法签名解决:(
  • 很好的信息,我不知道您可以通过这种方式定义您的期望。我仍然有同样的问题,我需要 if 能够知道 setter 方法会发生什么,但看起来我必须制作几个中间方法并使用它们。
  • 好吧,如果你想为自己节省一个中间方法,你可以添加一个类令牌参数..看我的编辑。
  • 另外,在这种情况下,另一种备用方法并利用泛型的方法是更改​​方法的签名: private T prepareNumber(Object number, Class type)
【解决方案2】:

prepareNumber 方法返回 Number 的类型,它是 Integer 的超类,但是您的 setInteger 正在接受 Integer 并且在这种情况下没有隐式转换。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-25
    • 2018-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多