以下代码是我希望实现的一个例子。不幸的是,如果没有函数getElements()
中的强制转换,就无法编译此代码。
我仍然完全围绕Java泛型,但这似乎是一个相当简单的情况。
非常感谢任何帮助。
import org.junit.Test;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class GenericFruitTest
{
@Test
public void genericFruit()
{
Collection<Apple> apples = new FruitBasket().getApples();
Collection<Orange> oranges = new FruitBasket().getOranges();
Collection<Rye> rye = new BreadBasket().getRye();
}
class FruitBasket extends Basket<Fruit>
{
Collection<Apple> getApples()
{
return getElements(Apple.class);
}
Collection<Orange> getOranges()
{
return getElements(Orange.class);
}
}
private class BreadBasket extends Basket<Bread>
{
private Collection<Rye> rye;
public Collection<Rye> getRye()
{
return getElements(Rye.class);
}
}
class Basket<E>
{
Map<Class<? extends E>, Collection<? extends E>> classCollectionMap = new HashMap<Class<? extends E>, Collection<? extends E>>();
<T extends E> Collection<T> getElements(Class<T> elementClass)
{
// The following line throws compile time "incompatible types" without cast
return classCollectionMap.get(elementClass);
}
}
class Rye extends Bread
{
}
class Apple extends Fruit
{
}
class Orange extends Fruit
{
}
class Fruit
{
}
private class Bread
{
}
}
答案 0 :(得分:3)
在这种情况下,Map
是从Class<? extends E>
到Collection<? extends E>
的映射。就编译器而言,任何Class<? extends E>
都可以合法地映射到任何Collection<? extends E>
。
事实上,您碰巧总是将一个与集合匹配的类放入Map中,这不是编译器所知道的 - 因为您可以将任何扩展E的类放入映射中。
不幸的是,在这种情况下你需要使用强制转换 - 尽管至少泛型允许你将强制转换放在你的方法中,所以任何使用该方法的人都看不到它。
答案 1 :(得分:2)
它需要一个转换,因为编译器不知道任何给定键具有的集合的类型。您的地图显示它将未知类型的Class
映射到未知类型的Collection
,但您无法告诉地图他们必须是同类型。
使用泛型时,大多数情况下无法摆脱强制转换。但是,大多数这些强制转换是未经检查的转换,由于类型擦除而在运行时被删除。关键是,当你可以保证类型安全时,编译器会让你独自一人,你的类的客户端会得到一个类型安全的,无需转换的接口。
当然,如果你搞砸了,运行时无法提醒你。
答案 2 :(得分:-2)
就像在C ++中使用模板元编程一样,您必须指定特定类型,否则编译器不知道如何在运行时运行。