2

Im trying to create an instantiate a generic class called "MultipleBoundsClass" that has multiple bounds - a class called "OrderedPair" and an interface called "Pair"(which Ordered Pair implements).

Ive tried removing the interface boundary and that let me compile. But I dont know why that worked, and how Id get it to successfully with the interface boundary included.

public interface Pair<K, V>
{
  public K getKey();
  public V getValue();
}

public class OrderedPair<K, V> implements Pair
{
  private K key;
  private V value;
  public OrderedPair(K key, V value)
  {
    this.key = key;
    this.value = value;
  }
  public K getKey()
  {
    return key;
  }
  public V getValue()
  {
    return value;
  }
}

class OrderedPair {}
interface Pair {}
public class MultipleBounds<T extends OrderedPair & Pair>
{
  private T t;
  public MultipleBounds(T t)
  {
    this.t = t;
  }
  public T getPair()
  {
    return t;
  }
}

public static void main(String[] args)
{
  OrderedPair<String, Integer> p1 = new OrderedPair<>("even", 8);
  MultipleBounds<OrderedPair> myPair = new MultipleBounds<OrderedPair>(p1);
}

I get the error "type argument OrderedPair is not within bounds of type-variable T". Bounded types restrict the arguments a generic parameter can be, to the class you define and its subclasses, so why is the type OrderedPair not within bounds of itself when the interface is included as a present boundary?

Dylan
  • 375
  • 1
  • 2
  • 12
  • Please specify where the error is coming in the code. I guess it is in your main method – A_C Feb 01 '19 at 07:35
  • You probably don't need to extend both `OrderedPair` and `Pair`. Use `public class MultipleBounds`, as `OrderedPair` already implements `Pair` and is allowed to be a `T` type in `MultipleBounds` – coffman21 Feb 01 '19 at 08:03
  • @coffman21 that works as does only extending the class. So you're saying the cause of the error when extending both, is that OrderedPair already implements Pair? So the only valid scenario for multiple bounds is when the argument's type is that of a subclass of the extended class? – Dylan Feb 01 '19 at 11:53
  • @Dylan no, I'm not saying that it might be a reason for error, I just mentioned that you are extending a type by interface and by class which already implements it - and that is all. It is probably over explained. According to your issue - I tried to compile and run your code, and had no errors. Which Java version do you use? – coffman21 Feb 01 '19 at 13:51
  • @coffman21 10.0.2, you? – Dylan Feb 01 '19 at 13:53
  • 1
    @Dylan Sorry, no meaning in that question. Why are you declaring `class OrderedPair {}` and `interface Pair {}` right before `MultipleBounds` once again, with no types? Here, your `OrderedBound` class does not really implements `Pair` and therefore cannot be used as a `T` type - it is not in bounds by not implementing `Pair`. – coffman21 Feb 01 '19 at 14:03
  • @coffman21 Maybe I misinterpreted the java tutorial: "A type variable with multiple bounds is a subtype of all the types listed in the bound. If one of the bounds is a class, it must be specified first."(https://docs.oracle.com/javase/tutorial/java/generics/bounded.html) – Dylan Feb 01 '19 at 14:25
  • 2
    @Dylan You didn't get it. You have: `public interface Pair { /* blah blah */ }`, and then again you have: `interface Pair {}`, same file, duplicate interface, same for class. That is not okay. Does it represent your code base? If so, you might want to delete the duplicate. – coffman21 Feb 01 '19 at 14:34
  • @coffman21 Thank you for clearing that up for me, I appreciate it. – Dylan Feb 01 '19 at 14:42
  • @Dylan You're welcome. I added an answer to clarify how you might use multiple bounds with an example. – coffman21 Feb 01 '19 at 16:10

1 Answers1

0

I want to provide an example of how you might be using multiple bounds. It is freaky a lot, but may help to understand things.

Suppose we have a Container, and we are able to put something in.

abstract class Container {
    private Object content;

    public void put(Object object) { this.content = object; }
    public Object get() { return content; }
}

Then, there are interfaces to define some properties for those containers. They may be Rollable and/or Inflammable.

interface Rollable { void roll(); /* rolls somehow */ }
interface Inflammable { void burnItself(); /* burns somehow */ }

Then, we define concrete Container classes: a CardboardBox, a GiftBox, a MetalBarrel and a WoodBarrel, and implement interfaces according to their properties:

class CardboardBox extends Container implements Inflammable {
    @Override
    public void burnItself() { /* omit implementation */ }
}

class GiftBox extends Container implements Rollable, Inflammable {
    @Override
    public void burnItself() { /* omit implementation */ }
    @Override
    public void roll() { /* omit implementation */ }
}

class MetalBarrel extends Container implements Rollable {
    @Override
    public void roll() { /* omit implementation */ }
}

class WoodBarrel extends Container implements Rollable, Inflammable {
    @Override
    public void burnItself() { /* omit implementation */ }
    @Override
    public void roll() { /* omit implementation */ }
}

Now, the real bizarre. Suppose you want to create a Stock, where all the things must be Rollable. And Inflammable. Because you want to roll all your containers inside and to be able to burn one of them. You define a Stock:

class Stock <T extends Container & Rollable & Inflammable> {
    private List<T> containers;

    void addContainer(T container) { containers.add(container); }

    void rollAllContainers() { containers.forEach(Rollable::roll); }

    void burnContainer(int index) { containers.get(index).burnItself(); }
}

And then you are able to create one of those. You are not tied to Container type; just to its properties - as they are defined by interfaces.

public static void main(String[] args) {
    Stock<GiftBox> giftBoxStock = new Stock<>();

    GiftBox giftBox = new GiftBox();
    giftBox.put("a gift");
    GiftBox giftBox1 = new GiftBox();
    giftBox1.put("another gift");

    giftBoxStock.addContainer(giftBox);
    giftBoxStock.addContainer(giftBox1);
    giftBoxStock.rollAllContainers();
    giftBoxStock.burnContainer(0);

    Stock<WoodBarrel> woodBarrelStock = new Stock<>();

    WoodBarrel woodBarrel = new WoodBarrel();
    woodBarrel.put("wine");
    WoodBarrel woodBarrel1 = new WoodBarrel();
    woodBarrel1.put("gas");

    woodBarrelStock.addContainer(woodBarrel);
    woodBarrelStock.addContainer(woodBarrel1);
    woodBarrelStock.rollAllContainers();
    woodBarrelStock.burnContainer(1);
}
coffman21
  • 943
  • 11
  • 18