java知识3-----核心2-面向对象高级 续1--对象多态性

对象多态性

多态性在面向对象中是最重要的,在java中面向对象多态性主要有以下两种主要体现:
1,方法的重载与覆写;
2,对象的多态性;
面向对象三个特性:
封装,是为了保护类中的属性不被外部直接访问到;
继承,是为了扩展类的功能;
多态,方法的重载、覆写;对象的多态;
对象的多态性,主要分为向上转型和向下转型。
在这里插入图片描述

面向对象向上转型、向下转型

向上转型

向上转型:子类对象用父类接收;对于向上转型程序会自动完成;

父类 父类对象 = 子类实例;

向下转型:父类对象转为子类对象,对于向下转型必须明确指明要转型的子类类型。

子类 子类对象 = (子类)父类实例;
class A{					// 定义类A
	public void fun1(){		// 定义fun1()方法
		System.out.println("A --> public void fun1(){}") ;
	}
	public void fun2(){
		this.fun1() ;		// 调用fun1()方法
	}
};
class B extends A{
	public void fun1(){		// 此方法被子类覆写了
		System.out.println("B --> public void fun1(){}") ;
	}
	public void fun3(){
		System.out.println("B --> public void fun3(){}") ;
	}
};
public class PolDemo01{
	public static void main(String asrgs[]){
		B b = new B() ;		// 实例化子类对象
		b.fun1() ;			// 此方法被子类覆写过
	}
};

fun1()被子类覆写过,所以子类对象调用的时候,肯定是调用了覆写过的方法。
在这里插入图片描述

class A{					// 定义类A
	public void fun1(){		// 定义fun1()方法
		System.out.println("A --> public void fun1(){}") ;
	}
	public void fun2(){
		this.fun1() ;		// 调用fun1()方法
	}
};
class B extends A{
	public void fun1(){		// 此方法被子类覆写了
		System.out.println("B --> public void fun1(){}") ;
	}
	public void fun3(){
		System.out.println("B --> public void fun3(){}") ;
	}
};
public class PolDemo01{
	public static void main(String asrgs[]){
		B b = new B() ;		// 实例化子类对象
		A a = b ;			// 向上转型关系
		a.fun1() ;			// 此方法被子类覆写过
	}
};

进行向上转型,运行后可以发现,子类对象向上转型成父类对象后,调用的方法依然是子类覆写过的方法。
在这里插入图片描述

class A{					// 定义类A
	public void fun1(){		// 定义fun1()方法
		System.out.println("A --> public void fun1(){}") ;
	}
	public void fun2(){
		this.fun1() ;		// 调用fun1()方法
	}
};
class B extends A{
	public void fun1(){		// 此方法被子类覆写了
		System.out.println("B --> public void fun1(){}") ;
	}
	public void fun3(){
		System.out.println("B --> public void fun3(){}") ;
	}
};
public class PolDemo01{
	public static void main(String asrgs[]){
		B b = new B() ;		// 实例化子类对象
		A a = b ;			// 向上转型关系
		a.fun1() ;			// 此方法被子类覆写过
		a.fun2() ;
	}
};

调用父类的fun2()方法,fun2()中去调用的fun1()依然是子类覆写过的fun1()。
在这里插入图片描述
结论:
可以发现,通过子类进行父类对象的实例化操作,即对象发生向上转型之后,如果调用的方法被子类覆写过,则调用的肯定都是子类中覆写过的方法,但是当方法没有被覆写过,则调用的就是父类中继承过来的方法,也就是从父类中去找的方法。
注意点:
转型后,因为操作的是父类对象,所以是无法找到在子类中定义的新方法的。

class A{					// 定义类A
	public void fun1(){		// 定义fun1()方法
		System.out.println("A --> public void fun1(){}") ;
	}
	public void fun2(){
		this.fun1() ;		// 调用fun1()方法
	}
};
class B extends A{
	public void fun1(){		// 此方法被子类覆写了
		System.out.println("B --> public void fun1(){}") ;
	}
	public void fun3(){
		System.out.println("B --> public void fun3(){}") ;
	}
};
public class PolDemo01{
	public static void main(String asrgs[]){
		B b = new B() ;		// 实例化子类对象
		A a = b ;			// 向上转型关系
		a.fun1() ;			// 此方法被子类覆写过
		a.fun3() ;
	}
};

