Is there a way to guarantee an interface extends a class in Java?

前端 未结 6 1964
你的背包
你的背包 2020-12-28 13:38

Suppose I have the following situation:

public abstract class Vehicle {
  public void turnOn() { ... }
}

public interface Flier {
  public void fly();
}


        
相关标签:
6条回答
  • 2020-12-28 14:16

    You could rearrange your classes and interfaces like this:

    public interface IVehicle {
      public void turnOn();
    }
    
    public abstract class Vehicle implements IVehicle {
      public void turnOn() { ... }
    }
    
    public interface Flier extends IVehicle {
      public void fly();
    }
    

    This way all implementations of Flier are guaranteed to implement the protocol of a vehicle, namely IVehicle.

    0 讨论(0)
  • 2020-12-28 14:17

    It's a strange requirement, but you can accomplish something of the sort with Generics:

    <T extends MyInterface & MyAbstractClass>
    
    0 讨论(0)
  • 2020-12-28 14:23

    This question shows that you haven't grasped the essence of interface and class. Forgetting the concrete Java syntax right now, all you need to understand first is that: interface is a set of protocol, which should be implementation-agnostic. It makes no sense to let an interface extend a class(which is implementation-oriented).

    Back to your concrete question, if you want to guarantee that a Flier is always a kind of Vehicle, just change the latter to an interface and let former extends it(It does make sense to extend one protocol from the other protocol). After that, you may create any class(abstract or concrete) that implements Vehicle or Flier.

    0 讨论(0)
  • 2020-12-28 14:25

    Java interfaces cannot extend classes, which makes sense since classes contain implementation details that cannot be specified within an interface..

    The proper way to deal with this problem is to separate interface from implementation completely by turning Vehicle into an interface as well. The Car e.t.c. can extend the Vehicle interface to force the programmer to implement the corresponding methods. If you want to share code among all Vehicle instances, then you can use a (possibly abstract) class as a parent for any classes that need to implement that interface.

    0 讨论(0)
  • 2020-12-28 14:27

    If you have control on the Vehicle classes just extract Vehicle as an interface and then provide a base implementation.

    If you have no control over Vehicle class, for example because it is part of a framework you are using or a third party library, it's not possible to do in Java.

    The closest thing you can do is using Generics multiple wildcards notation.

    <T extends Vehicle & Car>
    

    But you can't really apply it directly to Car unless you do something like this:

    public interface Car<T extends Vehicle & Car>() {
        T self();
    }
    

    Which is bot weird and do not enforce the self method to actually return self, it's just a strong hint/suggestion.

    You would implement a Car like this:

    public class CitroenC3 extends Vehicle implements Car<CitroenC3> {
        @Override
        public CitroenC3 self() {
            return this;
        }
    }
    

    one can use a Car<?> like this:

    Car<?> car = obtainCarInSomeWay();
    Vehicle v = car.self();
    Car c = car.self();
    

    they should be both valid syntax.

    What the compiler enforce here is that what you specify in Car<WHICH> as WHICH must both extend Vehicle and implement Car. And by adding self() you are saying to the programmer that the T object is supposed to be the object itself, thus forcing the wildcard instance to match the class if he want to be compliant with the specification.

    in Java 8 you can even define a default implementation for the self method.

    I also wish there was a better way to handle something like this.

    0 讨论(0)
  • 2020-12-28 14:30
    1. Define a new Package
    2. Create a new interface (ie. HiddenOne) with scope "default" with a method "implementMe(HiddenOne)"
    3. Move Vehicle and Flier to the new Package.
    4. Inherit Vehicle and Flier from HiddenOne
    5. Implement the method implementMe in Vehicle.

    Now: Whenever you like to implement from "Flier" you must extends from Vehicle ! (because only Vehicle can implement implementMe).

    This is tricky but works great.

    0 讨论(0)
提交回复
热议问题