Java初学之中的多态

多态

为了理解多态,我们首先新建三个类——Mammal(哺乳类),Whale(鲸鱼类),Earth(地球类)。

public class Mammal{

	 public void move(){  
			System.out.println("奔跑"); 
	   }
}
public class Whale extends Mammal{
     @Override
	 public void move(){  
			System.out.println("用鳍游动"); 
	   }
}

public class Earth {

	public static void main(String[] args) {
		Whale whale = new Whale();
		whale.move();////当子类对象调用重写后的方法时,调用的是子类重写后的方法
    }
}

 对于Earth类中的whale对象而言,当子类对象调用重写之后的方法时,调用的是子类重写之后的方法,显而易见

​

public class Earth {

	public static void main(String[] args) {
		Whale whale = new Whale();
		whale.move();////当子类对象调用重写后的方法时,调用的是子类重写后的方法
        double price = 9;
		Mammal mammal = new Whale();//自动类型转换:父类类型的变量指向其子类创建的对象 对象上转型  new Whale()上转型对象
		
    }
}

​

首先让我们来看double price=9;这行代码,我们知道double是双精度浮点型,9是整形值,毫无疑问小于double的范围,这个时候系统自动的把9的范围上调,变成double类型的值。

同理——

父类类型(比如Mammal)的变量(比如mammal1)指向子类创建的对象,使用该变量调用父类中一个被子类重写的方法(比如move方法),则父类中的方法呈现出不同的行为特征,这就是多态。

Java引用变量有两种类型,分别是编译时类型运行时类型:编译时类型由声明该变量时使用的类型决定;运行时类型由实际赋给该变量的对象。如果编译时类型和运行时类型不一致,就可能出现所谓多态。

其中mammal被称为上转型对象。

​

public class Earth {

	public static void main(String[] args) {
		Whale whale = new Whale();
		whale.move();////当子类对象调用重写后的方法时,调用的是子类重写后的方法
        double price = 9;
		Mammal mammal = new Whale();//自动类型转换:父类类型的变量指向其子类创建的对象 对象上转型  new Whale()上转型对象

		mammal.move();//两个状态:表面调用的是父类的方法;但是执行时由于mammal存的是子类创建的对象,所以执行时执行的是子类中的方法
		
		//如果编译时类型和运行时类型相同,则一定不会出现多态;√
		//如果编译时类型与运行时类型不相同,则一定出现多态x
		
    }
}

如果子类Whale中新增了breath方法,则在Earth类之中添加mammal.breath();会报错,因为——

上转型对象不能调用子类新增的方法 和新增加的属性。  

上例分析:当把子类创建的对象直接赋给父类引用类型时,例如上例Test main方法中“Mammal mammal1 = new Whale();”, mammal1引用变量的编译时类型是Mammal,运行时类型是Whale,当程序运行时,该引用变量mammal1调用父类中被子类重写的方法时,其方法行为表现的是子类重写该方法后的行为特征,而不是父类方法的行为特征。

总结,在编译时只会加载父类,运行则是运行子类,在子类之中新增的变量和方法父类之中显然没有,因此加载时就会出现错误,因为只加载父类,无法找到新增的子类变量和方法,甚至包括子类之中本来就有的方法和变量,如果父类之中没有相同名称的同样存在,也会报错,因为代码的左边是编译时类型只会加载父类,不会动子类。

上转对象调用父类方法,如果该方法已被子类重写,则表现子类重写后的行为特征,否则表现父类的行为特征。

使用上转型对象调用成员变量,无论该成员变量是否已经被子类覆盖,使用的都是父类中的成员变量:

如果编译时类型和运行时类型不一致时未必会出现所谓多态,如下例子:

下转型对象

//问题:在上转型对象中如何实现调用子类新增的方法 和新增加的属性   对象下转型
		//int price = (int)9.0
//		Whale whale = (Whale)mammal;

 和强制类型转换类似,我们可以将mammal强制转换成Whale类。

但是——下转型的前提是先出现上转型对象。

Mammal mammal = new Mammal();//下转型的前提是先出现上转型对象
//		Whale whale = (Whale)mammal;
		
//		System.out.println(new Whale().weight);
//		Mammal mammal = new Whale();
//		System.out.println(mammal.weight);
		
		
		//在多态的前提下,父类中被子类重写的方法没有必要有方法体
		Mammal mammal = new Whale();//自动类型转换:父类类型的变量指向其子类创建的对象 对象上转型  new Whale()上转型对象
		
		mammal.move();

可以将上转型对象再强制转换为创建该对象的子类类型的对象,即将上转型对象还原为子类对象,对应于数据类型转换中的强制类型转换。

还原后的对象又具备了子类所有属性和功能,即可以操作子类中继承或增的成员变量,可以调用子类中继承或增的方法。

注意:不可以将父类创建的对象通过强制类型转换赋值给子类声明的变量。

发散思考

如果子类对于父类的方法重写,我们有需要的是子类,那么父类的方法体是否还有存在的必要?

即我们只需要whale类的move方法,mammal的move方法我们根本用不上,那么显然,mammal的move方法体有没有都一个样。

即在mammal类中舍弃方法体——

public abstract void move(){  
			
	   }

这时,必须要在move方法前加上abstract修饰词,表明这时一个抽象方法。

如果一个类里面只要有一个抽象方法,那么这个类就是抽象类。

public abstract class Mammal {
	public abstract void move(){  
			
	   }
}

极端假设——

如果一个抽象类中的所有方法都是抽象方法,那么这个抽象类就是接口(interface).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值