向上转型以后,找不到子类中定义的新方法。
在这里插入图片描述

向下转型

将父类对象变为子类对象,称为向下转型。向下转型需要采用强制的手段。

class A{					// 定义类A
	public void fun1(){		// 定义fun1()方法
		System.out.println("A --> public void fun1(){}") ;
	}
	public void fun2(){
		this.fun1() ;		// 调用fun1()方法
	}
};
class B extends A{
	public void fun1(){		// 此方法被子类覆写了
		System.out.println("B --> public void fun1(){}") ;
	}
	public void fun3(){
		System.out.println("B --> public void fun3(){}") ;
	}
};
public class PolDemo02{
	public static void main(String asrgs[]){
		A a = new B() ;			// 向上转型关系
		B b = (B)a ;		// 发生了向下转型关系
		b.fun1() ;
		b.fun2() ;
		b.fun3() ;
	}
};

类B中存在3个方法,所以都可以调用到。
在这里插入图片描述
在进行对象向下转型操作之前,有一股注意点:

class A{					// 定义类A
	public void fun1(){		// 定义fun1()方法
		System.out.println("A --> public void fun1(){}") ;
	}
	public void fun2(){
		this.fun1() ;		// 调用fun1()方法
	}
};
class B extends A{
	public void fun1(){		// 此方法被子类覆写了
		System.out.println("B --> public void fun1(){}") ;
	}
	public void fun3(){
		System.out.println("B --> public void fun3(){}") ;
	}
};
public class PolDemo03{
	public static void main(String asrgs[]){
		A a = new A() ;			// 实例化了一个父类对象
		B b = (B)a ;		// 发生了向下转型关系
		b.fun1() ;
		b.fun2() ;
		b.fun3() ;
	}
};

编译时候没有任何的语法问题,但是在执行的时候报错,一个既空指针异常之后的又一个非常经典的错误,类型转换异常:
在这里插入图片描述
此异常是在对象强转的时候会出现,如果两个没有关系的对象,发生转换关系则肯定出现此异常。
分析:
仅仅知道A类的情况下,并不知道谁是它的子类;
但是知道B类的情况下,就可以通过B extends A,知道B是A的子类,这样,就知道了A和B两个类是有关系的;
发生向下转型之前已经发生了向上转型,然后再进行了向下转型,才不会有任何问题;例如:A a = new B() ; B b = (B)a ;
当直接进行向下转型,肯定是会报类型转换异常的。比如:A a = new A() ; B b = (B)a ;

设计一个方法,可以接收A类的任意子类对象。

方案一:不使用对象多态性,使用重载实现:

class A{					// 定义类A
	public void fun1(){		// 定义fun1()方法
		System.out.println("A --> public void fun1(){}") ;
	}
	public void fun2(){
		this.fun1() ;		// 调用fun1()方法
	}
};
class B extends A{
	public void fun1(){		// 此方法被子类覆写了
		System.out.println("B --> public void fun1(){}") ;
	}
	public void fun3(){
		System.out.println("B --> public void fun3(){}") ;
	}
};
class C extends A{
	public void fun1(){		// 此方法被子类覆写了
		System.out.println("C --> public void fun1(){}") ;
	}
	public void fun5(){
		System.out.println("C --> public void fun5(){}") ;
	}
};
public class PolDemo04{
	public static void main(String asrgs[]){
		fun(new B()) ;	// 传递B的实例
		fun(new C()) ;	// 传递B的实例
	}
	public static void fun(B b){
		b.fun1() ;		// 调用覆写父类中的fun1()方法
	}
	public static void fun(C c){
		c.fun1() ;		// 调用覆写父类中的fun1()方法
	}
};

重载思路方案也是有局限性,没增加一个子类,fun()方法就得重载一次,如果有成百上千的子类的话,就得重载成百上千个方法了。
为了解决这样的局限性,就得使用对象多态性完成。
方案二:对象多态性实现:

