【Java】多态的理解与使用

理解多态思想

学了继承关系,我们知道继承关系是一种”is A”的关系,也就说子类是父类的一种特殊情况;
问题: 子类的对象是动物?
既然子类是一种特殊的父类,那么我们可不可以认为狗对象/猫对象就是动物类型的对象.

Class Animal{};//动物类	
Class Dog extends Animal{};//狗类	
Class Cat extends Animal{}//猫类
Animal a = new Dog();
Animal b = new Cat();

当编译类型和运行类型不同的时候,多态就产生了;

对象有两种类型

(1)编译类型:声明变量的类型,Animal,表示把对象看做什么类型。

(2)运行类型:对象的真实类型。

编译类型必须是运行类型的父类/或相同;

所谓多态:对象有多种形态,对象可以存在不同的形式;

Animal a = null;
a = new Dog();	 //a此时表示Dog类型的形态
a = new Cat(); 	 //a此时表示Cat类型的形态

多态的前提:

1.可以是继承关系(类和类)

2.也可以是实现关系(接口和实现类)

在开发中多态一般都指第二种。

多态的特点:把子类对象赋给父类变量,在运行时期会表现出具体的子类特征(调用子类的方法).

多态的好处

需求:给饲养员提供一个饲养动物的方法,用于喂养动物的方法,用于喂养动物。

没有多态:针对于不同的动物,我们得提供不同的feed方法来喂养。代码如下:

class Person
{
	public void feed(Dog g){
		System.out.println("开始喂食");
		g.feed();
	}

	public void feed(Cat c){
		System.out.println("开始喂食");
		c.feed();
	}
	
}

class Animal
{

}

class Dog extends Animal
{
	public void feed(){
	
		System.out.println("小狗吃骨头");
	}
}

class Cat extends Animal
{
	public void feed(){
	
		System.out.println("小花猫吃鱼");
	}

}

class PolymorphicDemo
{
	public static void main(String[] args) 
	{
		Person p = new Person();
		Dog d = new Dog();
		Cat c = new Cat();
		p.feed(d); // 喂狗
		p.feed(c); // 喂猫
	}
}

存在多态:统一了喂养动物的行为。代码如下:

class Person
{
	public void feed(Animal a){
		System.out.println("开始喂食");
		a.feed();
	}
}

class Animal
{
	public void feed(){	
		System.out.println("小宠物都爱吃食物");
	}
}

class Dog extends Animal
{
	public void feed(){
	
		System.out.println("小狗吃骨头");
	}
}

class Cat extends Animal
{
	public void feed(){
	
		System.out.println("小花猫吃鱼");
	}
}

class PolymorphicDemo
{
	public static void main(String[] args) 
	{
		Person p = new Person();
		Animal d = new Dog(); 
		Animal c = new Cat();
		p.feed(d); // 喂狗
		p.feed(c); // 喂猫
	}
}

从上述例子,可以得知多态的作用:把不同的子类对象当做父类类型来看待,可以屏蔽不同子类对象之间的差异,从而写出通用的代码达到编程,以适应需求的不断变化。

多态时的方法调用

多态时方法的调用问题:
前提:必须存在多态情况;
如下几种情况的代码:存在父类SuperClass,子类SubClass,方法doWork

情况1:doWork方法存在于SuperClass(父类)中,不存在SubClass(子类)中。

// 定义父类
class SuperClass
{
	public void dowork(){
	
		System.out.println("SuperClass");
	}
}

// 定义子类
class SubClass extends SuperClass
{
}
class PolymorphicDemo2 
{
	public static void main(String[] args) 
	{
		SuperClass sub = new SubClass(); // 多态
		sub.dowork(); // SuperClass
	}
}
---------- 运行java ----------
SuperClass

输出完成 (耗时 0) - 正常终止

执行结果:编译通过,执行SuperClass的doWork方法。
从SubClass中去找doWork方法,找不到,再去父类SuperClass中去找。

情况2:doWork方法存在于SubClass(子类)中,不存在SuperClass(父类)中。

// 定义父类
class SuperClass
{
}

// 定义子类
class SubClass extends SuperClass
{
	public void dowork(){	
		System.out.println("SubClass");
	}
}

class PolymorphicDemo2 
{
	public static void main(String[] args) 
	{
		SuperClass sub = new SubClass(); // 创建子类对象
		sub.dowork(); // 编译报错
	}
}
---------- 编译java ----------
PolymorphicDemo2.java:22: 错误: 找不到符号
		sub.dowork(); // SuperClass
		   ^
  符号:   方法 dowork()
  位置: 类型为SuperClass的变量 sub
1 个错误

输出完成 (耗时 0) - 正常终止

此时的执行结果:编译错误:
编译时期:会去编译类型(SuperClass)类中去寻找doWork方法,但是找不到。除非找到,编译才能通过。

情况3:doWork方法公同存在于SubClass(子类)和SuperClass(父类)中。

// 定义父类
class SuperClass
{
	public void dowork(){	
		System.out.println("SuperClass");
	}
}

// 定义子类
class SubClass extends SuperClass
{
	public void dowork(){	
		System.out.println("SubClass");
	}
}
class PolymorphicDemo2 
{
	public static void main(String[] args) 
	{
		SuperClass sub = new SubClass(); // 多态
		sub.dowork();  
	}
}
---------- 运行java ----------
SubClass

输出完成 (耗时 0) - 正常终止

此时执行结果:编译通过,执行SubClass的doWork方法。因为子类继承了父类,覆盖了dowork方法,子类对象赋给父类变量,在运行时期会表现出具体的子类特征(调用子类的方法)。

情况4:doWork方法公同存在于SubClass(子类)和SuperClass(父类)中,但是doWork是static修饰的静态方法,此时这种情况我们称为隐藏,而不是覆盖。

// 定义父类
class SuperClass
{
	public static void dowork(){	
		System.out.println("SuperClass");
	}
}
// 定义子类
class SubClass extends SuperClass
{
	// 这里的dowork方法使用了static修饰,因此这里的dowork与父类中的dowork不再是覆盖,而是隐藏关系
	public static void dowork(){
		System.out.println("SubClass");
	}
}
class PolymorphicDemo2 
{
	public static void main(String[] args) 
	{
		SuperClass sub = new SubClass(); // 多态
		sub.dowork();  
	}
}
---------- 运行java ----------
SuperClass

输出完成 (耗时 0) - 正常终止

此时执行结果:编译通过,执行SuperClass的doWork方法。

上述代码包含了隐藏现象

满足继承的访问权限下,隐藏父类静态方法:若子类定义的静态方法的签名和父类中的静态方法的签名相同,那么此时就是隐藏父类的方法。注意:仅仅是静态方法。

在父类和子类中都存在了一个static修饰的dowork方法,这里的dowork是隐藏的概念,而不是覆盖 !

总结:

子类中和父类的dowork方法使用了static修饰,因此子类的dowork与父类中的dowork不再是覆盖,而是隐藏关系;

静态方法的调用只需要类即可。

虽然我们的代码,使用的是sub对象来调用的dowork方法,

	SuperClass sub = new SubClass(); // 多态
	sub.dowork();  

下图是反编译后的代码,可以看到,在编译时,并没有使用对象去调用,而是用的父类类名去调用的。
在这里插入图片描述
因此,如果使用对象来调用静态方法,其实使用的是对象的编译类型来调用静态方法,和对象没有关系。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值