2

Suppose I have a class that extends another class and implements one or more interfaces. How can I specify a type that requires such condition?

For example:

class Eagle extends Animal implements Fly {
}

class Falcon extends Animal implements Fly {
}


public static void main (){
    ??? anAnimalWhoCanFly; 
}

Update: I removed the list. Just suppose I want to have an object that is an object of a class that extends Animal and implements Fly.

Thanks

Mohammad Roohitavaf
  • 439
  • 2
  • 6
  • 15
  • possible duplicate of https://stackoverflow.com/questions/745756/java-generics-wildcarding-with-multiple-classes – Evgeny Tanhilevich Sep 28 '17 at 01:20
  • Sorry, if it not clear for you. See, I want a type that specifies any object of this type is an object of a class that extends this class and implements that interface. I hope this helps. – Mohammad Roohitavaf Sep 28 '17 at 01:20
  • @EvgenyTanhilevich, It is not duplicate. I don't want to define a new class. I am looking for a way to set the type for an object that is an object of a class that extends Animal and implements Fly. I hope it helps clear my problem for you. Thanks – Mohammad Roohitavaf Sep 28 '17 at 01:24
  • @MohammadRoohitavaf, one of the answers to the question that I am referring to states that it is not possible to define wildcards that extend multiple classes/interfaces. So looks like there is no way around defining a new class somehow, seems to be a Java language limitation. – Evgeny Tanhilevich Sep 28 '17 at 01:28

2 Answers2

2

If you want a way to specify, say, "a type that extends Animal and implements Fly", just define a class that does exactly that:

public abstract class FlyingAnimal extends Animal implements Fly{ }

Now you have Eagle and Falcon extend from FlyingAnimal rather directly from Animal:

public class Falcon extends FlyingAnimal {
    public void fly(){ System.out.println("I'm a fast flier");
}

public class Eagle extends FlyingAnimal {
    public void fly(){ System.out.println("I'm built for soaring");
}

public class Cat extends Animal {
    // I'm a cat; I can't fly
}

Now you can do something like this:

public void flyIt(FlyingAnimal fa){
    fa.fly();
}

public void test(){
    Falcon falcon = new Falcon();
    Animal eagle = new Eagle();
    Animal cat = new Cat();

    flyIt(falcon);    // OK: `Falcon` is a `Falcon`, which is also 
                      //   a `FlyingAnimal`
    flyIt(cat);       // COMPILE ERROR: `cat` is an `Animal`,
                      //   which is not a subclass of `FlyingAnimal`
    flyIt(eagle);     // COMPILE ERROR: `eagle` is an `Animal`, which is 
                      //  not a `FlyingAnimal`
    flyIt((Eagle)eagle);
                      // OK: because we know that `eagle` actually references
                      //   an `Eagle`, we know the type-cast `(Eagle)eagle` 
                      //   will succeed at run-time; `Eagle` is a `FlyingAnimal`
                      //   and thus is acceptable as an argument to `flyIt`
    flytIt((FlyingAnimal)eagle);
                      // OK: because we know that `eagle` actually references 
                      //   an `Eagle`, which in turn is a `FlyingAnimal`, we 
                      //   know the type-cast `(FlyingAnimal)eagle` will 
                      //   succeed at run-time
    flyIt((FlyingAnimal)cat);
                      // RUN-TIME ERROR: `cat` references a `Cat`, which is 
                      //   an `Animal` but not a `FlyingAnimal`, and so will
                      //   not successfully convert to a `FlyingAnimal` at
                      //   run-time.
Kevin Anderson
  • 4,568
  • 3
  • 13
  • 21
0

It is sad that we cannot do it in java, if @EvgenyTanhilevich is right.

I found something that somehow does what I want. It is not exactly what I wanted, because it does not require that object MUST be an instance of class that implements Fly, but still let me call fly function:

public class Main  {

    public static void main(String[] args) {

        Eagle eagle = new Eagle(); 
        ((Fly)eagle).fly();

    }

}
Mohammad Roohitavaf
  • 439
  • 2
  • 6
  • 15
  • Of course the object MUST be an instance of a class that implements `Fly`! What do you suppose would happen here if if you declared `eagle` as `Animal eagle = new Animal();`? – Kevin Anderson Sep 28 '17 at 02:34
  • Yes, you are right. But I wanted to force that condition. Imagine that I have a function. I want to force object you pass to have this specification, and if not I want to get compile error. – Mohammad Roohitavaf Sep 28 '17 at 02:39
  • Then you need a single type that has the functionality of both an `Animal` and `Fly`. See my answer, coming shortly... – Kevin Anderson Sep 28 '17 at 02:55
  • @KevinAnderson Thanks :) What if it is someone else's code? Actually, I am working with Google protocol buffer, and I don't have control over the code it generates for me. – Mohammad Roohitavaf Sep 28 '17 at 03:02
  • It's not a compile-time error to type-cast an object reference to another reference type (Java Lang Spec [§15.16](https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.16)). Even if the cast is obviously destined to fail, the compiler must allow it and let it fail at run-time. – Kevin Anderson Sep 28 '17 at 04:05
  • That's why I said this solution does not solve my problem completely! I was looking for one that cause compile error – Mohammad Roohitavaf Sep 28 '17 at 04:25
  • Kevin in his answer above has provided a solution. Animal Behaviour and flying ability are two different attribute. An entity can be an Animal but may or may not have flying ability. To have something which is an Animal and also has flying ability, you need to create such an entity explicitly. This is what Kevin has done `FlyingAnimal`. Now to force both the behaviours you can use `FlyingAnimal` as a type. – nits.kk Sep 29 '17 at 12:06
  • How can I write FlyingAnimal class if classes Animal and Interface Flying is written by someone else? As I said, I am working with Google Protocol Buffer. It has a class that extend another class and implements an interface. I am writing a library that needs to deal with objects of such class. How can I refer to those objects? – Mohammad Roohitavaf Sep 29 '17 at 17:49