多态的笔记

本文详细介绍了Java中的多态性,包括多态的概述、成员访问特点、好处与弊端以及多态程序的编写步骤。同时,文章讨论了抽象类的概念、特点、成员特性,并给出相关案例。此外,接口的定义、特点、成员特点以及接口与抽象类的对比也被深入探讨。通过一系列案例,展示了如何在实际编程中运用多态、抽象类和接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多态

多态的概述
  • 什么是多态?

    答:同一个对象,在不同的时刻有多种形态

    比如:

    Animal an = new Cat();
    Animal an = new Dog();
    
  • 多态的举例

    • 绿巨人 , 是正常人的时候是班纳,发怒后就变为绿巨人
    • 毛毛虫,刚开始是个虫,过段时间后就变为蝶了。
  • 多态的形式:具体类多态、抽象类多态、接口多态

  • 多态的前提

    • 要有实现 || 继承关系

    • 要有方法的重写

      体现:继承关系下,子类重写父类的方法;实现关系下,实现类 来实现接口中的方法

    • 父类的引用类型的变量指向了子类对象,接口的引用类型变量指向了实现类对象

多态中成员访问特点
  • 成员访问特点

    • 成员变量(实际开发中不太关注

      编译看左边,运行看左边

    • 成员方法(重点掌握)

      编译看左边,运行看右边

    总结:编译全看左边,只有成员方法运行看右边

    代码展示:

    // 动物类
    public class Animal {
        public int age = 40;
        public void eat() {
            System.out.println("动物吃东西");
        }
    }
    // 猫类
    class Cat extends Animal {
        public int age = 10;
        public int weight = 10;
        public void eat() {
            System.out.println("猫吃鱼");
        }
        public void playGame() {
            System.out.println("猫捉迷藏");
        }
    }
    // 编写测试类
    class AnimalTest {
        public static void main(String[] args) {
            // 父类的引用类型的变量指向了子类对象
            Animal an = new Cat();
            System.out.println(an.age);
            an.eat();
            an.playGame();
        }
    }
    
多态的好处和弊端
  • 好处

    提高了程序的扩展性

    具体体现:定义方法时,使用父类 | 接口类型作为方法形参,在调用该方法时,将 不同的子类对象 | 不同的实现类对象作为方法实参传入。

  • 弊端

    继承关系下的多态,不能访问子类的特有成员,实现关系下的多态,不能访问实现类的特有成员,若要访问必须向下转型

写一个多态程序的步骤(必须掌握)

继承关系下的多态:

  1. 写一个父类
  2. 写一个或多个子类继承父类,重写父类中的方法
  3. 写一个父类的使用类(或者叫做操作类),在使用类中定义一个方法,方法的形式参数类型就是父类类型
  4. 写一个测试类,在main方法中,创建使用类对象,调用其方法,将不同的子类对象作为其方法的实际参数传入

实现关系下的多态:

  1. 写一个接口
  2. 写一个实现类,实现类实现该接口,并实现接口中的所有抽象方法
  3. 写一个接口的使用类,在使用类中定义一个方法,方法的参数类型就是接口类型
  4. 写一个测试类,在main方法中,创建使用类对象,调用其方法,其方法的参数要传入不同的实现类对象
多态中的转型
  • 向上转型(就是多态的格式)

    父类的引用类型变量指向了子类对象 ,比如:

    Animal an =  new Cat();
    

    接口的引用类型变量指向了实现类对象,比如:

    SpeakEnglish se = new PingPang();
    
  • 向下转型(也叫做强制类型转换)

    父类的引用类型变量强转为子类对象,格式: 子类型 对象名 = (子类型) 父类引用;,比如:

    Animal an = new Cat(); // Cat是Animal的子类,Animal是Cat的父类
    Cat cat =  (Cat)an;
    

    接口的引用类型变量强转为实现类对象,格式:实现类类型 对象名 = (实现类类型)接口引用;,比如:

    SpeakEnglish se = new PingPang();// PingPang是SpeakEnglish接口的实现类
    PingPang  pp = (PingPang)se; 
    

    向下转型一定会成功吗?

    需要使用instanceof运算符,来判断对象是否属于某种类型,属于返回true,否则返回false,比如:

    public void  useAnimal(Animal an) {
        an.eat();
        if(an instanceof Wolf) {
            Wolf wolf = (Wolf)an;
            wolf.howl();
        }
    }
    

代码展示:

// 动物类
public class Animal {
    public void eat() {
        System.out.println("动物吃东西");
    }
}
// 猫类
class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
    public void playGame() {
        System.out.println("猫捉迷藏");
    }
}
// 测试类
class AnimalTest {
    public static void main(String[] args) {
        Animal an =  new Cat(); // 向上转型
        an.eat(); // 编译看左边,运行看右边
        
        Cat cat = (Cat)an; // 向下转型
        cat.eat(); // 编译看左边,运行看右边
        cat.platGame();
    }
}
多态的案例

