Java基础--多态

多态

Java引用变量有两种类型:编译时类型、运行时类型。

编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。对于如下代码,f 的编译时类型就是 Father 类型,运行时类型是 Son 类型。

Father f = new Son();

如果编译时类型和运行时类型不一致,就有可能出现所谓的多态性。

  • 多态的优点

    • 提高了代码的维护性(继承保证)
    • 提高了代码的扩展性(多态保证)

多态前提和演示

多态的前提条件
  1. 要有继承关系;

  2. 要有方法重写;

  3. 要有父类引用指向子类对象。

多态的代码演示
	// 示例代码01

	class Father {
	    public int age = 40;
	
	    public void base(){
	        System.out.println("父类自己的方法");
	    }
	
	    public void test(){
	        System.out.println("父类要被覆盖的方法");
	    }
	
	}
			
	public class Son extends Father {
	
	    public String age = "今年6岁啦";
	
	    public void test(){
	        System.out.println("子类覆盖了父类的方法");
	    }
	
	    public void self(){
	        System.out.println("子类自己的方法");
	    }
	
	    public static void main(String[] args){
	        // 编译时类型和运行时类型不同,将发生多态特征
			Father f = new Son();
	
			// 将访问父类的实例变量
	        System.out.println(f.age);
	        // 将调用从父类继承到的base()方法
			f.base();
			// 将调用子类重写的test()方法
	        f.test();
	        // 因为变量f编译时的类型是Father,但Father类没有提供self()方法,所以下面的代码编译时会出错
	        // f.self();
	    }
	}

分析: 当把一个子类对象直接赋值给父类引用变量时,正如上面的 Father f = new Son();,这个 f 引用变量的编译时类型是 Father,而运行时类型是 Son,当运行时调用该引用变量的方法时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征。这就出现:相同类型的变量、调用同一方法时呈现出多种不同的行为特征,这就是多态。

多态特点总结

通过引用变量来访问其包含的实例变量时,系统总是试图访问它编译时类型所定义的成员变量,而不是它运行时类型所定义的成员变量。

引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法。

可以从三个方面简记多态的特点。对于类似下面的代码:

Father f = new Son();
  1. 访问成员变量:
    编译看左边,运行看左边。

  2. 访问非静态成员方法:
    编译看左边,运行看右边。(动态绑定)

  3. 访问静态成员方法:
    编译看左边,运行看右边。(静态和类相关,算不上是重写。所以访问还是看左边)

引用变量的强制类型转换

在编写Java程序时,引用变量只能调用它编译时类型的方法,而不能调用它运行时类型的方法,即使它实际所引用的对象的确包含该方法。

如果需要让这个引用变量调用它运行时类型的方法,则必须把它强制类型转换成运行时类型。

强制类型转换简单示范

强制类型转换的需求体现在 “示例代码01” 的如下片段:

// 因为变量f编译时的类型是Father,但Father类没有提供self()方法,所以下面的代码编译时会出错
// f.self(); 

想要调用子类的 self()方法,需要将 f 进行强制类型转换,如下代码即可实现调用子类的 self() 方法:

// 强制类型转换
Son s = (Son) f;
s.self();
借助instanceof运算符进行强制类型转换

instanceof 运算符用于判断前面的对象是否是后面的类、子类或是实现类的实例。如果是则返回 true,否则返回 false。

instanceof 运算符在强制类型转换中的作用是:在进行强制类型转换之前,首先判断前一个对象是否是后一个类的实例,是否可以成功转换,从而保证代码的健壮性。

对于如下代码:

// 强制类型转换
Son s = (Son) f;
s.self();

如果不确定 Son 类和 Father 类的关系,直接进行强制类型转换,可能会出现 ClassCastException 异常,使用 instanceof运算符可以让强制类型转换更加安全。

// 更加安全的强制类型转换
if( f instanceof Son)
{
	Son s = (Son) f;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值