Java 为什么泛型方法更改赋值中的参数化类型?

Java 为什么泛型方法更改赋值中的参数化类型?,java,generics,Java,Generics,在编写处理表单数据的通用方法时,我遇到了以下(在我看来)未执行的行为。给定以下代码: public class Test { public <T> void someGenericMethod(Integer a) { @SuppressWarnings("unchecked") T t = (T) a; System.out.println(t); System.out.println(t.getClass()); }

在编写处理表单数据的通用方法时,我遇到了以下(在我看来)未执行的行为。给定以下代码:

public class Test {
   public <T> void someGenericMethod(Integer a) {
      @SuppressWarnings("unchecked")
      T t = (T) a;
      System.out.println(t);
      System.out.println(t.getClass());
   }

   public static void main(String[] args) {
      Test test = new Test();
      test.<BigDecimal>someGenericMethod(42);
   }  
}
事实上,如果我向方法签名添加另一个参数(如
字符串b
),并进行另一次赋值
t2=(T)b
,程序将打印

42
class java.lang.String 
为什么
t
变量将其类型更改为
Integer
(很可能是对类型t进行了某种升级,使其成为对象)

对此行为的任何解释都是受欢迎的

(T)a
是未经检查的强制转换:由于运行时无法知道T是什么类型,因此它实际上无法检查a是否属于T类型

执行此操作时,编译器会发出警告;在您的例子中,您已通过写入
@SuppressWarnings(“未选中”)
来抑制该警告


编辑后添加(回答下面评论中的进一步问题):

如果要检查强制转换,可以编写以下内容:

public class Test {
   public <T> void someGenericMethod(Class<T> clazz, Integer a) {
      T t = clazz.cast(a);
      System.out.println(t);
      System.out.println(t.getClass());
   }

   public static void main(String[] args) {
      Test test = new Test();
      // gives a ClassCastException at runtime:
      test.someGenericMethod(BigDecimal.class, 42);
   }
}

但那是
main
的错误,而不是
someGenericMethod
。:-)

编译时,上面的代码基本上变成了以下非泛型方法:

public void someGenericMethod(Integer a) {
   Object t = a;
   System.out.println(t);
   System.out.println(t.getClass());
}

没有演员阵容。没有例外。

您在方法签名中指定了一个类型参数,但从不使用它

我想你想要这样的东西:

public class Test {
   public <T> void someGenericMethod(T someItem) {
      System.out.println(someItem);
      System.out.println(someItem.getClass());
   }
}

public static void main(String[] args) {
    Test test = new Test();
    BigDecimal bd = new BigDecimal(42);

    test.someGenericMethod(42);    // Integer
    test.someGenericMethod("42");  // String
    test.someGenericMethod(42L);   // Long
    test.someGenericMethod(bd);    // BigDecimal
}  
公共类测试{
public void someGenericMethod(T someItem){
System.out.println(someItem);
System.out.println(someItem.getClass());
}
}
公共静态void main(字符串[]args){
测试=新测试();
BigDecimal bd=新的BigDecimal(42);
test.someGenericMethod(42);//整数
test.someGenericMethod(“42”);//字符串
test.someGenericMethod(42L);//长
test.someGenericMethod(bd);//BigDecimal
}  
请注意,不需要强制转换

参数类型在方法签名中声明并从参数推断

在您的代码中,您正在参数化方法调用(我从未见过),并传入一个int


很难理解您想做什么,因为您的示例代码什么都不做。

是的,是未经检查的强制转换,但是为什么不抛出
ClassCastException
而不是将
T
的类型更改为
Object
?因为它是未经检查的强制转换。运行时无法检查强制转换的有效性。如果运行时可以检查强制转换,它将看到它无效,并抛出一个
ClassCastException
;但它不能,所以它不能,也不能。我不知道你为什么会有其他想法。未经检查强制转换的定义是,如果在运行时知道完整的类型信息,它无法检查是否会抛出
ClassCastException
。感谢您的澄清,不知道未经检查强制转换意味着,
测试中的
东西。如果方法签名不包含至少一个
T
参数,则某些泛型方法调用是非常无用的?谢谢,因此如果不在方法签名中添加类型为
T
的参数,
是无用的。。。
public void someGenericMethod(Integer a) {
   Object t = a;
   System.out.println(t);
   System.out.println(t.getClass());
}
public class Test {
   public <T> void someGenericMethod(T someItem) {
      System.out.println(someItem);
      System.out.println(someItem.getClass());
   }
}

public static void main(String[] args) {
    Test test = new Test();
    BigDecimal bd = new BigDecimal(42);

    test.someGenericMethod(42);    // Integer
    test.someGenericMethod("42");  // String
    test.someGenericMethod(42L);   // Long
    test.someGenericMethod(bd);    // BigDecimal
}