抽象类
每一个技术的出现, 都是为了解决某一种问题的.
抽象类的出现, 就是为了让子类强制重写父类中的某一个方法.
父类的抽象方法在子类中必须重写, 否则子类代码直接报错.
抽象方法所在的类就叫做抽象类.
抽象类和抽象方法主要学习:
-
抽象类的定义格式.
-
抽象方法的定义格式.
-
子类继承抽象类之后, 如何重写抽象方法.
-
抽象类在实际开发中的意义所在.
将多个子类中的共的行为 (方法) 抽取到父类之后, 由于每一个子类的执行的内容是不一样的, 所以父类中不能确定具体的方法体, 则该方法可以被定义为抽象方法.
如果一个类里面存在抽象方法, 不管有多少个, 那么这个类就必须被定义为抽象类.
抽象方法是不写方法体的, 直接用分号结束, 连花括号都没有. 抽象方法的定义格式为: public abstract 返回值类型 方法名 (参数列表);
抽象类的定义格式为: public abstract class 类名 { 类体 }
程序示例:
public abstract class Person { public abstract void work(); }
抽象类不能实例化 (实例化即创建对象). 如果可以实例化, 则抽象类的对象可以调用抽象类的方法, 包括抽象方法, 而抽象方法没有方法体, 那么调用什么呢?由此就产生了矛盾, 因此规定抽象类不能实例化.
抽象类中不一定有抽象方法, 但是有抽象方法的类一定是抽象类.
抽象类可以有构造方法. 既然抽象类不能实例化, 那么抽象类的构造方法有何作用? 作用: 当其子类创建对象时, 可以给子类对象赋值. 子类的构造方法用 super 调用父类的构造方法. 抽象类的构造方法是给可以实例化的子类通过 super() 来使用的.
抽象类的子类要么重写抽象类的所有抽象方法, 要么子类本身也是一个抽象类. 如果子类还是抽象类, 那么这个子类还是不能实例化, 如果想创建对象, 那就要再定义 "孙子类", 且一定不是抽象类, 那么这个 "孙子类" 还是要重写全部的抽象方法. 所以一般都是采用第一种方法, 即在子类中重写全部的抽象方法.
也就是说, 一般情况下, 抽象类的子类不是抽象类.
程序示例:
public abstract class Person { // 是抽象类但是没有抽象方法 // public abstract void work(); public void sleep() { } }
public class Person { // 有抽象方法但不是抽象类, 则报错 public abstract void work(); public void sleep() { } }
public abstract class Person { // 带有构造方法的抽象类 String name; int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public abstract void work(); public void sleep() { } }
练习:
编写带有抽象类的标准 Javabean 类
青蛙 Frog: 属性: 名字, 年龄 行为: 吃虫子, 喝水
狗 Dog: 属性: 名字, 年龄 行为: 吃骨头, 喝水
山羊 Sheep: 属性: 名字, 年龄 行为: 吃草, 喝水
画出示意图:

Javabean 类:
public abstract class Animal { private String name; private int age; public Animal() { } public Animal(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void drink() { System.out.println(getName() + "在喝水. "); } public abstract void eat(); }
public class Dog extends Animal { public Dog() { } public Dog(String name, int age) { super(name, age); } @Override public void eat() { System.out.println("狗在吃骨头. "); } }
public class Frog extends Animal { public Frog() { } public Frog(String name, int age) { super(name, age); } @Override public void eat() { System.out.println("青蛙在吃虫子. "); } }
public class Sheep extends Animal { public Sheep() { } public Sheep(String name, int age) { super(name, age); } @Override public void eat() { System.out.println("羊在吃草. "); } }
测试类:
public class Test { public static void main(String[] args) { Frog f = new Frog("小绿", 1); System.out.println(f.getName() + ", " + f.getAge()); f.eat(); f.drink(); } }
执行结果:
小绿, 1 青蛙在吃虫子. 小绿在喝水.
在父类中定义抽象类, 在子类中又重写, 看起来是很麻烦, 因为在父类中多写了一个类, 但是这样做是有意义的, 因为假如有多个人去调用这个父类写了多个子类, 如果没有这个抽象类限制了子类中的这个类的书写形式, 那么不同的人所写的子类中的这个方法可能差别很大, 另外的人去调用时, 不知道该如何调用, 如果在父类中写了这个抽象类, 就相当于限定了这个类的形式, 调用时如果不知道如何调用, 只需要去父类中看看就知道了. 所以, 父类中定义抽象类有统一形式的意义.
抽象的子类的父类不一定是抽象的, 可能子类特有的方法是抽象方法.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术