class A{					// 定义类A
	public void fun1(){		// 定义fun1()方法
		System.out.println("A --> public void fun1(){}") ;
	}
	public void fun2(){
		this.fun1() ;		// 调用fun1()方法
	}
};
class B extends A{
	public void fun1(){		// 此方法被子类覆写了
		System.out.println("B --> public void fun1(){}") ;
	}
	public void fun3(){
		System.out.println("B --> public void fun3(){}") ;
	}
};
class C extends A{
	public void fun1(){		// 此方法被子类覆写了
		System.out.println("C --> public void fun1(){}") ;
	}
	public void fun5(){
		System.out.println("C --> public void fun5(){}") ;
	}
};
public class PolDemo05{
	public static void main(String asrgs[]){
		fun(new B()) ;	// 传递B的实例
		fun(new C()) ;	// 传递B的实例
	}
	public static void fun(A a){
		a.fun1() ;		// 调用覆写父类中的fun1()方法
	}
};

父类对象接收子类实例;这样,不管有多少个子类,都可以轻松完成,不用再重载方法。

面向对象转型的限制

向上转型:自动完成。
向下转型:强制手段进行,发生向下转型之前,必须先发生向上的转型关系。
对象多态性可以解决方法接收参数的问题。

instanceof

instanceof关键字的作用及使用时机

在java中可以使用instanceof关键字判断,一个对象是哪个类的实例。

对象 instanceof 类    ---> 返回一个boolean类型
class A{					// 定义类A
	public void fun1(){
		System.out.println("A --> public void fun1(){}") ;
	}
	public void fun2(){
		this.fun1() ;		// 调用fun1()方法
	}
};
class B extends A{
	public void fun1(){
		System.out.println("B --> public void fun1(){}") ;
	}
	public void fun3(){
		System.out.println("B --> public void fun3(){}") ;
	}
};
public class InstanceofDemo01{
	public static void main(String asrgs[]){
		A a1 = new B() ;
		System.out.println("A a1 = new B() " + (a1 instanceof A)) ;
		System.out.println("A a1 = new B() " + (a1 instanceof B)) ;
		A a2 = new A() ;
		System.out.println("A a2 = new A() " + (a2 instanceof A)) ;
		System.out.println("A a2 = new A() " + (a2 instanceof B)) ;
	}
};

在这里插入图片描述
a1是A的实例,也是B的实例;
a2是A的实例,但是并不是B的实例,所以a2是无法发生向下转型的,因为a2和类B是没有关系的。

使用instanceof对对象的转型进行安全验证

例子:
A类是父类,B是A的子类,C也是A的子类;判断,如果是B类则调用B类覆写过的fun1()方法后调用B类中新定义的fun3()方法;如果是C类则掉员工C类覆写过的fun1()方法然后调用C类中新定义的fun5()方法。
(对象发生向上转型以后,就相当于是父类对象了,对象只能调用子类覆写过的方法,对于子类中新定义的方法是无法访问到的)

class A{					// 定义类A
	public void fun1(){		// 定义fun1()方法
		System.out.println("A --> public void fun1(){}") ;
	}
	public void fun2(){
		this.fun1() ;		// 调用fun1()方法
	}
};
class B extends A{
	public void fun1(){		// 此方法被子类覆写了
		System.out.println("B --> public void fun1(){}") ;
	}
	public void fun3(){
		System.out.println("B --> public void fun3(){}") ;
	}
};
class C extends A{
	public void fun1(){		// 此方法被子类覆写了
		System.out.println("C --> public void fun1(){}") ;
	}
	public void fun5(){
		System.out.println("C --> public void fun5(){}") ;
	}
};
public class InstanceofDemo02{
	public static void main(String asrgs[]){
		fun(new B()) ;
		fun(new C()) ;
	}
	public static void fun(A a){
		a.fun1() ;
		if(a instanceof B){
			B b = (B) a ;
			b.fun3() ;
		}
		if(a instanceof C){
			C c = (C) a ;
			c.fun5() ;
		}
	}
};

在开发中对于向下转型,最好增加验证,保证转型时不发生ClassCastException。
如果现在增加A的这类,则就需要修改fun()方法,这样一来,程序就失去了灵活性和可维护性。问题出在哪里?父类的设计不合理,需要把父类重新设计,否则开发中会非常难以维护。

开发设计原则:
一个类永远不要去继承一个已经实现好的类,而是去继承抽象类或者实现接口。
父类一般都设计成抽象类或者接口。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值