An abstract class

If we have only one abstract class like Instrument, then the objects of that class make little sense. We create abstract classes in the hope of manipulating a series of classes through this generic interface. Therefore, an Instrument represents only an interface. There is no implementation content. Creating an Instrument object makes little sense, and we might want to prevent users from doing so by making all parties in the Instrument produce errors. But doing so delays error information until runtime and requires reliable, exhaustive testing on the client side, so it’s best to catch these problems at compile time.

To this end, Java provides a mechanism called abstract method, this method is not complete, only statement without method body, if you don’t complete an abstract class, so when we try to produce the class object, due to the abstract class unsafe when creating objects, so we will get an error message from the compiler.

interface

The interface keyword takes abstraction a step further. An interface says, “All classes that implement that particular interface look like this,” so any code that uses a particular interface knows which methods of that interface can be called, and only needs to know that. Interfaces are used to establish protocols between classes.

  • Methods in interfaces are public by default, because protocols need to be exposed.
  • The fields in an interface are static by default. In a multi-interface implementation scenario, you can distinguish which interface the same domain belongs to.
  • Interface in the domain of the default are final, if the domain can be modified, then there is no inheritance significance, interface protocol, is another Angle: because he is so a static the domain can have only one instance of the interface, so need to use it only at the interface first initialized, for realizing the significance of class object without any modification.
  • Because of the enumeration enum, the use of interfaces to describe domains is obsolete.

Multiple inheritance

An interface is more than just a purer form of abstract class, its goal is much higher than that, because there is no concrete implementation of an interface at all, and there is no storage associated with the interface, thus preventing multiple interfaces from being composed.

In derived classes, it is not mandatory to have an abstract or concrete base class. If you want to inherit from a non-interface class, you can only inherit from one class. The rest of the base elements must be interfaces. You can inherit as many interfaces as you want, and you can be upcast to each interface because each interface is a separate type.

interface CanFight { void fight(); } interface CanSwim { void swim(); } interface CanFly() { void fly(); } class ActionCharacter { public void fight() {} } class Hero extends ActionCharater implements CanFight, CanSwim, CanFly { public void swim() {} public void fly() {} } public class Adventure { public static void t(CanFight x) { x.fight(); } public static void u(CanSwim x) { x.swim(); } public static void v(CanFly x) { x.fly(); } public static void w(ActionCharacter x) { x.fight(); } public static void main(String[] args) { Hero h = new Hero(); t(h); u(h); v(h); w(h); }}Copy the code

Note that the signature of the CanFight interface is the same as that of the fight() method in the ActionCharater class, and there is no definition of fight() in Hero, which is derived from the ActionCharater, but the compiler will reject it if the two return value types are different.

Multiple inheritance is an important way to adapt existing library interfaces.

public interface Generator<T> { T next(); } public class Fibonacci implements Generator<Integer> { private int count = 0; public Integer next() { return fib(count++); } private int fib(int n) { if (n < 2) { return 1; } return fib(n-2) + fib(n-1); } } public class IterableFibonacci extends Fibonacci implements Iterable<Integer> { pirvate int n; public IterableFibonacci(int count) { n = count; } public Iterator<Integer> iterator() { return new Iterator<Integer>() { public boolean hasNext() { return n > 0; } public Integer next() { n--; return IterableFibonacci.this.next(); } public void remove() { throw new UnsupportedOperationException(); }}; } public static void main(String[] args) { for(int i : new IterableFibonacci(18) { System.out.print(i + " "); }}}Copy the code

This example assumes that Fibonacci is code that cannot be controlled or modified, and that iterator functionality can be implemented through multiple inheritance adaptation because Iterable is an interface.

The interface itself can have multiple inheritance.

interface Monster {
    void menace();
}
interface DangerousMonster extends Monster {
    void destroy();
}
interface Lethal {
    void kill();
}
interface Vampire extends DangerousMonster, Lethal {
    void drinkBlood();
}
Copy the code

Nested interface

Interfaces can be nested in classes or other interfaces.

  • The various rules that apply to interfaces, in particular that all interface elements must be public, so an interface nested in another interface is automatically public and cannot be declared private unless there happens to be an internal implementation class and public access to that private interface.
  • When you implement an interface, you do not need to implement any of the nested interfaces inside it. Nested interfaces are equivalent to internal member variables and do not need to be implemented.

Should we use interfaces or abstract classes? The proper rule is to choose classes over interfaces, starting with the class, and refactoring if it becomes clear that the interface is necessary.