需求:用多态思想实现猫和狗的案例,并在测试类中进行测试
代码展示:

// 动物类
public class Animal {
    // 编写属性
    protected String name;
    protected int age;
    // 编写无参构造
    public Animal() {
      // super()    
    }
    // 编写带参构造
    public Animal(String name ,int age) {
        this.name = name;
        this.age = age;
    }
    // 编写成员方法
    // setXxx()方法 和 getXxx() 方法
    public void setName(String name) {
        this.name = name ;
    }
    public String getName() {
        return name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public void eat() {
        System.out.println("动物要吃东西");
    }
}
// 猫类
class Cat extends Animal {
    // 无参构造
    public Cat() {
        
    }
    // 带参构造
    public Cat(String name ,int age) {
        super(name,age);
    }
    // 子类重写父类Animal父类的方法
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
// 狗类
class Dog extends Animal {
    // 无参构造
    public Dog() {
        
    }
    // 带参构造
    public Dog(String name , int age) {
        super(name,age);
    }
    // 子类重写父类中的方法
	public void eat() {
        System.out.println("狗吃骨头");
    }
}
// 编写测试类
class Test {
    // 编写main方法,main方法是程序的入口,能被JVM识别并执行
    public static void main(String[] args) {
        // 父类的引用类型的变量指向子类对象
        Animal an = new Cat();
        an.setName("加菲");
        an.setAge(5);
        System.outt.println(an.getName() + "," + an.getAge());
        an.eat();
        
        an = new Cat("加菲",5);
       	System.out.println(an.getName + ", " + an.getAge());\
        an.eat();
    }
}

抽象类

抽象类的概述

当我们在做子类共性功能抽取时,有些方法在父类中并未具体的体现,这时就需使用抽象类了

比如:世上没有一个对象是动物,只会是具体的猫和狗,所以我们不需创建Animal类的对象,该类应定义为抽象类。

java中,一个没方法体“{}”的方法应定义为抽象方法,而类中若有抽象方法,那该类必须定义为抽象类

什么是抽象方法?答:一个方法只有方法声明,没有方法体,有abstract修饰的方法,就是抽象方法

抽象类的特点
  • 抽象类和抽象方法必须使用abstract关键字修饰

    // 抽象类的定义
    public abstract class 类名 {}
    // 抽象方法的定义
    public abstract 返回值类型 方法名称();
    
  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类

  • 抽象类不能实例化

    抽象类如何实例化?

    答:参照多态的方式,通过子类对象实例化,这叫抽象类多态

  • 抽象类的子类

    要么重写抽象类中的所有抽象方法

    要么是抽象类

抽象类的成员特点
  • 成员的特点
    • 成员变量
      • 既可以是变量
      • 也可以是常量
    • 构造方法
      • 有构造方法,但不能抽象类不能创建对象

        那抽象类中的构造方法的作用是用于给子类调用,来初始化父类中的成员变量,方便访问。

    • 成员方法
      • 抽象方法

        作用:限定子类必须重写抽象类父类中的所有抽象方法

      • 普通方法

