抽象类和接口用法 Is-a 关系 vs Has-a 功能

何时使用抽象类:在多个相关对象之间实现相同或不同的行为

何时使用接口:通过多个不相关的对象实现合同

抽象类创建是一种关系,而接口提供具有能力。

这可以在下面的代码中看到:

public class InterfaceAndAbstractClassDemo{
    public static void main(String args[]){
        
        Dog dog = new Dog("Jack",16);
        Cat cat = new Cat("Joe",20);
            
        System.out.println("Dog:"+dog);
        System.out.println("Cat:"+cat);
        
        dog.remember();
        dog.protectOwner();
        Learn dl = dog;
        dl.learn();
                
        cat.remember();
        cat.protectOwner();
        
        Climb c = cat;
        c.climb();
        
        Man man = new Man("Ravindra",40);
        System.out.println(man);
        
        Climb cm = man;
        cm.climb();
        Think t = man;
        t.think();
        Learn l = man;
        l.learn();
        Apply a = man;
        a.apply();
    }
}

abstract class Animal{
    String name;
    int lifeExpentency;
    public Animal(String name,int lifeExpentency ){
        this.name = name;
        this.lifeExpentency=lifeExpentency;
    }
    public abstract void remember();
    public abstract void protectOwner();
    
    public String toString(){
        return this.getClass().getSimpleName()+":"+name+":"+lifeExpentency;
    }
}
class Dog extends Animal implements Learn{
    
    public Dog(String name,int age){
        super(name,age);
    }
    public void remember(){
        System.out.println(this.getClass().getSimpleName()+" can remember for 5 minutes");
    }
    public void protectOwner(){
        System.out.println(this.getClass().getSimpleName()+ " will protect owner");
    }
    public void learn(){
        System.out.println(this.getClass().getSimpleName()+ " can learn:");
    }
}
class Cat extends Animal implements Climb {
    public Cat(String name,int age){
        super(name,age);
    }
    public void remember(){
        System.out.println(this.getClass().getSimpleName() + " can remember for 16 hours");
    }
    public void protectOwner(){
        System.out.println(this.getClass().getSimpleName()+ " won't protect owner");
    }
    public void climb(){
        System.out.println(this.getClass().getSimpleName()+ " can climb");
    }
}
interface Climb{
    void climb();
}
interface Think {
    void think();
}

interface Learn {
    void learn();
}
interface Apply{
    void apply();
}

class Man implements Think,Learn,Apply,Climb{
    String name;
    int age;

    public Man(String name,int age){
        this.name = name;
        this.age = age;
    }
    public void think(){
        System.out.println("I can think:"+this.getClass().getSimpleName());
    }
    public void learn(){
        System.out.println("I can learn:"+this.getClass().getSimpleName());
    }
    public void apply(){
        System.out.println("I can apply:"+this.getClass().getSimpleName());
    }
    public void climb(){
        System.out.println("I can climb:"+this.getClass().getSimpleName());
    }
    public String toString(){
        return "Man :"+name+":Age:"+age;
    }
}

输出:

Dog:Dog:Jack:16
Cat:Cat:Joe:20
Dog can remember for 5 minutes
Dog will protect owner
Dog can learn:
Cat can remember for 16 hours
Cat won't protect owner
Cat can climb
Man :Ravindra:Age:40
I can climb:Man
I can think:Man
I can learn:Man
I can apply:Man

主要说明:

  1. Animal 是一个具有共享属性的抽象类:namelifeExpectancy 以及抽象方法:remember()protectOwner()DogCatAnimals,已经实现了 remember()protectOwner() 方法。

  2. Cat 可以 climb()Dog 不能。Dog 可以 think() 但是 Cat 不能。通过实现将这些特定功能添加到 CatDog

  3. Man 不是 Animal 但他可以 ThinkLearnApplyClimb

  4. Cat 不是 Man 但它可以 Climb

  5. Dog 不是 Man 但它可以 Learn

  6. Man 既不是 Cat 也不是 Dog 但是可以​​拥有后两者的一些能力而不延伸 AnimalCatDog。这是通过接口完成的。

  7. 即使 Animal 是一个抽象类,它也有一个构造函数,与接口不同。

TL; DR:

不相关的类可以通过接口具有功能,但相关的类通过扩展基类来改变行为。

请参阅 Java 文档页面以了解在特定用例中使用哪一个。

**** 如果…… 考虑使用抽象类

  1. 你希望在几个密切相关的类之间共享代码。
  2. 你希望扩展抽象类的类具有许多常用方法或字段,或者需要除公共之外的访问修饰符(例如 protected 和 private)。
  3. 你想声明非静态或非最终字段。

**考虑使用接口,**如果……

  1. 你希望不相关的类将实现你的接口。例如,许多不相关的对象可以实现 Serializable 接口。
  2. 你希望指定特定数据类型的行为,但不关心谁实现其行为。
  3. 你希望利用类型的多重继承。