抽象类
抽象类的意义何在?
表面上看抽象类就是其中的抽象方法 不写方法体 只写一个方法声明:
public abstract void eat();
这个eat方法 在基类中是一个抽象概念 不知道动物要吃什么 动物是一个总体概念
所以继承它的子类必须实现这个方法 把抽象变为具体
public abstract class Animal {@Setter@Getterprivate String name = "动物";@Setter@Getterprivate int age;@Setter@Getterprivate String color;public void show(){System.out.println("这是一个动物");}public abstract void eat();
}
那么这里引申出几个问题:
- 你会发现抽象类中是可以有其他非抽象的东西的 比如一般的属性 方法等等
- 如果出现抽象方法 那么它的类必须也带上 abstract 这是一个死规则
- 抽象类是不能实例化 不能创建对象的 比如你这样写
Animal a = new Animal();
是会报错的,原因也很简单 因为它里面可能有抽象方法 抽象方法里面什么都没有 就一个声明 无法被调用 因为java不允许你直接实例化抽象类
最后回到最初的问题 抽象类的意义在哪里呢? 好像你不写抽象方法eat ,继承动物的猫狗类中 也照样可以写各自的eat方法
比较官方的回答是:
提供了一种约束和规范:抽象类可以定义一些方法的签名但不提供具体的实现,这些方法留给子类去实现。这样一来,子类必须实现这些抽象方法,从而使得子类在设计和实现时具有一定的规范和约束,确保了程序的结构和行为的一致性。实现了代码复用和继承:通过继承抽象类,子类可以继承抽象类中定义的方法和属性,从而实现了代码的复用。这种继承机制使得子类可以在基类的基础上进行扩展和定制,同时避免了重复编写相似的代码。面向抽象编程:抽象类可以被视为一种抽象的概念,它定义了一个通用的模板或接口,而不涉及具体的实现细节。这样一来,程序员可以针对抽象类编程,而不需要关心具体的子类实现细节,从而提高了代码的灵活性和可维护性。实现了多态性:由于抽象类可以被子类继承并实现其抽象方法,因此可以通过父类类型引用指向子类对象,从而实现多态性。这种多态性使得代码更加灵活,能够在运行时根据对象的实际类型来调用相应的方法,从而实现了更加动态和可扩展的程序设计。
接口
接口的概念很简单,很抽象类很相似 为了照顾新手 也写一个例子:
// 定义一个接口
interface Animal {void makeSound(); // 接口中的方法只有方法签名,没有方法体
}// 实现接口的类
class Dog implements Animal {@Overridepublic void makeSound() {System.out.println("Dog barks");}
}class Cat implements Animal {@Overridepublic void makeSound() {System.out.println("Cat meows");}
}public class Main {public static void main(String[] args) {Animal dog = new Dog(); // 通过接口类型引用指向实现类的对象Animal cat = new Cat(); // 同上dog.makeSound(); // 调用接口中定义的方法cat.makeSound(); // 同上}
}
这里注意:
- 我们之前讲多态的时候 说个继承关系可以多态 子类对象指向父类引用,这里发现接口也可以多态!
- 接口是行为规则定义 所以它里面没有 成员属性 比如动物的 name age type, 只能有常量!final修饰 意味着不能改
- 接口中没有构造方法! 因为接口是行为规则的定义 而不是某个对象的定义
正确的理解区分抽象类和接口
这部分才是重点,新手往往都会疑惑一个事情 抽象类和接口有什么区别? 好像看着差不多
这里有一个重要的理解: 抽象类是定义的抽象, 而接口是行为的抽象。
怎么理解呢?
比如基类动物 继承类 猫 狗 牛 鸟
这时候出现一个吃eat方法, 这时候应该用抽象类还是接口???
答案是抽象类 因为吃是动物的一个基础属性 是个动物都会吃 不存在 不吃东西的动物,所以它放入抽象类中
如果出现一个飞fly方法, 这时候应该用哪个
答案是接口 因为飞是不是一个基础属性 而是一个选择性的行为 有的动物会飞 有的动物不会飞 那么会飞的动物就实现飞的接口就可以了