这是我为问题的上下文做的一组课程
水族馆课程:
package test;
import java.util.ArrayList;
public class Aquarium {
// the aquarium is composed of fish tanks
ArrayList<Object> aquarium;
public Aquarium(){
aquarium = new ArrayList<Object>();
}
public <T> void addFishToTank(int index, T fish){
FishTank<T> tank = (FishTank<T>) aquarium.get(index);
tank.addFish(fish);
}
public ArrayList<Object> getAquarium(){
return aquarium;
}
public String toString(){
String holder = "";
int i = 0;
for (Object tank : aquarium){
holder += "Tank " + i + ":\n";
holder += tank.toString();
i ++;
}
return holder;
}
public static void main(String[] args){
Aquarium seaWorld = new Aquarium();
seaWorld.getAquarium().add(new FishTank<Salmon>());
seaWorld.addFishToTank(0, new Salmon());
seaWorld.addFishToTank(0, new Grouper());
System.out.println(seaWorld.toString());
}
}
FishTank课程:
package test;
import java.util.ArrayList;
public class FishTank<T>{
// inside each fish tank there is a group of fish
ArrayList<T> fishGroup = new ArrayList<T>();
public void addFish(T element){
fishGroup.add(element);
}
public String toString(){
String holder = "";
for (T fish: fishGroup){
holder += fish.toString() + "\n";
}
return holder;
}
}
鲑鱼类:
package test;
public class Salmon {
public String toString(){
return "This is a salmon";
}
}
石斑鱼类:
package test;
public class Grouper {
public String toString(){
return "This is a grouper";
}
}
所有代码编译都很好,水族馆的输出结束了
Tank 0:
This is a salmon
This is a grouper
这怎么可能?当我将水箱加入水族箱时
seaWorld.getAquarium().add(new FishTank<Salmon>());
指出它是一个只能容纳Salmon物品的FishTank。首先,我添加了一个Salmon对象
seaWorld.addFishToTank(0, new Salmon());
这很好,因为水族馆指数0的鱼缸是一个装有三文鱼物品的鱼缸。但是当我将一个Grouper对象添加到索引0的Salmon坦克时
seaWorld.addFishToTank(0, new Grouper());
它仍然将石斑鱼加入坦克。在运行时不应该抛出异常吗?然后,我如何强制执行以便只将三文鱼物品添加到鲑鱼缸中?
答案 0 :(得分:4)
泛型仅用于编译时类型安全。如果你想要一个有单独类型坦克的水族箱,它的底层鱼类在编译时是不知道的,那么你在Java中就不走运了。更糟糕的是,因为泛型类型在编译过程中都被删除了,所以你剩下的就是Object
。
没有类强制转换异常的原因是因为在运行时它只是每个数组索引的FishTank
(原始类型),你可以自由地混合鱼(或陆地动物,或心理结构)
解决此类问题的一种方法是通过包含Class< T >
字段使您的FishTank在运行时了解其成员资格。然后坦克可以在addFish()
期间进行运行时间检查,尽管所述检查的严格性有限(例如,如果您的鱼本身是一个通用容器,您仍然可以在同一个容器中混合容器; getClass()返回“已擦除”的类对象。)
答案 1 :(得分:2)
这怎么可能?
因为泛型类型参数在运行时被擦除,并且在向集合添加元素时未进行检查。它们仅在进行演员表时进行检查。 (但不是T
的强制转换,因为T
被删除,所以只变成Object
,所以这样的演员不会检查任何内容。)