当我们在做子类共性功能抽取时,有些方法在父类中并没有具体的体现,这个时候就需要抽象类了!
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类!
抽象类和抽象方法必须使用 abstract 关键字修饰
- //抽象类的定义
- public abstract class 类名 {}
-
- //抽象方法的定义
- public abstract void eat();
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
抽象类不能实例化
抽象类如何实例化呢?参照多态的方式,通过子类对象实例化,这叫抽象类多态
抽象类的子类
要么重写抽象类中的所有抽象方法
要么是抽象类
成员的特点
成员变量
既可以是变量
也可以是常量
构造方法
空参构造
有参构造
成员方法
抽象方法
普通方法
抽象类的成员特点
成员变量
构造方法
有构造方法,但是不能实例化
那么,构造方法的作用是什么呢?用于子类访问父类数据的初始化成员方法
成员方法
可以有抽象方法:限定子类必须完成某些动作
也可以有非抽象方法:提高代码复用性(由继承来实现)
代码演示
- package com.object_03;
- //抽象类
- public abstract class Animal1 {
- private int age = 20;
- private final String city = "北京";
-
- public Animal1() {}
-
- public Animal1(int age) {
- this.age = age;
- }
-
-
- public void show() {
- age = 40;
- System.out.println(age);
- System.out.println(city);
- }
-
- //抽象方法
- public abstract void eat();
- }
-
- package com.object_03;
-
- public class Cat1 extends Animal1{
- @Override
- public void eat() {
- System.out.println("猫咪吃鱼");
- }
- }
-
-
- package com.object_03;
- //抽象类
- public abstract class Animal1 {
- private int age = 20;
- private final String city = "北京";
-
- public Animal1() {}
-
- public Animal1(int age) {
- this.age = age;
- }
-
-
- public void show() {
- age = 40;
- System.out.println(age);
- System.out.println(city);
- }
-
- //抽象方法
- public abstract void eat();
- }
-

