我有一个具有以下功能的Box泛型类:
put
方法中的一个应该允许客户端插入一个框并将其内容发送到当前框。我希望此方法能够获得两种类型的框:Box<Number>
和Box<Integer>
,这就是我将put(Box<T>)
方法更改为put(Box<? extends Number> box)
的原因。但是我收到了编译警告。我在这做错了什么?
这是我目前的代码: 我得到的警告是:类型安全:未捕获来自捕获#1的投射?将Number扩展为T
public class Box<T> {
public T get() {
return element;
}
public void put(T element) {
this.element = element;
}
public void put(Box<? extends Number> box) {
put((T) box.get()); // this is where i get the warning
}
private T element;
}
public class BoxClient {
public static void main(String[] args) {
Box<Number> nBox = new Box<Number>();
Box<Integer> iBox = new Box<Integer>();
nBox.put(iBox);
}
}
答案 0 :(得分:6)
将其更改为
public void put(Box<? extends T> box) {
put(box.get());
}
答案 1 :(得分:3)
如果我测试你的代码,那么我会在这个方法中收到警告:
public void put(Box<? extends Number> box) {
put( (T) box.get());
}
警告是:
未选中广告:
java.lang.Number
至T
问题是您的通用类型T
没有bounds,因此它可以是任何内容,由于type erasure它将被删除为Object
。
变量box
的泛型类型有一个界限,很明显,它总是某种Number
。
您的广告(T) box.get()
现在“不安全”,因为box.get()
返回的子类型为Number
,T
可以是任何内容,例如String
。因此编译无法确定此强制转换是否总是正常并且不会抛出ClassCastException
。
这就是他警告你不安全演员的原因。
答案 2 :(得分:1)
你的Box有一个通用类型T
,它不对它的类型做任何假设(没有界限)。如果您的框只能包含Number
s(以及Number
的子类型),则可以将其更改为:class Box<T extends Number>
。
和您的方法:put(Box<? extends T> box)
,以便它接受T
及其任何子类型。
答案 3 :(得分:1)
您的班级Box
定义了通用类型T
。
T
可以是任何东西。即“包含任何种类对象”的框
然后,您的方法会收到Box<? extends Number>
。即“包含数字类型的框”。
问题在于你的方法:
public void put(Box<? extends Number> box) {
put(box.get());
}
该方法接收“包含数字的方框”,但是,它会转换为T
。
请记住,T
可以是任何内容,因此您可以对某些实际上不是数字的内容执行强制转换。考虑这个例子:
public class BoxClient {
public static void main(String[] args) {
Box<String> sBox = new Box<String>();
Box<Integer> iBox = new Box<Integer>();
iBox.put(1);
sBox.put(iBox);
System.out.println(sBox.get());
}
}
在这里,我创建了一个Box<String>
或“一个包含字符串的框”,并添加了一个Box<Integer>
或“一个包含数字的框”。
通过泛型代码,这是有效的,因为T
可以是任何东西,但是,如果你试图执行它
java.lang.ClassCastException:java.lang.Integer无法强制转换为java.lang.String
那是因为Integer
1无法转换为String
。
为了确保永远不会发生这种情况,您需要更改Box
的声明以强制执行T extends Number
,如下所示:
public class Box<T extends Number> {
public T get() {
return element;
}
public void put(T element) {
this.element = element;
}
public void put(Box<? extends T> box) {
put((T) box.get());
}
private T element;
}
更新:
如上所述,我之前的回答可能仍然不安全。
比如说,如果你有一个Box<Number>
并尝试添加Box<Integer>
,它仍然会被允许并仍然会抛出异常。
最佳解决方案是添加bayou.io的建议。
这样你就可以确保:
1:您的Box总是包含数字
2:您的Box只能从T
UPDATE2:
正如下面newacct的评论所述,对T
的强制转换也没有必要。
希望这有帮助!
答案 4 :(得分:0)
您的问题导致事实,即Java 5中引入了泛型类型。因此,方法签名不包含有关的信息。 通用类。
课程草稿:
public abstract class Draft<T> {
public abstract void put(T element);
public abstract void putDraft(Draft draft);
}
使用此草案,代码保持可读性,您没有任何编译器 警告。
查看here以查找有关此问题的更多信息。