0

After doing some reading, it appears that it is possible to use the & operator to require multiple extends: Class<T extends Class1 & Class2> classObj;

However, I'm looking for a way to enforce "not" functionality at compile time. I have the example where Banana extends Fruit. However, I'm after something along the lines of:

public abstract class Fruit
{
    public abstract String getFlavour();
}

public class Lemon extends Fruit
{
    @Override
    public String getFlavour()
    {
        return "sour";
    }
}

public abstract class Banana extends Fruit
{
    @Override
    public String getFlavour()
    {
        return "very sweet!";
    }

    public abstract String getBananaRipeness();
}

public class UnripeBanana extends Banana
{
    @Override
    public String getBananaRipeness()
    {
        return "unripe";
    }
}

...
    public String methodThatTakesFruitClassButNotBanana( Class<? extends Fruit ! Banana> fruitClass )
    {
        Fruit fruit = fruitClass.newInstance();
        return fruit.getFlavour();
    }

...
        methodThatTakesFruitClassButNotBanana( Lemon.class ); // I want this to compile.
        methodThatTakesFruitClassButNotBanana( UnripeBanana.class ); // I want this not to compile.

Obviously Class<? extends Fruit ! Banana> is not valid syntax. What approaches would you recommend to enforcing this sort of type hierarchy at compile time?

jr.
  • 1,699
  • 14
  • 31
  • 5
    I don't think there is an easy way to do it - what would be easier would be to throw an exception at runtime. But I would question the design before trying to find a workaround. If you can do something with a Fruit that can't be done with a Banana then either your Banana is not a Fruit or more likely, you have put too much stuff in Fruit which is not applicable to any fruits. – assylias Feb 06 '13 at 01:43
  • @assylias -> you've hit the nail on the head. Banana really is a Fruit, but in our design, it's as if it's extended another Fruit instead - it should have been tacked on higher up in the hierarchy, not where it is. – jr. Feb 06 '13 at 02:17

1 Answers1

4

public String methodThatTakesFruitClassButNotBanana

This is exact opposite of Liskov Substitution Principle and how polymorphism works. Since Banana extends Fruit there is a requirement that any method that takes a Fruit accepts a Banana.

If you have to, you need to check dynamic type and throw exception, the compiler cannot do this for you.

Miserable Variable
  • 28,432
  • 15
  • 72
  • 133
  • I agree entirely. We have a unit test framework that takes Bananas (amongst other things that are not fruit), and I need to extend it to work with Lemons, Oranges, Apples etc. Bananas in this framework are handled different to other fruit. The problem with the design is the inherent problem that in reality it's more like Banana extends Lemon. The Banana has been tacked on far too low in the hierarchy. However, this is not something I can change, so I'll have to go with the hard (runtime) failure. Thanks a lot. :) – jr. Feb 06 '13 at 02:15