我有这个通用功能:
public static <T extends Number> T sum(List<T> list){
Number tot = 0;
for(Number n: list){
tot = tot.doubleValue() + n.doubleValue();
}
return (T)tot;
}
回想一下这段代码:
public static void main(String[] args) {
ArrayList<Integer> listInt = new ArrayList<>();
listInt.add(3);
listInt.add(5);
listInt.add(6);
listInt.add(8);
System.err.println("Sum: " + Calcolatrice.sum(listInt))
}
因此我希望(作为listInt是一个整数的ArrayList),函数sum返回的值是T = Integer,在这种情况下,给我一个从Double到Integer的转换错误。 结果的类型是Double,不会抛出任何错误。 演员(T)tot没有所需的结果。
我想这是因为Java处理泛型站点阶段,但是有人知道更好地解释它为什么会这样工作?
答案 0 :(得分:3)
Generics仅在编译时使用,以确保您的代码不会出错:此处,参数为ngOnInit() {
this.route.params
.switchMap((params: Params) => this.recipeService.getElement(+params['id']))
.subscribe(element => this.form.patchValue(element);
}
,接收变量必须为List<T>
类型。就是这样。
在运行时期间,T
不存在,T
不是tot
的实例;这是一个T
。
您可以在方法中使用Number
来接收未定义的实例,但是,例如,您无法创建T
。
答案 1 :(得分:3)
当您查看类型层次结构时,您会发现Integer
和Double
都是Number
的子项:所以他们是兄弟姐妹而您无法直接将Double
强制转换为{ {1}}:
Integer
编译器无法确切知道 Double testDbl = 3.14;
Integer testInt = (Integer)testDbl; // this will NOT compile
函数的return语句中的强制转换是否有效:但编译器会显示警告:
sum
由于强制转换Unchecked cast: 'java.lang.Number' to 'T'
,编译器只会理所当然地认为你的函数返回(T)tot
(它没有)。
最后,由于type erasure,没有运行时检查。
答案 2 :(得分:1)
返回类型的Calcolatrice.sum(listInt)
实际上是Integer
,这要归功于您示例中sum
末尾的演员表。但是结果的实际类型是Double
。显然这不是一个好的情况,但它发生的原因是你明确地告诉编译器中的编译器返回值与返回值具有相同的类型。
这种情况意味着如果您改为撰写Calcolatrice.sum(listInt).toString()
,则会得到ClassCastException: java.lang.Double cannot be cast to java.lang.Integer
,因为您将在Integer.toString()
上呼叫Double
。您的代码实际执行的是System.out.println("Sum: "+ String.valueOf(Calcolatrice.sum(listInt)))
,因为它在调用Object
之前向下转换为toString
(从而解决冲突)。
正如@TmTron指出的那样,你无法在Double
和Integer
盒装类型之间进行投射,就像使用基元一样。
即。
int i = (int) 2.0;
遵循以下不同的规则:
Integer i = (Integer) new Double(2.0)