22.多态

上一篇:21.接口



一.什么是多态

以下将用一个父类Animal、两个子类:Cat、Dog以及一个测试类说明。

public class Animal {
	void howl(){
		System.out.println("动物在嚎叫!");
	}
}

public class Cat extends Animal{
	@Override
	void howl() {
		System.out.println("cat正在喵喵叫!");
	}
	
	void name() {
		System.out.println("cat的名字叫做喵喵");
	}

}
public class Dog extends Animal{
	@Override
	void howl() {
		System.out.println("dog正在汪汪叫!");
	}
}

测试类:

public class Test {

	public static void main(String[] args) {
		Animal animal1 = new Cat();
		animal1.howl();
		// cat正在喵喵叫!
		
		// animal1.name;
		
		Animal animal2 = new Dog();
		animal2.howl();
		// dog正在汪汪叫
	}

}

当使用多态方式调用时,首先检查父类中是否有该方法,如果没有就会编译错误;例如:

animal1.name;//父类方法中没有该方法,编译错误

如果有,再去调用子类的同名方法。例如:

Animal animal1 = new Cat();
animal1.howl();

此时编译时类型和运行时类型不一致,就会出现多态;简而言之地讲:多态即多种形态、状态。

(一).实现条件

Java实现多态的必要条件:继承、重写。

(二).实现基础

父类声明的变量可以引用所有子类的对象,这是多态实现的基础。
我们只有在运行的时候才会知道引用变量所指向的具体实例对象。

(三).多态作用

把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。简单地说:就是父类或接口的引用变量指向子类的对象。

(四).总结

在涉及多态的编程中,请注意以下细节:

1.静态方法

静态方法不能被重写,所以静态方法也没有多态性。

2.成员变量

成员变量不具备多态性。成员变量的值取决于引用所属的类。

3.成员方法

编译时:检查引用变量所属类中是否有所调的方法。
运行时:调用实际对象所属类中的重写方法。


二.多态的转型

在基本数据类型的转换中我们已经认识了数据类型的转换,那么在多态当中实际上也有父类与子类之间的转换。
Animal类和Dog类:

public class Animal {
	void howl() {
		System.out.println("Animal.howl()");
	} 
}

public class Dog extends Animal{
	@Override
	void howl() {
		System.out.println("Dog.howl()");
	}
	
	void eatBone() {
		System.out.println("Dog.eatBone()");
	}

}

(一).向上转型 upcasting

向上转型就是子类转父类,这是由系统来自动完成的;例如:

public class Test {

	public static void main(String[] args) {
		// 向上转型
		Animal animal = new Dog();
		animal.howl();// Dog.howl()
		
		// animal.eatBone();
		// The method eatBone() is undefined for the type Anima
	}

}

一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那就不能再访问子类中特有的属性和方法。

(二).向下转型 downcasting

向下转型就是父类转子类,此时需要使用强制类型转换符()。
例如:

public class Test1 {

	public static void main(String[] args) {
		// 向下转型
		Animal animal = new Dog();	
		Dog dog = (Dog) animal;
		dog.howl();
		dog.eatBone();
	}

}

在类型转换时,请注意:
1.弄清楚继承关系,谁是父类谁是子类;
2.在创建对象时调用的是谁的构造函数。


三.instanceof

(一).引入

在多态编程中可以通过instanceof判断对象到底属于哪个确切的类型。
示例:

public class Animal {
	void howl() {
		System.out.println("动物都会嚎叫");
	}

}
public class Cat extends Animal{
	@Override
	void howl() {
		System.out.println("Cat正在喵喵叫");
	}

}
public class Dog extends Animal{
	@Override
	void howl() {
		System.out.println("Dog正在汪汪叫");
	}

}

测试类:

public class Test {

	public static void main(String[] args) {
		Animal animal = new Cat();
		Cat cat = (Cat) animal;
		// 当我们不确定对象属于哪个类时,可以使用instanceof进行判断
		boolean res = cat instanceof Cat;
		System.out.println(res);// true
		
		res = cat instanceof Animal;
		System.out.println(res);// true
		
		// 由子类构造函数创建的对象,对象既属于子类,也属于父类
		Dog dog = new Dog();
		res = dog instanceof Dog;
		System.out.println(res);//true
		
		res = dog instanceof Animal;
		System.out.println(res);//true
		
		// 由父类构造函数创建的对象,不属于子类
		Animal animal1 = new Animal();
		res = animal1 instanceof Dog;
		System.out.println(res);// false
	}

}

(二).实际应用

public class Test {

	public static void main(String[] args) {
		Animal animal1 = new Cat();
		Cat cat = (Cat) animal1;
		checkType(cat); // Cat正在喵喵叫

		Dog dog = new Dog();
		checkType(dog); // Dog正在汪汪叫

	}

	public static void checkType(Animal animal) {
		if (animal instanceof Cat) {
			Cat cat = new Cat();
			cat.howl();
		}

		if (animal instanceof Dog) {
			Dog dog = new Dog();
			dog.howl();
		}

	}
}


四.多态应用场景

(一).基于继承的多态

多个子类对同一父类方法的重写,可以在运行时表现出不同的行为。

(二).基于接口的多态

一个接口可以有多个实现类。所以,多个实现类对接口中同一方法的重写,可以在运行时表现出不同的行为。

语法:

接口名 变量名 = new 类名()

注意:命名规范——>实现类为 接口名+impl。
例如:

public interface MyInterface {

}
public class MyInterfaceImpl1 implements MyInterface{

}

public class MyInterfaceImpl2 implements MyInterface {

}
public class Test1 {

	public static void main(String[] args) {

		MyInterfaceImpl1 impl1 = new MyInterfaceImpl1();
		MyInterface test1 = test1(impl1);
		MyInterface myInterface =new MyInterfaceImpl2();
		MyInterface test2 = test2(myInterface);
		
	}

	
	// 返回接口
	public static MyInterface test1(MyInterface myInterface) {
		MyInterfaceImpl1 impl1=new MyInterfaceImpl1();
		
		return impl1;
	}
	public static MyInterface test2(MyInterface myInterface) {
		MyInterfaceImpl2 impl2=new MyInterfaceImpl2();
		return impl2;
	}
	

}

(三).函数输入参数的多态

多态可以作为形参,接受范围更广的对象,接收的参数更加灵活。

(四).函数返回值的多态

多态可以作为返回值,接受范围更广的对象。

public  父类  方法名(){
	return 父类对象;
	return 子类对象;
}

下一篇:23.内部类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值