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

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?

最佳答案

这里的问题是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
}

10-06 13:31