        作用:直接给子类继承使用,提高了代码复用性。

普通类和抽象类的区别:普通类有的抽象类都可有,抽象类还可有抽象方法。抽象类的成员,比原来普通类多了一个抽象方法

代码展示:

public abstract class Animal {
    // 变量
    private int age = 20;
    // 常量
    private final String city = "北京";
    // 无参构造
    public Animal() {
        
    }
    // 带参构造
    public Animal(int age) {
        this.age = age;
    }
    // 普通方法
	public void show() {
        age = 40;
        // city = "上海"; // 编译错误,因为是常量,常量一旦赋值,值不可发生改变
	   System.out.println(age); // 40
       System.out.println(city); // 北京
    }
    // 抽象方法
    public abstract void eat();
}
class Cat extends Animal {
	// 重新抽象类父类中eat方法
    public void eat() {
        System.out.println("猫吃鱼");
    }
   
}
class AniamlTest {
    public static void main(String[] args) {
        // 父类的引用类型变量指向了子类对象
        Animal an = new Cat();
        // 多态中访问成员方法的特点:编译看左边,运行看右边
	    an.eat();
        an.show();
    }
}
抽象类的案例

需求:用抽象类的思想实现猫和狗的案例,并用测试类来测试

代码展示:

// 编写动物类 
public abstract class Animal {
    private String name;
    private int age;
    // 无参
    public Animal() {
        
    }
    // 带参
    public Animal(String name ,int age) {
        this.name = name;
        this.age = age;
    }
    // getXxx() 和 setXxx()方法
    public void setName(String name ) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public abstract void eat();
} 
// 猫类
class Cat extends Animal {
    // 无参
    public Cat() {
        
    }
    public Cat(String name,int age) {
        super(name,age);
    }
    // 子类重写父类中的eat方法
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
// 狗类
class Dog extends Animal {
    // 无参构造
    public Dog() {
        
    }
    public Dog(String name,int age) {
        super(name,age);
    }
    // 子类重写父类中的eat方法
    public void eat() {
        System.out.println("狗啃骨头");
    }
}
// 编写测试类
class  AnimalTest {
    // 编写main方法,main方法是程序的入口,能被JVM识别并执行
    public static void main(String[] args) {
        // 父类的引用类型变量指向了子类对象
        Aniaml an  = new Cat();
        an.setName("加菲");
        an.setAge(5);
        System.out.println(an.getName() + "," + an.getAge());
        an.eat();
        System.out.println("---------------");
        an = new Cat("加菲",5);
        System.out.println(an.getName() + "," + an.getAge());
        an.eat();
    }
}

接口

接口的概述

接口是种公共的规范标准,只要符合规范标准,大家都可以通用。java中的接口更多体现在对行为(或者叫做方法)的抽象。

接口的举例

在生活中的接口其实就是种公共的规范,不同的电子设备只要符合相同的规范,就可集成到一起使用

例如:

USB接口:U盘,移动硬盘,usb小风扇等等,只要这些设备都符合USB接口这种规范,这些设备就都可以通用

接口的特点
  • 接口用interface关键字修饰

    public interface 接口名 {}
    
  • 类实现接口用implements表示

    public class 类名 implements 接口名 {}
    
  • 接口不能实例化

    接口如何实例化呢?参照多态的方式,通过实现类对象实例化,这叫接口多态

  • 接口的实现类

    要么重写接口中的所有抽象方法

    要么子类是抽象类

接口的成员特点
  • 成员特点

    • 成员变量

      只能是常量,默认修饰符:public static final

    • 构造方法

      没有,接口不能实例化,一个类若没有父类,默认继承Object类

  • 成员方法

    只能是抽象方法

    默认修饰符:public abstract

    接口中的方法在JDK 1.8和JDK 1.9中有些新特性

代码展示:

// 接口
public interface Inter {
    public int num = 10;
    public final int num2 = 20;
    public static final int num3 = 30;
    int num3 = 30;
    // 接口中没有构造方法,不能实例化
    // public Inter() {}
    public abstract void method();
    void show();
}
// 实现类
class InterImpl /* extends Object */ implements Inter {
    public InterImpl() {
        super();
    }
    public void method() {
        System.out.println("method");
    }
    public void show() {
        System.out.println("show");
    }
}
// 测试类
class  InterfaceTest {
    public static void main(String[] args) {
        // 接口的引用类型变量指向了实现类对象 
        Inter inter = new InterImpl();
        // 多态中访问成员变量的特点:编译看左边,运行看左边
        // inter.num = 20;  编译错误,因为是常量
        System.out.println(inter.num);
        // inter.num2 = 40; 编译错误
        System.out.println(inter.num2);
        System.out.println(Inter.num);
    }
}
接口的案例

需求:对猫和狗进行训练,他们可以跳高了,这里加入跳高功能

请采用抽象类和接口来实现猫狗案例,并在测试类中进行测试

代码展示:

// 动物类
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 void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public abstract void eat();
}
// 跳高接口
interface Jumpping {
    // 抽象方法
    public abstract void jump();
}
// 猫类
class Cat extends Animal implements Jumpping {
    // 无参构造
    public Cat() {
        
    }
    // 带参构造
    public Cat(String name,int age) {
        super(name,age);
    }
    public void eat() {
        System.out.println("猫吃鱼");
    }
    public void jump() {
        System.out.println("猫可以跳高了...");
    }
}

// 测试类
class AnimalTest {
    public static void main(String[] args) {
        // 创建对象,调用方法
        // 接口引用类型变量指向了实现类对象
        Jumpping jp = new Cat();
        // 多态中调用成员方法的特点:编译看左边,运行看右边
        jp.jump();  
        System.out.println("--------------");
   
        // 父类的引用类型变量指向了子类对象
        Aniaml an = new Cat(); 
        an.setName("加菲");
        an.setAge(5);
        System.out.println(an.getName() + "," + an.getAge());
        an.eat();
        
        an = new Cat("加菲",5);
        System.out.println(an.getName() + "," + an.getAge());
        an.eat();
        System.out.println("----------------");
        
        Cat c = new Cat();
        c.setName("加菲");
        c.setAge(5);
        System.out.println(c.getName() + "," + c.getAge());
        c.eat();
        c.jump();
    }
}
类和接口的关系
  • 类与类的关系

