0

Let's say I have these classes:

public interface Ordinal{}

public class One implements Ordinal {
    public static final One FIRST = new One();
}

public class Two extends One {
    public static final Two SECOND = new Two();
}

public class Three extends Two {
    public static final Three THIRD  = new Three();
}

Then an interface, with a method which accepts any sub type of Ordinal interface.

public interface UseOrdinal<T extends Ordinal> {
    void use(T ordinal);
}

Then a client which implements interface.

public class Client implements UseOrdinal<Three> {

    @Override
    public void use(Three ordinal) {};
}

The problem is that Client's use method can only accept instances of class Three. But I want that it would accept it's super types as well, such as One and Two. How can I achieve this?

Edit (added question Context): I have loads of small and different collections ranging from 1 to 12 elements in my application. So to make it more readable and reduce exception handling, I want to encapsulate access to it's elements, so that instead of T get(int index) I would have T get(Ordinal o) where Ordinal would contain only allowed indexes for particular collection.

Dennis Grinch
  • 353
  • 3
  • 13

2 Answers2

0

You have to make Client class generic and pass the generic parameter to UseOrdinal.

public class Client<T extends Ordinal> implements UseOrdinal<T> {

    @Override
    public void use(T ordinal) {};
}

Or simply pass Ordinal as the generic argument, because all of your classes are derived from it:

public class Client implements UseOrdinal<Ordinal> {

    @Override
    public void use(Ordinal ordinal) {};
}

And later in use method body you can check what class is passed using instanceof keyword:

@Override
public void use(T ordinal) {
    if (ordinal instanceof One) {
        // handle object of class One
    }
    else if (ordinal instanceof Two) {
        // handle object of class Two
    }
    else if (ordinal instanceof Three) {
        // handle object of class Three
    }
};

Although, in my opinion, having three Client classes to handle three different Ordinal types would be a better (more OOP) idea.

Jezor
  • 3,253
  • 2
  • 19
  • 43
  • This is not a solution for me. Because I want to restrict possible types which can be passed to `use` method. So that if `Two` is acceptable then, `One` and `Two` should be allowed, not `Three`. – Dennis Grinch Sep 10 '16 at 18:32
  • @DennisGrinch ~~then simply `implements UseOrdinal, UseOrdinal`. You can implement more than one interface, only deriving from classes is restricted to one.~~ scratch that, apparently you can't do that in Java. `implements UseOrdinal` and then casting could do the trick, but take a look at [this answer](http://stackoverflow.com/questions/1297972/how-to-make-a-java-class-that-implements-one-interface-with-two-generic-types). – Jezor Sep 10 '16 at 18:37
  • @DennisGrinch Okay, scratch that too. Please rethink your design, otherwise you may have to deal with throwing [UnsupportedOperationException](https://docs.oracle.com/javase/7/docs/api/java/lang/UnsupportedOperationException.html). If `Three` shouldn't be used with `Client` class, why is it derived from `Two`? – Jezor Sep 10 '16 at 18:56
0

Based on the context, the following might be a better approach. I'm assuming you want to avoid runtime check for IndexOutOfBounds.

public interface OneElementCollection<T> {

    T getFirst();
}

public interface TwoElementCollection<T> extends OneElementCollection<T> {

    T getSecond();
}

// etc.

As mentioned by @Jezor the design is somewhat questionable, unless you require something like a tuple data structure and the size is always within [1..12].

AlmasB
  • 3,377
  • 2
  • 15
  • 17