16.多态

发布于:2022-12-15 ⋅ 阅读:(525) ⋅ 点赞:(0)

1.什么是多态

生活中的多态:同一种事物,由于条件的不同,产生的结果也不同。

多态:同一个引用类型,使用不同的实例而执行不同的操作。

1.1 认识多态

1、多态的通常含义是指能够呈现出不同的形式或者形态;

2、在程序设计中,多态意味着一个特定类型的变量可以引用不同类型的对象,并且自动的调用引用的对象的方法,也就是说,根据不同的引用的对象的类型,执行不同的操作;

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

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

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

1.2 向上转型

什么是向上转型:子类向父类的转换称为向上转型,即:父类的引用对象指向子类对象,是自动类型转换

语法格式:父类名  父类对象=new 子类型();

注:

此时通过父类引用变量调用的方法是子类覆盖或继承了父类的方法,并不是父类的方法;

此时通过父类引用变量无法调用子类特有的方法。

1.3 向下转型

概念:将一个指向子类对象的父类引用赋给一个子类的引用,即将父类类型转换为子类类型,是强制类型转换。

语法格式:子类型  引用变量名=(子类型)父类引用变量;

1.4 instanceof运算符

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

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

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

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

1.5 多态的优势

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

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

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

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

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

2.抽象方法和抽象类

2.1 抽象方法

在Java中,当一个类的方法被abstract关键字修饰时,这个方法称之为抽象方法。

语法格式:访问修饰符 abstract 返回值类型 方法名(参数列表);

访问修饰符,参数列表根据需要可写可不写。

特点:

1.抽象方法没有方法体;

2.抽象方法所在的类必须定义为抽象类;

3.抽象方法在子类中必须要重写,如果这个子类不重写这个抽象方法,则这个子类要定义为抽象类。

注:

private关键字不能用来修饰抽象方法;

abstract修饰符不能和final修饰符一起使用。

2.2 抽象类

在Java中,当一个类被abstract关键字修饰时,该类称之为抽象类。

语法格式:abstract  class 类名{

                代码

}

说明:

抽象类需要用修饰符abstract修饰,普通类不需要。

1.普通类可以实例化,抽象类不能被实例化。

2.抽象类中可以有抽象方法也可以没有抽象方法,可以有普通方法也可以没有普通方法。

3.抽象类中可以包含普通类包含的一切成员。

当一个类实例化没有意义时,就可以把这个类定义为抽象类。

3.多态的举例说明

需求:使用多态实现主人领养动物并带动物看病的功能,狗有特有的吃方法,企鹅有特有的游泳方法。

1.编写父类

//编写父类
public class Animal {
	private String name;
	private int health;
	private int love;

	public Animal() {

	}

	public Animal(String name, int health, int love) {
		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 toHospital(){
		System.out.println("去看病");
	}
}

2.编写子类

//编写子类Dog,通过关键字extends继承父类Animal
public class Dog extends Animal {
	// 声明品种属性,这个属性是Dog类特有的
	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;
	}

	//Dog类重写的toHospital()看病方法
	public void toHospital() {
		System.out.println("打针");
		this.setHealth(80);
	}
	//Dog类特有的eat()方法
	public void eat() {
		System.out.println("狗喜欢吃骨头");
	}
}
//编写子类Penguin类,继承父类Animal类
public class Penguin extends Animal {
	
	// Penguin类特有属性
	private String sex;
	// 无参构造方法
	public Penguin() {
		super();
	}
	// 有参构造方法
	public Penguin(String name, int health, int love, String sex) {
		super(name, health, love);
		this.sex = sex;
	}
	//sex读写方法
	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	@Override
	//Penguin类重写的toHospital()看病方法
	public void toHospital() {
		System.out.println("打针,吃药");
		this.setHealth(90);
	}
	//Penguin类特有的swimming()方法
	public void swimming(){
		System.out.println("企鹅会仰泳");
	}
}

3.编写主人类,定义看病方法

//编写主人类,在这个类中定义看病方法
public class Master {
	//定义看病方法
	public void cure(Animal animal){
		//如果animal的健康值低于60,就去看病
		if(animal.getHealth()<60){
			animal.toHospital();
		}
	}
}

4.进行测试

public class Test {

	public static void main(String[] args) {
		// 创建主人类对象
		Master master = new Master();

		// 向上转型:父类引用指向子类的实例(对象),即子类向上转型了
		// 父类引用animal指向子类Dog类对象
		Animal animal = new Dog("富贵", 30, 98, "金毛");
		System.out.println("看病前健康值:" + animal.getHealth());

		// 调用看病方法,此时的animal指向Dog类,进而调用Dog类的看病方法toHospital()方法
		master.cure(animal);
		System.out.println("看病后健康值:" + animal.getHealth());
		// 但是父类引用不能调用子类的特有方法和属性
		// animal.eat();
		// animal.getStrain();
		
		// 向下转型:子类的引用(对象名)指向父类引用(对象名),即父类向下转型,需要强制类型转换
		Dog dog = (Dog) animal;
		dog.eat();// 调用Dog类的特有方法eat()方法
		System.out.println("狗的品种:" + dog.getStrain());

		System.out.println("----------------");
		
		// 父类引用指向子类Penguin类对象
		animal = new Penguin("qq", 40, 99, "公");
		System.out.println("看病前健康值:" + animal.getHealth());
		// 调用看病方法,此时的animal指向Penguin类,进而调用Penguin类的看病方法toHospital()方法
		master.cure(animal);
		System.out.println("看病后健康值:" + animal.getHealth());
		//下面两行代码在编写时不会报错,但是运行会报错,因为此时的父类引用指向的是子类Penguin类对象,向下转型时却没有转换成其指向的子类
		/*Dog dog1=(Dog)animal;//ClassCastException类型转换异常,父类引用没有转换成其指向的子类
		dog1.eat();*/
		
		/*由此可见:
		 * 在向下转型的时候,有可能转换错误,没有转换成其指向的子类,这时候会报ClassCastException异常
		 * 我们可以在转型之前使用instanceof关键字进行判断父类引用指向了哪个子类对象 
		 */
		if(animal instanceof Dog){
			Dog dog1=(Dog)animal;
			dog1.eat();
		}else if(animal instanceof Penguin){
			Penguin pe1=(Penguin)animal;
			pe1.swimming();
		}
	}
}
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到