    继承关系,只能单继承,但支持多层继承

  • 类与接口的关系

    实现关系,可单实现,也可多实现,还可在继承一个类的同时实现多个接口

  • 接口与接口的关系

    继承关系,可单继承、也可多继承

抽象类和接口的区别
  • 成员区别

    • 抽象类

      变量,常量,有构造方法,可有抽象方法,也可没抽象方法

    • 接口

      常量,抽象方法

  • 关系区别

    • 类与类

      继承,单继承

    • 类与接口

      实现,可单实现,也可多实现

    • 接口与接口

      继承,单继承,多继承

  • 设计理念的区别

    • 抽象类
      • 对类抽象,包括属性和行为
    • 接口
      • 对方法抽象,主要是行为

    描述:抽象类与其派生类是一种is-a关系,即父类和派生子类在概念上的本质是相同的(父子关系,血缘关系,很亲密)。接口与其实现类是一种like-a关系,即接口与实现类的关系只是实现了定义的行为,并无本质上的联系(契约关系,比较松散)。

    比如:

    猫,狗可继承动物,猫,狗都是动物的一种

    鸟可实现飞行接口,飞机也可实现飞行接口,但鸟和飞机并无本质联系。

综合案例

需求:我们现在有兵乓球运动员和篮球运动员,兵乓球教练和篮球教练

为了出国交流,跟兵乓球相关的人员都需要学习英语

请用所学知识分析,这个案例中有哪些具体类,哪些抽象类,哪些接口,并用代码实现
在这里插入图片描述

代码展示:

public abstract class Person {
    // 编写成员变量
    private String name;
    private int age;
    public Person() {
        
    }
    public Person(String name,int age) {
        this.name = anme;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
    	this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public abstract void eat();
}
// 抽象运动员类
abstract class Player extends Person {
    // 无参构造
    public Player() {
        
    }
    // 带参构造
    public Player(String name,int age) {
        super(name,age); // 调用父类中的带参构造
    }
    // 抽象方法
    public abstract void study();
}
// 抽象教练类
abstract class Coach extends Person {
    public Coach() {
        
    }
    public Coach(String name,int age) {
        super(name,age);
    }
    public abstract void teach();
}
// 学英语接口
interface SpeakEnglish {
    public abstract void speak();
}
// 篮球教练
class BasketBallCoach extends Coach {
    // 无参构造
    public BasketBallCoach() {
        
    }
    // 带参构造
    public BasketBallCoach(String name,int age) {
        super(name,age);
    }
    // 子类重写父类中的方法
    public void teach() {
        System.out.println("篮球教练教如何运球和投篮");
    }
    public void eat() {
        System.out.println("篮球教练吃羊肉,喝牛奶");
    }
}
// 兵乓球教练
class PingPangCoach extends Coach implements SpeakEnglish {
    public PingPangCoach() {
        
    }
    public PingPangCoach(String name,int age) {
        super(name,age);
    }
    public void teach() {
        System.out.println("兵乓球教练教如何发球和接球");
    }
    public void eat() {
        System.out.println("兵乓球教练吃小白菜,喝大米粥");
    }
    public void speak() {
        System.out.println("兵乓球教练说英语");
    }
}
// 兵乓球运动员
class PingPang extends Player implements SpeakEnglish {
    public PingPangPlayer() {
        
    }
    public PingPangPlayer(String name,int age) {
        super(name,age);
    }
    public void study() {
        System.out.println("兵乓球运动员学习如何发球和接球")
    }
    public void eat() {
        System.out.println("乒乓球运动员吃大白菜,喝小米粥");
    }
    public void speak() {
        System.out.println("兵乓球运动员说英语");
    }
}
// 篮球运动员
class BasketBallPlayer extends Player {
    public BasketBallPlayer() {
        
    }
    public BasketBallPlay(String name,int age) {
        this.name  = name;
        this.age = age;
    } 
    public void study() {
        System.out.println("篮球运动员学习如何运球和投篮");
    }
    public void eat() {
        System.out.println("篮球运动员吃牛肉,和牛奶");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奔走中的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值