【JAVA入门】Day10 - 多态

【JAVA入门】Day10 - 多态



        面向对象的三大特征就是:封装继承多态
        封装,是对象代表什么,就得封装对应的数据,并提供数据对应的行为。
        为了解决封装代码冗余的问题,继承诞生了,解决了 Javabean 当中代码重复的问题。
        多态是指对象的“多种形态”。如下面的代码所示,我们创建了(new)一个 Student 对象,然后直接把它赋值给了其父类 Person 的一个对象 p,这种形式是合理的,它就是多态。

//子类 学生形态 对象 s
Student s = new Student();
//父类 人的形态 对象 p
Person p = new Student();

        多态的应用场景也有很多,不同用户身份登录就是其中一种应用。

public void register(? ? ?) {

	//方法里面就是注册的代码逻辑

}

        我们可以根据传递对象的不同,调用不同对象中的同名方法。基于上面那个多态的特性,我们就可以把子类对象作为参数赋值给父类对象

public void register(Person p) {

		p.show();
		
}

        根据传递对象的不同,就会调用不同的 show 方法。假如 Person 有子类 Administrator 和 NormalUser,那么将 Administrator 的对象作为参数传递给这里,这里的 p.show() 就会调用 Administrator 的;将 NormalUser 的对象作为参数传递给这里,这里的 p.show() 就会调用 NormalUser 的。

Administrator a = new Administrator();
register(a); //把 a 赋值给 p,此时的 p.show() 相当于 a.show()

一、什么是多态

        同类型的对象,表现出不同的形态,这就是多态。
        其表现形式为:

父类类型 对象名称 = 子类对象;

        多态是有前提的:

  • 有继承 / 实现关系。
  • 有父类引用指向子类对象。 Fu f = new Zi();
  • 有方法重写。
public class Person {
	private String name;
	private int 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 void show() {
		System.out.println(name + ", " + age);
	}
}
public class Student extends Person {

	@Override
	public void show() {
		System.out.println("学生的信息为:" + getName() + ", " + getAge());
	}
}
public class Teacher extends Person {

	@Override
	public void show() {
		System.out.println("教师的信息为:" + getName() + ", " + getAge());
	}
}
public class Administrator extends Person {

	@Override
	public void show() {
		System.out.println("管理员的信息为:" + getName() + ", " + getAge());
	}
}
public class Test {
	public static void main(String[] args) {
		//创建三个对象,调用 register 方法
		Student s = new Student();
		s.setName("张三");
		s.setAge(18);

		Teacher t = new Teacher();
		t.setName("王坚果");
		t.setAge(30);

		Administrator a = new Administrator();
		a.setName("管理员");
		a.setAge(28);
	}

	//这个方法要既能接受老师,又能接受学生,还能接受管理员
	//只能把参数写成这三个类型的父类
	public static void register(Person p) {
		p.show();
	}
}

二、多态调用成员的特点

  • 变量调用:编译看左边,运行也看左边。
  • 方法调用:编译看左边,运行看右边。
public class Test {
	public static void main(String[] args) {
	//创建对象(多态方式)
	//Fu f = new Zi();
	Animal a = new Dog();
	//调用成员变量:编译看左边,运行也看左边
	//编译看左边:javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功;如果没有,编译失败。
	//运行也看左边:java运行代码的时候,实际获取的也是左边父类中的成员变量的值。
	System.out.println(a.name);		//动物

	//调用成员方法:编译看左边,运行看右边
	//编译看左边:javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功;如果没有,编译失败。
	//运行看右边:java运行代码的时候,实际上运行的是子类中的方法。
	a.show();			// Dog --- show方法
	}
}
class Animal {
	String name = "动物";
	public void show()  {
		System.out.println("Animal --- show方法");
	}
}

class Dog extends Animal {
	String name = "狗";

	@Override
	public void show() {
		System.out.println("Dog --- show方法");
	}
}

三、多态的优势

  • 在多态形势下,右边对象可以实现解耦合,便于扩展和维护。
Person p = new Student();
p.work(); 			// 业务逻辑发生改变时,后续代码无需修改

        如上代码所示,p.work();无需做任何改动,只需要修改第一行等号右边的 new Student(); 就可以实现业务逻辑的改变。

  • 定义方法的时候,使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利性。

四、多态的弊端

  • 不能调用子类特有的功能(方法)。(编译看左边,如果子类特有这个方法,而父类没有,编译压根不会通过)

        因此,针对这个弊端,我们要进行一些改进。解决方案一般是:把调用者变回子类类型就可以了。

Animal a = new Dog();
a.eat();
a.lookHome();	//报错,父类中没有lookHome方法
Animal a = new Dog();
a.eat();
Dog d = (Dog) a;  //强制类型转换
d.lookHome();

        但是一定要注意:强制转换的父类对象应本来就是用相应的子类对象赋值创建的,转换类型与真实对象类型不一致会报错。比如下面的例子:

Animal a = new Dog();	//用Dog子类创建了一个父类对象
Cat c = (Cat) a;		//报错,因为a根本不是Cat创建的

        为了防止强转报错,我们可以提前根据该父类对象的创建类型进行 if else 语句判断。此时就要用到新的关键字——instanceof。

  • instanceof 关键字:对象变量 instanceof 类名
    用于确定某个对象是否属于这个类,如果是,返回 true,如果不是,返回 false。
if(a instanceof Dog) {
	Dog d = (Dog) a;
	d.lookHome();
}else if(a instanceof Cat) {
	Cat c = (Cat) a;
	c.catchMouse();
}else{
	System.out.println("没有这个类型,无法转换");
}

        根据不同的类型进行强转,然后调用相应类型的特有的方法。
        到了 JDK14 ,Java 新添了一种写法,可以直接把判断和强转写在一行:

//如果“是”,强转成 Dog 类型,转换后变量命名为 d;如果“不是”,则不强转。
if(a instanceof Dog d) {
	d.lookHome();
//如果“是”,强转成 Cat 类型,转换后变量命名为 c;如果“不是”,则不强转。
}else if(a instanceof Cat c) {
	c.catchMouse();
}else{
	System.out.println("没有这个类型,无法转换");
}

        强制类型转换可以将多态父类转换成真正的子类类型,从而调用子类独有的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值