关于通用类和ArrayLists的困惑

时间:2013-12-06 20:18:56

标签: java generics arraylist

这是我为问题的上下文做的一组课程

水族馆课程:

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());

它仍然将石斑鱼加入坦克。在运行时不应该抛出异常吗?然后,我如何强制执行以便只将三文鱼物品添加到鲑鱼缸中?

2 个答案:

答案 0 :(得分:4)

泛型仅用于编译时类型安全。如果你想要一个有单独类型坦克的水族箱,它的底层鱼类在编译时是不知道的,那么你在Java中就不走运了。更糟糕的是,因为泛型类型在编译过程中都被删除了,所以你剩下的就是Object

没有类强制转换异常的原因是因为在运行时它只是每个数组索引的FishTank(原始类型),你可以自由地混合鱼(或陆地动物,或心理结构)

解决此类问题的一种方法是通过包含Class< T >字段使您的FishTank在运行时了解其成员资格。然后坦克可以在addFish()期间进行运行时间检查,尽管所述检查的严格性有限(例如,如果您的鱼本身是一个通用容器,您仍然可以在同一个容器中混合容器; getClass()返回“已擦除”的类对象。)

答案 1 :(得分:2)

  

这怎么可能?

因为泛型类型参数在运行时被擦除,并且在向集合添加元素时未进行检查。它们仅在进行演员表时进行检查。 (但不是T的强制转换,因为T被删除,所以只变成Object,所以这样的演员不会检查任何内容。)