2013-12-21 4 views
1

Ниже не будет компилировать, но я хочу, чтобы создать что-то подобной функциональности, который компилируется:Как передать несколько параметров универсального при расширении обобщенного класса

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

... Но что, если съедобные, SmallerThanABeachball и Freezeable все из библиотеки 3-й партии и других сторонних библиотек относятся к этим типам, некоторые из которых имеют реализации интерфейса необходим знакомься критерии f или WillFitInMiniFoodFreezer, но явно не реализует WillFitInMiniFoodFreezer?

+4

Боюсь, вам придется сделать это во время выполнения проверить или создать класс адаптера, который обертывает IceCream и реализует WillFitInMiniFoodFreezer. –

ответ

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

} 

вы хотите сделать свое собственное хранение, которые принимают типы, реализующие три интерфейса Съедобные, SmallerThanABeachball, Freezeable

OK не красивая, но простая работа вокруг

создать интерфейс, которые реализуют это интерфейсы

и создать класс, который ничего не делать, но расширение целевой класс и реализует новый интерфейс, сочетающий

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 
Смежные вопросы