这是我针对问题的上下文而编写的一组类
水族馆类:
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";
}
}
所有代码都能正常编译,Aquarium的输出最终被
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的鱼缸是一个装有鲑鱼物体的鱼缸。但是当我向索引为0的鲑鱼缸添加一个Grouper对象时
seaWorld.addFishToTank(0, new Grouper());
它仍然将石斑鱼添加到坦克中。在运行时是否应该引发异常?然后,如何执行强制措施,以便仅将鲑鱼对象添加到鲑鱼缸?
最佳答案
泛型仅用于编译时类型安全。如果您想要一个具有单独类型的水箱的水族馆,而这些水箱的底层鱼类类型在编译时不知道,那么您在Java中是不走运的。更糟糕的是,由于泛型类型在编译过程中都会被删除,因此剩下的就是Object
了。
没有类强制转换异常的原因是,在运行时,它只是每个数组索引处的FishTank
(原始类型),您可以在其中自由混合鱼类(或陆地动物或心理构造物)。
解决此类问题的一种方法是,通过包含Class< T >
字段,使FishTank在运行时意识到其成员资格。然后,水箱可以在addFish()
期间进行运行时检查,尽管所述检查的严格性是有限的(例如,如果您的鱼本身是通用容器,则仍然可以在同一水箱中混合容器; getClass()返回一个“擦除的”类对象)。