案例需求
请采用抽象类的思想实现猫和狗的案例,并在测试类中进行测试
思路:
1.定义动物类(Animal)
成员变量:姓名,年龄构造方法:无参,带参
成员方法: get/set方法,吃饭;
2.定义猫类(Cat),继承动物类
构造方法:无参,带参成员
方法:重写吃饭(){.….}
3.定义狗类(Dog),继承动物类
构造方法:无参,带参
成员方法:重写吃饭({.….}
4.定义测试类(AnimalDemo),写代码测试
代码实现
- package com.object_03;
- //抽象类的案例
- public abstract class Animal2 {
- private String name;
- private int age;
-
- public Animal2() {
- }
-
- public Animal2(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 abstract void eat();
- }
-
- package com.object_03;
-
- public class Dog2 extends Animal2 {
- public Dog2() {
- }
-
- public Dog2(String name, int age) {
- super(name, age);
- }
-
- @Override
- public void eat() {
- System.out.println("狗吃骨头");
- }
- }
-
-
-
- package com.object_03;
-
- public class Cat2 extends Animal2 {
- public Cat2() {
- }
-
- public Cat2(String name, int age) {
- super(name, age);
- }
-
- @Override
- public void eat() {
- System.out.println("猫吃鱼");
- }
- }
-
-
-
- package com.object_03;
-
- public class AnimalDemo2 {
- public static void main(String[] args) {
- //创建对象,按照多态的方式
- Animal2 a = new Cat2();
- a.setName("暹罗");
- a.setAge(6);
- System.out.println(a.getName()+","+a.getAge());
- a.eat();
- System.out.println("*****************");
-
- a =new Cat2("中华田园猫",5);
- System.out.println(a.getName()+","+a.getAge());
- a.eat();
- }
- }
-
-

1.5抽象类和接口的区别
门和警报的例子
门:都有open)和close()两个动作,这个时候,我们可以分别使用抽象类和接口来定义这个抽象概念
抽象类
- //抽象类
- public abstract class Door {
- public abstract void open ( ) ;
-
- public abstract void close ( ) ;
- public abstract void alarm ( ) ; //但是有的门没有报警功能
- }
接口
- //接口
- public interface Door {
- void open ( ) ;
- void close () ;
- void alarm(); //但是接入接口还会实现open和close
- }
- public interface Alram {void alarm () ;
- }
- public abstract class Door {
- public abstract void open ( ) ;public abstract void close ( );}
- public class AlarmDoor extends Door implements Alarm {
- public void oepn () {
- // ....
- }
- public void close (o) {l l ....
- }
- public void alarm () {
- // ....
- }
- }
这里我们将alarm单独作为接口来实现,需要的时候写入,各自独立开来就好
在这里,我们再次强调抽象类是对事物的抽象,而接口是对行为的抽象
接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。
Java中的接口更多的体现在对行为的抽象!
接口用关键字interface修饰
public interface 接口名 {} 类实现接口用implements表示(类和接口之间不能用继承,需要implements(实现)来连接)
public class 类名 implements 接口名 {} 接口不能实例化
接口如何实例化呢?参照多态的方式,通过实现类对象实例化,这叫接口多态。
- package com.itheima_o1;
- /*测试类*/
- public class JumppingDemo i
- public static void main( String[] args) {
- //Jumpping j = new Jumpping(); //失败了,接口不能实例化
-
- //接口如何实例化呢?参照多态的方式,通过实现类对象实例化,这叫接口多态
- Jumpping j = new Cat();
- j.jump();
- }
- }
多态的形式:具体类多态,抽象类多态,接口多态。
多态的前提:有继承或者实现关系;有方法重写;有父(类/接口)引用指向(子/实现)类对象
接口的实现类
要么重写接口中的所有抽象方法
要么子类也是抽象类
成员特点
成员变量
只能是常量 默认修饰符:public static final
构造方法
接口没有构造方法,因为接口主要是对行为进行抽象的,是没有具体存在
一个类如果没有父类,默认继承自Object类
成员方法
只能是抽象方法
默认修饰符:public abstract
关于接口中的方法,JDK8和JDK9中有一些新特性,后面再讲解
代码演示
- public interface Inter {
- public int num = 10; //有成员变量
- public final int num2 = 20; //可以是个常量
- // public static final int num3 = 30;
- int num3 = 30;
-
- // public Inter() {}
-
- // public void show() {} //接口为抽象方法,不能有方法体{}
-
- public abstract void method();
- void show();
- }
- public class InterImpl extends Object implements Inter { //接口实现类命名,类名+Impl
- public InterImpl() {
- super();
- }
-
- @Override
- public void method() {
- System.out.println("method");
- }
-
- @Override
- public void show() {
- System.out.println("show");
- }
- }
- public class InterfaceDemo {
- public static void main(String[] args) {
- Inter i = new InterImpl(); //通过创建对象
- // i.num = 20;
- System.out.println(i.num);
- // i.num2 = 40;
- System.out.println(i.num2);
- System.out.println(Inter.num);
- }
- }
接口
实现类
测试类
案例需求
对猫和狗进行训练,他们就可以跳高了,这里加入跳高功能。
请采用抽象类和接口来实现猫狗案例,并在测试类中进行测试。
代码实现
动物类
- package com.object_04.interface_01;
-
- 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 abstract void eat();
-
-
- public void setAge(int age) {
- this.age = age;
- }
-
-
- public abstract void eat();
- }
-
-
跳高接口
- package com.object_04.interface_01;
- //跳高接口
- public interface Jumpping {
- public abstract void jump();
- }
猫类
- package com.object_04.interface_01;
-
- public class Cat extends Animal implements Jumpping {
- public Cat() {
- }
-
- public Cat(String name, int age) {
- super(name, age);
- }
-
-
- @Override
- public void eat() {
- System.out.println("猫吃鱼");
- }
-
-
- @Override
- public void jump() {
- System.out.println("猫可以跳高了");
- }
- }
测试类
- package com.object_04.interface_01;
-
- public class AnimalDemo {
- public static void main(String[] args) {
- //创建对象,调用方法
- Jumpping j = new Cat();
- j.jump();
- System.out.println("--------");
-
- Animal a = new Cat();
- a.setName("加菲");
- a.setAge(5);
- System.out.println(a.getName()+","+a.getAge());
- a.eat();
- // a.jump();
-
- a = new Cat("加菲",5);
- System.out.println(a.getName()+","+a.getAge());
- a.eat();
- System.out.println("--------");
-
- Cat c = new Cat();
- c.setName("加菲");
- c.setAge(5);
- System.out.println(c.getName()+","+c.getAge());
- c.eat();
- c.jump();
- }
- }
- package com.object_04.interface_01;
-
结果:
- 猫可以跳高了
- --------
- 加菲,5
- 猫吃鱼
- 加菲,5
- 猫吃鱼
- --------
- 加菲,5
- 猫吃鱼
- 猫可以跳高了
类与类的关系
继承关系,只能单继承,但是可以多层继承
类与接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
接口与接口的关系
继承关系,可以单继承,也可以多继承
成员区别
抽象类
变量,常量;有构造方法;有抽象方法,也有非抽象方法
接口
常量;抽象方法
关系区别
类与类
继承,单继承
类与接口
实现,可以单实现,也可以多实现
接口与接口
继承,单继承,多继承
设计理念区别
抽象类
对类抽象,包括属性、行为
接口
对行为抽象,主要是行为
我们现在有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。
为了出国交流,跟乒乓球相关的人员都需要学习英语。
请用所学知识分析,这个案例中有哪些具体类,哪些抽象类,哪些接口,并用代码实现。
抽象人类
- public abstract class Person {
- private String name;
- private int age;
-
- public Person() {
- }
-
- public Person(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 abstract void eat();
- }
抽象运动员类
- public abstract class Player extends Person {
- public Player() {
- }
-
- public Player(String name, int age) {
- super(name, age);
- }
-
- public abstract void study();
- }
抽象教练类
- public abstract class Coach extends Person {
- public Coach() {
- }
-
- public Coach(String name, int age) {
- super(name, age);
- }
-
- public abstract void teach();
- }
学英语接口
- public interface SpeakEnglish {
- public abstract void speak();
- }
蓝球教练
- public class BasketballCoach extends Coach {
- public BasketballCoach() {
- }
-
- public BasketballCoach(String name, int age) {
- super(name, age);
- }
-
- @Override
- public void teach() {
- System.out.println("篮球教练教如何运球和投篮");
- }
-
- @Override
- public void eat() {
- System.out.println("篮球教练吃羊肉,喝羊奶");
- }
- }
乒乓球教练
- public class PingPangCoach extends Coach implements SpeakEnglish {
-
- public PingPangCoach() {
- }
-
- public PingPangCoach(String name, int age) {
- super(name, age);
- }
-
- @Override
- public void teach() {
- System.out.println("乒乓球教练教如何发球和接球");
- }
-
- @Override
- public void eat() {
- System.out.println("乒乓球教练吃小白菜,喝大米粥");
- }
-
- @Override
- public void speak() {
- System.out.println("乒乓球教练说英语");
- }
- }
乒乓球运动员
- public class PingPangPlayer extends Player implements SpeakEnglish {
-
- public PingPangPlayer() {
- }
-
- public PingPangPlayer(String name, int age) {
- super(name, age);
- }
-
- @Override
- public void study() {
- System.out.println("乒乓球运动员学习如何发球和接球");
- }
-
- @Override
- public void eat() {
- System.out.println("乒乓球运动员吃大白菜,喝小米粥");
- }
-
- @Override
- public void speak() {
- System.out.println("乒乓球运动员说英语");
- }
- }
篮球运动员
- public class BasketballPlayer extends Player {
-
- public BasketballPlayer() {
- }
-
- public BasketballPlayer(String name, int age) {
- super(name, age);
- }
-
- @Override
- public void study() {
- System.out.println("篮球运动员学习如何运球和投篮");
- }
-
- @Override
- public void eat() {
- System.out.println("篮球运动员吃牛肉,喝牛奶");
- }
- }
1、类名作为方法的形参
方法的形参是类名,其实需要的是该类的对象
实际传递的是该对象的【地址值】
2、类名作为方法的返回值
方法的返回值是类名,其实返回的是该类的对象
实际传递的,也是该对象的【地址值】
示例代码:
- class Cat {
- public void eat() {
- System.out.println("猫吃鱼");
- }
- }
- class CatOperator {
- public void useCat(Cat c) { //Cat c = new Cat();
- c.eat();
- }
- public Cat getCat() {
- Cat c = new Cat();
- return c;
- }
- }
- public class CatDemo {
- public static void main(String[] args) {
- //创建操作类对象,并调用方法
- CatOperator co = new CatOperator();
- Cat c = new Cat();
- co.useCat(c);
-
- Cat c2 = co.getCat(); //new Cat()
- c2.eat();
- }
- }
抽象类作为形参和返回值
方法的形参是抽象类名,其实需要的是该抽象类的子类对象
方法的返回值是抽象类名,其实返回的是该抽象类的子类对象
示例代码:
- abstract class Animal {
- public abstract void eat();
- }
- class Cat extends Animal {
- @Override
- public void eat() {
- System.out.println("猫吃鱼");
- }
- }
- class AnimalOperator {
- public void useAnimal(Animal a) { //Animal a = new Cat();
- a.eat();
- }
- public Animal getAnimal() {
- Animal a = new Cat();
- return a;
- }
- }
- public class AnimalDemo {
- public static void main(String[] args) {
- //创建操作类对象,并调用方法
- AnimalOperator ao = new AnimalOperator();
- Animal a = new Cat();
- ao.useAnimal(a);
-
- Animal a2 = ao.getAnimal(); //new Cat()
- a2.eat();
- }
- }
接口作为形参和返回值
方法的形参是接口名,其实需要的是该接口的实现类对象
方法的返回值是接口名,其实返回的是该接口的实现类对象
示例代码:
- interface Jumpping {
- void jump();
- }
- class JumppingOperator {
- public void useJumpping(Jumpping j) { //Jumpping j = new Cat();
- j.jump();
- }
- public Jumpping getJumpping() {
- Jumpping j = new Cat();
- return j;
- }
- }
- class Cat implements Jumpping {
- @Override
- public void jump() {
- System.out.println("猫可以跳高了");
- }
- }
- public class JumppingDemo {
- public static void main(String[] args) {
- //创建操作类对象,并调用方法
- JumppingOperator jo = new JumppingOperator();
- Jumpping j = new Cat();
- jo.useJumpping(j);
-
- Jumpping j2 = jo.getJumpping(); //new Cat()
- j2.jump();
- }
- }
-