• 多态与抽象



    在这里插入图片描述

    认识多态

    1. 多态一词的通常含义是指能够呈现出多种不同的形式或形态。

    2. 在程序设计的术语中,它意味着一个特定类型的变量可以引用不同类型的对象,并且自动地调用引用的对象的方法,也就是根据作用到的不同对象类型,响应不同的操作。

    3. 方法重写是实现多态的基础。

    4. 多态意味着在一次方法调用中根据包含的对象的实际类型(即实际的子类对象)来决定应该调用哪个方法,而不是由用来存储对象引用的变量的类型决定的。

    5. 当调用一个方法时,为了实现多态的操作,这个方法既是在父类中声明过的,也必须是在子类中重写过的方法。

    向上转型

    1. 向上转型:子类向父类的转换称为向上转型。

    2. 向上转型的语法格式如下:

    <父类型> <引用变量> = new <子类型>();

    • 将一个父类的引用指向一个子类对象称为向上转型,系统会自动进行类型转换。
    • 此时通过父类引用变量调用的方法是子类覆盖或继承了父类的方法,不是父类的方法。
    • 此时通过父类引用变量无法调用子类特有的方法。

    向下转型

    1. 向上转型中,父类引用变量无法调用子类特有的方法,如果需要调用子类特有的方法,可以通过把父类转换为子类来实现。

    2. 向下转型:将一个指向子类对象的父类引用赋给一个子类的引用,即将父类类型转换为子类类型,称为向下转型,此时必须进行强制类型转换。

    3. 向下转型的语法格式如下:

    <子类型> <引用变量名> = (<子类型>)<父类型的引用变量>;

    1. 上述这种向下转型的操作对接口和抽象(普通)父类同样适用。

    instanceof运算符

    1. 在向下转型的过程中,如果不是转换为真实子类类型,会出现类型转换异常(ClassCastException)。

    2. 在Java中提供了instanceof运算符类进行类型的判断。

    3. 使用instanceof时,对象的类型必须和instanceof后面的参数所指定的类有继承关系,否则会出现编译错误。

    4. instanceof通常和强制类型转换结合使用。

    多态的优势

    1)可替换性:多态对已存在的代码具有可替换性。

    2)可扩充性:多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特征的运行和操作。实际上新加子类更容易获得多态功能。

    3)接口性:多态是父类向子类提供了一个共同接口,由子类来具体实现。

    4)灵活性:多态在应用中体现了灵活多样的操作,提高了使用效率。

    5)简化性:多态简化了应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

    多态的两种主要应用形式

    1、 使用父类作为方法的形参

    2、 使用父类作为方法的返回值

    多态和继承章节总结

    1、 继承是Java中实现代码重用的重要手段之一。Java中只支持单根继承,即一个类只能有一个直接父类。Object类是所有Java类的祖先。

    2、 在子类中可以根据实际需要对从父类继承的方法进行重新编写,称为方法的重写或覆盖。

    3、 子类中重写的方法和父类中被重写的方法必须具有相同的方法名、参数列表,返回值类型必须和被重写方法的返回值类型相同。

    4、 在实例化子类是,会首先执行其父类的构造方法,然后在执行子类的构造方法。

    5、 通过super关键字可以访问父类的成员。

    6、 通过多态可以减少类中的代码量,可以提高代码的可扩展性和可维护性。继承是多态的基础,没有继承就没有多态。

    7、 在多态的应用中,可以使用父类作为方法的形参,还可以作为方法的返回值。

    8、 把子类转换为父类称为向上转型,系统自动进行类型转换。把父类转换为子类,称为向下转型,必须进行强制类型转换。

    9、向上转型后,通过父类引用变量调用的方法是子类覆盖或继承自父类的方法,通过父类引用变量无法调用子类特有的方法。

    10、 向下转型后可以访问子类特有的方法。向下转型必须转换为父类指向的真实子类类型,否则将出现类型转换异常ClassCastException。

    11、 instanceof运算符用于判断一个对象是否属于一个类。

    在这里插入图片描述

    抽象方法和抽象类

    区分普通方法和抽象方法

    (1)在Java中,当一个类的方法被abstract关键字修饰时,该方法称为抽象方法。
    (2)抽象方法所在的类必须定义为抽象类。
    (3)当一个方法被定义为抽象方法后,意味着该方法不会有具体的实现(没有方法体),而是在抽象类的子类中通过方法重写进行实现。
    (4)定义抽象方法的语法格式如下:

    [访问修饰符] abstract <返回类型> <方法名>([参数列表]);

    • 抽象方法需要使用abstract修饰,普通方法不需要。
    • 抽象方法没有方法体,普通方法没有。
    • 抽象方法所在的类必须被定义为抽象类。
    • 抽象方法在子类中必须被实现(子类要重写父类中的抽象方法),如果子类不实现,则子类要定位为抽象类。
    • private关键字不能用来修饰抽象方法。
    • abstract修饰符不能和final修饰符一起使用。

    区分普通类和抽象类

    (1)在Java中,当一个类被abstract关键字修饰时,该类称为抽象类。
    (2)定义抽象类的语法格式如下:

    abstract class <类名>{
    				//代码
    		}
    
    • 1
    • 2
    • 3
    • 抽象类需要用修饰符abstract修饰,普通类不需要。
    • 普通类可以实例化,抽象类不能被实例化。
    • 抽象类中可以有抽象方法也可以没有抽象方法,可以有普通方法也可以没有普通方法。
    • 抽象类中可以包含普通类包含的一切成员。

    定义一个抽象类

    当一个类被定义为抽象类时,它可以包含各种类型的成员,包括属性、方法等。其中方法又可以分为普通方法和抽象方法。

    public abstract class 类名称{
    	修饰符 abstract 返回类型 方法名();
    	修饰符 返回类型 方法名(){
    		//方法体
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    使用抽象类描述抽象的事物

    当一个类实例化没有意义时,可以将该类定义为抽象类

    抽象类和抽象方法的优势

    (1)抽象类中已经实现的方法可以被子类使用,使代码可以被复用。
    (2)抽象类中的抽象方法,子类需要进行重写,保证了子类具有自身的独特性。

    抽象类的局限性

    (1)抽象类有时候会出现代码冗余的问题。
    (2)类的继承是单根继承,一个类只能直接继承一个类。

    案例

    package cn.bdqn.demo03;
    
    public class Animal {
    
    	private String name;
    	private int health;
    	private int love;
    
    	public Animal() {
    		super();// 调用Object类里无参构造方法
    	}
    
    	public Animal(String name, int health, int love) {
    		super();
    		this.name = name;
    		this.health = health;
    		this.love = love;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public int getHealth() {
    		return health;
    	}
    
    	public void setHealth(int health) {
    		this.health = health;
    	}
    
    	public int getLove() {
    		return love;
    	}
    
    	public void setLove(int love) {
    		this.love = love;
    	}
    
    	public void print() {
    		System.out.println("Animal:宠物信息:昵称:" + this.getName() + ",健康值:"
    				+ this.getHealth() + ",亲密度:" + this.getLove());
    	}
    	
    	public void toHospital(){
    		System.out.println("宠物看病......");
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    package cn.bdqn.demo03;
    
    public class Cat extends Animal {
    
    	private String color;
    
    	public Cat() {
    		super();
    	}
    
    	public Cat(String name, int health, int love, String color) {
    		super(name, health, love);
    		this.color = color;
    	}
    
    	public String getColor() {
    		return color;
    	}
    
    	public void setColor(String color) {
    		this.color = color;
    	}
    	
    	@Override
    	public void print() {
    		super.print();
    		System.out.println("猫的颜色:"+this.getColor());
    	}
    	
    	@Override
    	public void toHospital() {
    		System.out.println("打针,吃药......");
    		this.setHealth(90);
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    package cn.bdqn.demo03;
    
    public class Dog extends Animal {
    	//在这个Dog类中只定义Dog类中特有的属性和方法,原来和Penguin类中相同的代码在Animal类中,通过继承获取,使用extends关键字来获取
    	
    	private String strain;
    
    	public Dog() {
    		super();//表示使用Animal类中的无参构造方法
    	}
    
    	public Dog(String name, int health, int love, String strain) {
    		super(name, health, love);//表示使用Animal类中的有参构造方法
    		this.strain = strain;
    	}
    
    	public String getStrain() {
    		return strain;
    	}
    
    	public void setStrain(String strain) {
    		this.strain = strain;
    	}
    	
    	
    	
    	public void print(){
    		super.print();
    		System.out.println("Dog:品种:"+this.getStrain());
    	}
    	
    	@Override
    	public void toHospital() {
    		System.out.println("打针......");
    		this.setHealth(80);
    	}
    	
    	//定义Dog类中特头的方法
    	public void eat(){
    		System.out.println("狗吃骨头......");
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    package cn.bdqn.demo03;
    
    public class Penguin extends Animal {
    	//定义企鹅类中特有的属性
    	private String sex;
    
    	public Penguin() {
    		super();//表示使用Animal类中的无参构造方法
    	}
    
    	public Penguin(String name, int health, int love, String sex) {
    		super(name, health, love);
    		this.sex = sex;
    	}
    
    	public String getSex() {
    		return sex;
    	}
    
    	public void setSex(String sex) {
    		this.sex = sex;
    	}
    	
    	@Override
    	public void print() {
    		
    		super.print();
    		System.out.println("Penguin:性别:"+this.getSex());
    	}
    
    	@Override
    	public void toHospital() {
    		System.out.println("吃药......");
    		this.setHealth(75);
    	}
    	
    	//定义Penguin类中特头的方法
    	public void swimming(){
    		System.out.println("企鹅会仰泳");
    	}
    	
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    package cn.bdqn.demo03;
    
    public class Tiger extends Animal {
    	
    	private String weight;
    
    	public Tiger() {
    		super();
    	}
    
    	public Tiger(String name, int health, int love, String weight) {
    		super(name, health, love);
    		this.weight = weight;
    	}
    
    	public String getWeight() {
    		return weight;
    	}
    
    	public void setWeight(String weight) {
    		this.weight = weight;
    	}
    	
    	@Override
    	public void toHospital() {
    		System.out.println("吃一只鸡......");
    		this.setHealth(99);
    	}
    	
    	//定义Tiger类中特有的方法
    	public void sleep(){
    		System.out.println("老虎打盹");
    	}
    
    	
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    package cn.bdqn.demo03;
    
    public class Master {
    	//定义给宠物Animal看病的方法
    	public void cure(Animal animal){
    		if(animal.getHealth()<60){
    			//这里animal调用的方法在形式上看是调用Animal类中的toHospital()方法,实际上调用的方法是animal对象指向的子类中重写后的toHospital()方法
    			animal.toHospital();
    		}
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    package cn.bdqn.demo03;
    
    public class Test {
    
    	public static void main(String[] args) {
    		// 创建Master类对象
    		Master master = new Master();
    		
    		//创建Dog类对象
    //		Dog dog = new Dog("宝马", 30, 90, "泰迪");
    //		master.cure(dog);
    		
    		//向上转型:父类的引用(对象名)指向子类的实例(对象)
    		Animal animal = new Dog("奥迪", 30, 90, "泰迪");
    		System.out.println("看病前的健康值:"+animal.getHealth());
    		master.cure(animal);
    		System.out.println("看病后的健康值:"+animal.getHealth());
    		//父类引用无法调用子类中特有的方法
    		//animal.eat();
    		//向下转型:子类的引用(对象名)指向父类的引用(对象名)
    		Dog dog =(Dog)animal;
    		dog.eat();
    		
    		
    		animal = new Penguin("精灵", 20, 88, "母");
    		System.out.println("看病前的健康值:"+animal.getHealth());
    		master.cure(animal);
    		System.out.println("看病后的健康值:"+animal.getHealth());
    		//animal是父类引用,无法调用子类中特有的方法
    //		animal.swimming();
    		Penguin penguin = (Penguin)animal;
    		penguin.swimming();
    		
    		animal = new Tiger("东北虎", 10, 99, "500公斤");
    		System.out.println("看病前的健康值:"+animal.getHealth());
    		master.cure(animal);
    		System.out.println("看病后的健康值:"+animal.getHealth());
    		//父类引用无法调用子类中特有的方法
    //		animal.sleep();
    //		Tiger tiger =(Tiger)animal;
    //		tiger.sleep();
    //		Penguin penguin2 = (Penguin)animal;//ClassCastException 类型转换异常,父类没有转换成其指向的子类
    //		penguin2.swimming();
    		/*
    		 * 在向下转型的时候,有可能转换错误,没有转换成其指向的子类,这时候会报ClassCastException异常
    		 * 我们可以在转型之前使用instanceof关键字进行判断父类引用指向了哪个子类对象
    		 * 
    		 * 
    		 */
    		
    		if(animal instanceof Dog){
    			Dog dog2 =(Dog)animal;
    			dog2.eat();
    		}else if(animal instanceof Penguin){
    			Penguin penguin2 = (Penguin)animal;
    			penguin2.swimming();
    		}else if(animal instanceof Tiger){
    			Tiger tiger2 =(Tiger)animal;
    			tiger2.sleep();
    		}
    		
    
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    总结

    1. 方法重写是实现多态的基础。
    2. 向上转型:子类向父类的转换称为向上转型。
    3. 向下转型:将一个指向子类对象的父类引用赋给一个子类的引用,即将父类类型转换为子类类型,称为向下转型,此时必须进行强制类型转换。
    4. 多态的优势:可替换性,可扩充性,接口性,灵活性,简化性。
    5. 多态的两种主要应用形式:
      1) 使用父类作为方法的形参
      2) 使用父类作为方法的返回值
    6. 抽象类需要用修饰符abstract修饰,普通类不需要。
    7. 普通类可以实例化,抽象类不能被实例化。
    8. 抽象类中可以有抽象方法也可以没有抽象方法,可以有普通方法也可以没有普通方法。
    9. 抽象类中可以包含普通类包含的一切成员。
    10. 抽象类和抽象方法的优势
      (1)抽象类中已经实现的方法可以被子类使用,使代码可以被复用。
      (2)抽象类中的抽象方法,子类需要进行重写,保证了子类具有自身的独特性。
    11. 抽象类的局限性
      (1)抽象类有时候会出现代码冗余的问题。
      (2)类的继承是单根继承,一个类只能直接继承一个类。
  • 相关阅读:
    R语言使用caret包的nzv函数进行接近零方差变量(特征)的删除、方差是衡量一个变量的离散程度(即数据偏离平均值的程度大小、越靠近零方差判别性越差)
    PCB电路板废水铜回收工艺有哪些?哪个处理效果好?
    【Linux】VM及WindowsServer安装
    SAP ABAP 基本运算(加减乘除取余 四舍五入 向上下取整) 问题:在使用`DIV`和 `/` 出现的差异以及错误
    二叉树的先序、中序、后序、层序遍历(递归&非递归)
    verilog牛客网刷题代码汇总
    Pyhon函数定义中的:必选参数、可选参数、可变参数
    RK3588S android12 删除设置-存储选项
    复合类型(自定义类型)
    AMSR/ADEOS-II L1A Raw Observation Counts V003地球表面和大气微波辐射的详细观测数据
  • 原文地址:https://blog.csdn.net/qq_45734913/article/details/126896653