扩展泛型类时如何传递多个泛型参数

时间:2013-12-21 07:23:52

标签: java generics

以下内容不会编译,但我希望创建一些类似的功能,可以编译:

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 

一种想法是创建一个包罗万象的界面然后传递:

interface WillFitInMiniFoodFreezer extends Edible, SmallerThanABeachball, Freezeable{}
class MiniFoodFreezer extends StorageChest<WillFitInMiniFoodFreezer>{
}

...但是,如果Edible,SmallerThanABeachball和Freezeable都来自第三方库,而其他第三方库引用这些类型,其中一些具有必要的接口实现符合WillFitInMiniFoodFreezer的标准但未明确实现WillFitInMiniFoodFreezer?

2 个答案:

答案 0 :(得分:3)

这里的问题是Freezeable & Edible & SmallerThanABeachball本身不是一个类型 - &符号(&)只能在声明类型参数时用于定义多个上限,例如<T extends Freezeable & Edible & SmallerThanABeachball> 。此语言限制将在此处进一步讨论:How to reference a generic return type with multiple bounds

一种解决方法是使用合成和通用add方法的组合:

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>实现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
}

答案 1 :(得分:0)

正如JB Nizet所说

  

我担心你必须把它作为运行时检查,或者创建一个   包装IceCream并实现的适配器类   WillFitInMiniFoodFreezer。

这将解决您的问题,直到java解决其通用废话

您认为以下内容属于某些第三方库

    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) {
        }

    }
    //third party class that has function require type implementing the three interfaces
    class SomeClass{

    <T extends Edible & SmallerThanABeachball & Freezeable> void doSomething(T someThing){
        System.out.println(someThing);
    }

}

你想创建自己的存储,接受实现三个接口的类型Edible,SmallerThanABeachball,Freezeable

好的不是美丽而是一个简单的工作

创建实现此接口的接口

并创建一个除了扩展目标类和实现新的组合接口

之外什么都不做的类
    interface WillFitInMiniFoodFreezer extends Edible, SmallerThanABeachball, Freezeable {
    }

    class MiniFoodFreezer extends StorageChest<WillFitInMiniFoodFreezer> {
    }
    //create your one version of iceCream implement the combining interface

    class MyIceCream extends IceCream implements WillFitInMiniFoodFreezer {
    }
    //you can make new types implementing WillFitInMiniFoodFreezer

    class Potato implements WillFitInMiniFoodFreezer {
    }

    class FreezerTest {

        public FreezerTest() {
            MiniFoodFreezer freezer = new MiniFoodFreezer();
            //what you have wished
            freezer.add(new Cat());//DESIRE COMPILE ERROR
            freezer.add(new MyIceCream());//DESIRE OK
            freezer.add(new Potato());//DESIRE OK
            freezer.add(new MyBrother());///DESIRE COMPILE ERROR
            freezer.add(new Banana());//DESIRE COMPILER ERROR
            freezer.add(new Marbles());//DESIRE COMPILER ERROR
    //third party function parametrized with the three interfaces
    SomeClass thirdPartyClass = new SomeClass();
        thirdPartyClass.doSomething(new MyIceCream()); // ^_^ ok
        thirdPartyClass.doSomething(new Potato()); // ^_^ ok
        thirdPartyClass.doSomething(new Cat());//:( not ok
        }

    }//end