JavaSE 基础语法 - 抽象类 📅 发布时间:2026/8/31 6:11:01 👁 浏览次数: 在前面的学习中继承和多态是面向对象编程非常重要的基础。例如classAnimal{publicvoideat(){System.out.println(动物吃东西);}}classDogextendsAnimal{Overridepublicvoideat(){System.out.println(狗吃狗粮);}}classCatextendsAnimal{Overridepublicvoideat(){System.out.println(猫吃猫粮);}}使用多态后Animala1newDog();Animala2newCat();a1.eat();a2.eat();输出狗吃狗粮 猫吃猫粮我们已经能够通过父类统一管理不同的子类。但是这里仍然存在一个问题AnimalanimalnewAnimal();从语法上来说这个对象是可以创建的。可是现实中我们很难描述一个具体的“动物”到底应该怎么执行某些行为。例如animal.eat();到底应该吃什么狗吃狗粮猫吃猫粮鸟可能吃虫子因此Animal 更像是一个抽象概念而不是一个具体对象。这时候我们就可以把它定义成abstractclassAnimal{}这就是抽象类。1、为什么需要抽象类1.1 普通父类存在的问题假设我们有classAnimal{publicvoideat(){System.out.println(动物吃东西);}publicvoidmove(){System.out.println(动物移动);}}然后classDogextendsAnimal{Overridepublicvoideat(){System.out.println(狗吃狗粮);}}虽然可以实现继承和多态但是仍然可以 new 创建 Animal 对象。问题是 Animal 本身只是一个抽象概念。2、抽象类的概念Java 提供了抽象类来解决这个问题。语法abstractclass类名{}例如abstractclassAnimal{}此时AnimalanimalnewAnimal();这样就会直接编译错误因为抽象类不能直接创建对象。但是它仍然可以作为父类classDogextendsAnimal{}所以抽象类的核心作用可以理解成抽象类主要用于作为父类为子类提供共同成员同时规定子类必须完成某些行为。3、abstract 关键字abstract是 Java 中用于定义抽象类和抽象方法的关键字。主要有两种使用方式abstractclassAnimal{}以及abstractvoideat();前者表示抽象类后者表示抽象方法4、抽象方法4.1 什么是抽象方法抽象方法是一种只有方法声明没有方法体的方法。例如abstractclassAnimal{publicabstractvoideat();}注意publicabstractvoideat();后面没有{...}而是直接;所以这个方法是抽象方法。4.2 为什么需要抽象方法假设classAnimal{publicvoideat(){System.out.println(动物吃东西);}}这里存在一个问题父类无法确定所有子类到底应该怎么吃。例如Dog-吃狗粮Cat-吃猫粮Bird-吃虫子Fish-吃鱼食因此父类与其随便写一个publicvoideat(){System.out.println(动物吃东西);}不如直接规定publicabstractvoideat();意思就是所有动物都必须拥有 eat() 方法但是具体怎么吃由子类自己决定。5、抽象类和抽象方法的关系一个非常重要的规则只要一个类中存在抽象方法那么这个类必须声明为抽象类。例如abstractclassAnimal{publicabstractvoideat();}这是正确的。但是classAnimal{publicabstractvoideat();}这是错误的因为普通类不能直接包含抽象方法。5.1 抽象类可以没有抽象方法反过来抽象类中不一定必须存在抽象方法。例如abstractclassAnimal{publicvoideat(){System.out.println(动物吃东西);}}这个类没有抽象方法但是仍然可以定义为抽象类。因为abstract还可以表达另外一种设计意图这个类本身不应该被直接实例化只应该作为父类使用。6、抽象类的特性抽象类主要有以下特性。①、不能直接实例化对象abstractclassAnimal{}不能AnimalanewAnimal();否则编译报错。②、抽象方法不能是 private修饰的abstractclassAnimal{abstractprivatevoideat();}否则编译报错。③、抽象方法不能被final和static修饰因为抽象方法要被子类重写abstractclassAnimal{abstractfinalvoideat();abstractpublicstaticvoidsleep();}否则编译报错。④、抽象类必须被继承并且继承后子类要重写父类中的抽象方法否则子类也是抽象类必须要使用 abstract 修饰⑤、抽象类中不一定包含抽象方法但是有抽象方法的类一定是抽象类⑥、抽象类中可以有构造方法供子类创建对象时初始化父类的成员变量7、抽象类的完整案例abstractclassAnimal{privateStringname;publicAnimal(Stringname){this.namename;}publicvoidsleep(){System.out.println(name正在睡觉);}publicabstractvoideat();}子类classDogextendsAnimal{publicDog(Stringname){super(name);}Overridepublicvoideat(){System.out.println(狗吃狗粮);}}再定义classCatextendsAnimal{publicCat(Stringname){super(name);}Overridepublicvoideat(){System.out.println(猫吃猫粮);}}使用DogdognewDog(旺财);dog.eat();dog.sleep();CatcatnewCat(咪咪);cat.eat();cat.sleep();输出狗吃狗粮 旺财正在睡觉 猫吃猫粮 咪咪正在睡觉8、子类继承抽象类后的规则如果一个普通子类继承了抽象类那么子类必须重写父类中的所有抽象方法。例如abstractclassAnimal{publicabstractvoideat();publicabstractvoidmove();}子类classDogextendsAnimal{Overridepublicvoideat(){System.out.println(狗吃狗粮);}Overridepublicvoidmove(){System.out.println(狗跑步);}}必须实现eat()move()如果只实现其中一个那么会产生编译错误。9、子类也可以是抽象类如果子类不想实现所有抽象方法那么子类自己也可以继续定义成抽象类。例如abstractclassAnimal{publicabstractvoideat();publicabstractvoidmove();}定义abstractclassDogextendsAnimal{Overridepublicvoideat(){System.out.println(狗吃狗粮);}}此时 Dog 没有实现move()但是它本身也是抽象类所以没有问题。然后继续classHuskyextendsDog{Overridepublicvoidmove(){System.out.println(哈士奇奔跑);}}10、抽象类中的构造方法这是初学者非常容易产生疑惑的地方。我们知道抽象类不能创建对象那么为什么还需要构造方法例如abstractclassAnimal{publicAnimal(){System.out.println(Animal 构造方法);}}虽然newAnimal();不允许。但是classDogextendsAnimal{publicDog(){super();System.out.println(Dog 构造方法);}}是允许的。创建DogdognewDog();执行过程Dog构造方法-super()-Animal构造方法-Dog构造方法继续执行输出Animal构造方法Dog构造方法所以抽象类虽然不能直接创建对象但是它的构造方法会在创建子类对象时参与父类初始化。11、抽象类与多态抽象类非常适合与多态结合使用。例如abstractclassAnimal{publicabstractvoideat();}子类classDogextendsAnimal{Overridepublicvoideat(){System.out.println(狗吃狗粮);}}然后AnimalanimalnewDog();虽然 Animal 是抽象类不能直接 new Animal();但是仍然可以作为引用类型AnimalanimalnewDog();然后 animal.eat(); 执行的是 Dog.eat()这就是抽象类 多态。12、抽象类的核心作用我们可以把抽象类总结成一句话抽象类用于提取子类的共同属性和共同行为同时通过抽象方法强制子类实现特定行为。例如abstractclassAnimal{Stringname;publicvoidsleep(){System.out.println(睡觉);}publicabstractvoideat();}其中namesleep()属于所有子类共同拥有的内容。而 eat() 属于所有子类都必须有但具体实现不同的内容。