【问题标题】:How to pass multiple generic parameters when extending a generic class扩展泛型类时如何传递多个泛型参数
【发布时间】:2013-12-21 07:23:51
【问题描述】:

以下内容无法编译,但我希望创建可以编译的类似功能:

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?

【问题讨论】:

  • 恐怕您必须对其进行运行时检查,或者创建一个包装 IceCream 并实现 WillFitInMiniFoodFreezer 的适配器类。

标签: java generics


【解决方案1】:

这里的问题是Freezeable &amp; Edible &amp; SmallerThanABeachball 本身不是一个类型 - 与号 (&amp;) 只能用于在声明类型参数时定义多个上限,例如 &lt;T extends Freezeable &amp; Edible &amp; SmallerThanABeachball&gt;。此处进一步讨论了此语言限制: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 不再是 is-a StoreageChest 任何东西,所以你失去了继承的任何直接好处。但是,您可以根据需要公开相同对象的不同类型视图。例如,假设StoreageChest&lt;T&gt; 实现Iterable&lt;T&gt;

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
}

【讨论】:

    【解决方案2】:

    正如 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 
    

    【讨论】:

      猜你喜欢
      • 2016-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-23
      • 1970-01-01
      • 2012-07-24
      • 1970-01-01
      相关资源
      最近更新 更多