扩展泛型类时如何传递多个泛型参数 [英] How to pass multiple generic parameters when extending a generic class
问题描述
下面的代码不会编译,但我希望创建一些类似的功能来编译:
The following will not compile but I wish to create something of similar functionality which will compile:
public class FreezerTest
{
interface Edible{}
interface SmallerThanABeachball{}
interface Freezeable{}
abstract class BoxedItem
{}
class Marbles extends BoxedItem
{}
class IceCream extends BoxedItem implements Freezeable, SmallerThanABeachball, Edible
{}
class MyBrother
{}
class Banana implements Edible, SmallerThanABeachball
{}
class Cat implements SmallerThanABeachball
{}
abstract class StorageChest<T>{
public void add(T toStore){}
}
class MiniFoodFreezer extends StoreageChest<Freezeable & Edible & SmallerThanABeachball>{
}
public FreezerTest(){
MiniFoodFreezer freezer = new MiniFoodFreezer();
freezer.add(new Cat());//DESIRE COMPILE ERROR
freezer.add(new IceCream());//DESIRE OK
freezer.add(new MyBrother());///DESIRE COMPILE ERROR
freezer.add(new Banana());//DESIRE COMPILER ERROR
freezer.add(new Marbles());//DESIRE COMPILER ERROR
}
}//end
一个想法是创建一个全面的接口,然后通过
One thought was to create an all-encompassing interface and then pass that:
interface WillFitInMiniFoodFreezer extends Edible, SmallerThanABeachball, Freezeable{}
class MiniFoodFreezer extends StorageChest<WillFitInMiniFoodFreezer>{
}
...但是如果Edible,SmallerThanABeachball和Freezeable都来自第三方库和其他第三方库引用这些类型,其中一些必须满足WillFitInMiniFoodFreezer条件的接口实现,但没有明确实现WillFitInMiniFoodFreezer?
...however what if Edible, SmallerThanABeachball, and Freezeable are all from a 3rd party library and other third-party libraries refer to these types, some of which have the interface implementations necessary meet the criteria for WillFitInMiniFoodFreezer but do not explicitly implement WillFitInMiniFoodFreezer?
推荐答案
这里的问题是 Freezeable&食用& SmallerThanABeachball
本身不是一种类型 - 例如,在声明类型参数时,&符号(&
)只能用于定义多个上限,例如< T扩展了Freezeable&食用& SmallerThanABeachball>
。此语言限制在此处进一步讨论:如何引用具有多个边界的泛型返回类型
The issue here is that Freezeable & Edible & SmallerThanABeachball
is not itself a type - the ampersand (&
) can only be used to define multiple upper bounds when declaring a type parameter, for example <T extends Freezeable & Edible & SmallerThanABeachball>
. This language limitation is further discussed here: How to reference a generic return type with multiple bounds
一种解决方法是使用组合和通用 add
方法:
One workaround is to use a combination of composition and a generic add
method:
class Freezer extends StoreageChest<Freezeable> { }
class MiniFoodFreezer {
private final Freezer freezer = new Freezer();
public <T extends Freezeable & Edible & SmallerThanABeachball> void add(
final T toStore
) {
freezer.add(toStore);
}
}
缺点是 MiniFoodFreezer
不再是是 任何东西的StoreageChest
,所以您失去了继承的直接好处。但是,您可以根据需要公开不同类型的视图。例如,假设 StoreageChest< T>
implements Iterable< T>
:
The downside being that MiniFoodFreezer
no longer is-a StoreageChest
of anything, so you lose any direct benefits of inheritance. However, you can expose differently typed views of the same objects as needed. For example, assume StoreageChest<T>
implements Iterable<T>
:
class MiniFoodFreezer {
private final Freezer freezer = new Freezer();
public <T extends Freezeable & Edible & SmallerThanABeachball> void add(
final T toStore
) {
freezer.add(toStore);
}
public Iterable<Freezeable> asFreezables() {
return freezer;
}
public Iterable<Edible> asEdibles() {
// this is okay because add must take an Edible and Iterable is read-only
@SuppressWarnings("unchecked")
final Iterable<Edible> edibles = (Iterable<Edible>)(Iterable<?>)freezer;
return edibles;
}
public Iterable<SmallerThanABeachball> asSmallerThanBeachballs() {
// same reasoning as above
@SuppressWarnings("unchecked")
final Iterable<SmallerThanABeachball> smallerThanBeachballs =
(Iterable<SmallerThanABeachball>)(Iterable<?>)freezer;
return smallerThanBeachballs;
}
}
然后我们可以这样做:
final MiniFoodFreezer miniFoodFreezer = new MiniFoodFreezer();
miniFoodFreezer.add(new IceCream());
miniFoodFreezer.add(new SnoCone());
miniFoodFreezer.add(new Slushy());
for (final Freezeable freezable : miniFoodFreezer.asFreezables()) {
// do freezable stuff
}
for (final Edible edible : miniFoodFreezer.asEdibles()) {
// do edible stuff
}
for (
final SmallerThanABeachball smallerThanABeachBall :
miniFoodFreezer.asSmallerThanBeachballs()
) {
// do smaller-than-a-beach-ball stuff
}
这篇关于扩展泛型类时如何传递多个泛型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!