43002

How to pass multiple generic parameters when extending a generic class

Question:

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

...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?

Answer1:

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: <a href="https://stackoverflow.com/questions/14464226/how-to-reference-a-generic-return-type-with-multiple-bounds" rel="nofollow">How to reference a generic return type with multiple bounds</a>

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

The downside being that MiniFoodFreezer no longer <em>is-a</em> 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; } }

Then we can do:

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 }

Answer2:

as JB Nizet say

<blockquote>

I'm afraid you'll have to make it a run-time check, or to create an adapter class that wraps IceCream and implements WillFitInMiniFoodFreezer.

</blockquote>

this will solve your problem until java solve its generic nonsense

you suppose the following are in some third party library

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

you want to make your own storage that accept types implementing the three interfaces Edible, SmallerThanABeachball, Freezeable

OK not beautiful one but a simple work around

create interface that implement this interfaces

and create a class that do nothing but extending the target class and implementing the new combining interface

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

Recommend

  • Java Plist XML Parsing
  • How to type in Sonatype Nexus a password with special characters in proxy repo?
  • In php, Prepare string and create XML/RSS Feed
  • How to assign to a variable an alias
  • how to sort the field in the mongo document which is inside array
  • Where is exactly is the demarkation between a version of Java and the JVM?
  • Swift: Validate Username Input
  • Interface with multiple implementations in ninject
  • OpenCL bytecode running on another card
  • Implementation of random number generator [duplicate]
  • Nhibernate QueryOver Orderby
  • How to change slowly background attributes in jquery?
  • MySpace DOM?
  • using pinentry-tty in a bash script (like read)
  • Google API - Redirect URI mismatch error
  • Oracle: Using CTE with update clause
  • CakePHP Subquery from SQL
  • overlapping appointments using the entity framework
  • When interface inheritance in Java is useful?
  • In C what exactly happens if i use () to initialize a double dimension array instead of the {}?
  • Symfony 2 error page response
  • Which open source license has no forking [closed]
  • How to explicitly/implicitly implemented interface members in C++/CLI?
  • Django simple Captcha “No module named fields” error
  • Sencha Touch 2.0 Controller refs attribute not working?
  • C++ Partial template specialization - design simplification
  • When to use `image` and when to use `Matrix` in Emgu CV?
  • Display issues when we change from one jquery mobile page to another in firefox
  • What is the “return” in scheme?
  • Different response to non-authenticated users and AJAX calls
  • C# - Serializing and deserializing static member
  • Bug in WPF DataGrid
  • Incrementing object id automatically JS constructor (static method and variable)
  • Arrow is showed instead of the material design version hamburger icon. Why doesn't syncState in
  • Which linear programming package should I use for high numbers of constraints and “warm starts” [clo
  • Data Validation Drop Down Box Arrow Disappearing
  • How can I get HTML syntax highlighting in my editor for CakePHP?
  • How do I configure my settings file to work with unit tests?
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • Binding checkboxes to object values in AngularJs