[2014-3-14]JAVA筆記_多態(Polymophism)、instanceof關鍵字

一、什麼是多態?

         Polymorphism means “different forms.” In object-oriented programming, you have the same interface from the base class, and different forms using that interface: the different versions of the dynamically bound methods. (摘自thinking in java, Page217)  polymorphism (also called dynamic bindingor late bindingor run-time binding)

例子:多態,子類-->父類  向上轉型

public class PolyTest
{
	public static void main(String[] args)
	{
		//Parent parent = new Parent();
		//parent.sing();
		
		//Child child = new Child();
		//child.sing();

		Parent p = new Child();		//子類即父類
		p.sing();
	}
}

class Parent
{
	
	public void sing()
	{
		System.out.println("parent is singing");
	}
	
}

class Child extends Parent
{
	//public void sing(int i)	//重載
	public void sing()
	{
		System.out.println("child is singing");
	}
}
//Note:當申明父類型的引用去指向字類型的對象時,父類調用方法原則:第一,會去
//父類中查看是否有此方法,如果有繼續查找此方法是否有被子類繼承,如果繼承
//則繼續查找此方法是否覆寫,如果覆寫則調用覆寫的方法,如果沒有被覆寫則直接
//調用父類中的方法。第二,如果父類型的引用調用方法時此方法在父類中沒有定義,則直接會報錯,因爲什麼類型的引用就能調用什麼類型的方法。
//(與重載無關,如果子類重載了父類的方法,調用時任然是調用父類的方法,如果有
//被覆寫則調用覆寫的方法)

爲什麼要向上轉型?

 a) 可以保持父類不需要修改,只需要子類繼承父類,然後覆寫父類的方法。

 b)可以用父類型引用,接受子類型引用參數,這樣父類方法不需要改變,只需要增加子類即可。(詳見第二十講最後大約10分鐘)

public class PolyTest5
{
	/*
	public void runCar(BMW bmw)	//不使用多態:子類添加,方法也必須添加。
	{
		bmw.run();
	}

	public void runCar(QQ qq)	//傳的都是具體的車的類型。QQ不能接受BMW
	{
		qq.run();
	}
	*/

	//使用多態:無論子類增加多少類,父類方法不需要修改
	public void runCar(Car car)		//可接受car類型和car的子類類型
	{
		car.run();		
	}

	public static void main(String[] args)
	{
		/*
		 PolyTest5 test = new PolyTest5();

		BMW bmw = new BMW();

		test.runCar(bmw);

		QQ qq = new QQ();

		test.runCar(qq);
		*/
		
		PolyTest5 test = new PolyTest5();

		Car car = new BMW();	//通過多態自動向上轉換實現
		
		test.runCar(car);
		
		QQ qq = new QQ();

		test.runCar(qq);	//子類引用傳遞給父類方法接受。向上類型轉換


	}
}

class Car
{
	public void run()
	{
		System.out.println("car is running");
	}
}

class BMW extends Car
{
	public void run()
	{
		System.out.println("BMW is running");
	}
}

class QQ extends Car
{
	public void run()
	{
		System.out.println("QQ is running");
	}
}

//總結:多態屏蔽掉了子類之間的差異性,用一個公共父類方法標識我的接口(方法的參數)
//不管子類怎麼改變,只要增加的子類都繼承了這個父類,都可以作爲參數傳遞到我的這個
//方法裏。



多態的晚綁定:

//驗證晚綁定
public class PolyTest4
{
	public static void main(String[] args)
	{
		A a = null;

		if(args[0].equals("1"))
		{
			a = new B();	
		}
		else if(args[0].equals("2"))
		{
			a = new C();
		}
		else if(args[0].equals("3"))
		{
			a = new D();
		}

		a.method();
	}
}

class A
{
	public void method()
	{
		System.out.println("A");
	}
}

class B extends A
{
	public void method()
	{
		System.out.println("B");
	}
}

class C extends A
{
	public void method()
	{
		System.out.println("C");
	}
}

class D extends A
{
	public void method()
	{
		System.out.println("D");
	}
}

向下轉型:

例子:多態,父類-->子類, 向下轉型

public class PolyTest2
{
	public static  void main(String[] args)
	{
		/*
		Animal animal = new Cat();
		Animal animal2 = new Animal();

		animal2 = animal;
		animal2.sing();
		*/
		
		/*
		Animal animal = new Cat();
		Animal animal2 = new Animal();

		animal = animal2;
		animal.sing();
		*/

		/*
		Cat cat = new Cat();
		Animal animal = cat;
		animal.sing();
		*/
		
		
		Animal animal = new Animal();
		Cat cat =new Animal();
		

	/*	//向上類型轉換
		Cat cat = new Cat();

		Animal animal = cat;

		animal.sing();

		//向下類型轉換
		Animal a = new Cat();

		Cat c = (Cat)a;		//向下轉換的原則是:a實際指向的是什麼,就可以把它轉換成什麼類型的引用

		c.sing();
	*/
	}
}

class Animal
{
	public void sing()
	{
		System.out.println("animal is singing");
	}
}

class Dog extends Animal
{
	public void sing()
	{
		System.out.println("dog is singing");
	}
}

class Cat extends Animal
{
	public void sing()
	{
		System.out.println("cat is singing");
	}
}

爲什麼要使用向下轉換?

例子:

public class PolyTest3
{
	public static void main(String[] args)
	{
		//Fruit f = new Pear();
		//f.run();
		
		//Pear p = (Pear)f;
		//p.run();
		
		//Fruit f = new Pear();
		//f.grow();

		Fruit f = new Pear();

		Pear p = (Pear)f;
		
		p.grow();

	}
}

class Fruit
{
	public void run()
	{
		System.out.println("fruit is running");
	}
}

class Pear extends Fruit
{
	public void run()
	{
		System.out.println("pear is running");
	}

	public void grow()
	{
		System.out.println("pear is growing");
	}
}

總結:子類裏面新增了自己的方法時,父類引用需要調用子類方法此時就需要向下轉型。將父類引用類型轉型爲子類引用類型,因爲什麼類型的引用就能指向什麼類型的對象。





1. JAVA中面向對象主要有兩種提現:

(1) 方法的重載與覆寫。

(2) 對象的多態性。

對象的多態性主要分爲以下兩種類型:

(1) 向上轉型:子類對象——>父類對象。

(2) 向下轉型: 父類對象——>子類對象。

對於向上轉型,程序會自動完成,而對於向下轉型時,必須明確地指明要轉型的子類類型。

【格式 對象轉型】

對象向上轉型: 父類 父類對象 = 子類實例;

對象向下轉型: 子類 子類對象 = (子類)父類實例;

範例:對象的向上轉型

//對象的向上轉型
class A{					//定義類A
	public void fun1(){
		System.out.println("A --> public void fun1(){}");
	}
	public void fun2(){
		this.fun1();
	}
};
class B extends A{				//子類通過extends繼承父類
	public void fun1(){			//覆寫父類中的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 []args){
		B b = new B();			//定義子類實例化對象
		A a = b;				//發生了向上轉型的關係,子類 --> 父類
		a.fun1();				//此方法被子類覆寫過
	}
}
//總結:如果對象發生了向上轉型關係後,所調用的方法一定是被子類覆寫過的方法。
程序運行結果:

B --> public void fun1(){}


此時的對象a是無法調用B類中的fun3()方法的,因爲此方法只在子類定義,而沒有在父類中定義,如果想要調用子類自己的方法,則肯定要使用子類實例,所以此時可以將對象進行向下轉型。

//對象的向下轉型
class A{					//定義類A
	public void fun1(){
		System.out.println("A --> public void fun1(){}");
	}
	public void fun2(){
		this.fun1();
	}
};
class B extends A{				//子類通過extends繼承父類
	public void fun1(){			//覆寫父類中的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 []args){
		A a = new B();			//發生了向上轉型的關係,子類-->父類
		B b = (B)a;				//此時發生了向下轉型關係
		b.fun1();				//調用方法被覆寫的方法
		b.fun2();				//調用父類的方法
		b.fun3();				//調用子類自己定義的方法
	}
}

程序運行結果:

B --> public void fun1(){}
B --> public void fun1(){}
B --> public void fun3(){}

總結:如果想要調用子類自己的方法,則一定只能用子類聲明對象,另外,在子類中調用了父類中的fun2()方法,fun2()方法要調用fun1()方法,但此時fun1()方法已經被子類所覆寫,所以,此時調用的方法是被子類覆寫過的方法。


注意: 對象向下轉型的要求

在進行對象的向下轉型前,必須首先發生對象向上轉型,否則將出現對象轉換異常

//錯誤的轉型
class A{					//定義類A
	public void fun1(){
		System.out.println("A --> public void fun1(){}");
	}
	public void fun2(){
		this.fun1();
	}
};
class B extends A{				//子類通過extends繼承父類
	public void fun1(){			//覆寫父類中的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 []args){
		A a = new A();			//此時聲明的是父類對象。父對象並不知道誰是子對象
		B b = (B)a;				//此時發生了向下轉型關係
		b.fun1();				//調用方法被覆寫的方法
		b.fun2();				//調用父類的方法
		b.fun3();				//調用子類自己定義的方法
	}
}
由以上程序可以發現,此時的A類對象是由A類本身進行實例化的,然後將A類的實例化對象強制轉換爲子對象,這樣寫在語法上是沒有任何錯誤的,但是在運行時出現了異常,因爲此時父類用其本身類實例化自己的對象,但它並不知道誰是自己的子類,那肯定在轉換時會出現錯誤。只需要將連個對象建立好關係即可解決此我呢提,在聲明父類對象時發生向上轉型關係“A a = new B();”,這時相當於是由子類去實例化父類對象,也就是說這時父類知道有這麼一個子類,所以下面在進行轉換時就不會再有問題。


2. instanceof 關鍵字:判斷某個對象是否是某個類的實例。

語法形式: 引用名  instanceof  類名(接口名),返回 boolean  值。


//Instanceof 關鍵字作用
public class InstanceofTest{
	public static void main(String args[]){

		People people = new Man();

		System.out.println(people instanceof People);

		//因爲 Man 是 People 的子類,根據繼承,子類就是父類,
		//因此 Man 也可以看作是 People 的實例。
	}
}

class People{};
class Man extends People{};


//使用instanceof判斷一個對象屬於那個類的實例
class A{					//定義類A
	public void fun1(){
		System.out.println("A --> public void fun1(){}");
	}
	public void fun2(){
		this.fun1();
	}
};
class B extends A{				//子類通過extends繼承父類
	public void fun1(){			//覆寫父類中的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 []args){
		A a1 = new B();				//通過向上轉型實例化A類對象
		System.out.println("A a1 = new B():" + (a1 instanceof A));
		System.out.println("A a1 = new B():" + (a1 instanceof B));
		A a2 = new A();				//通過A類的構造實例化本類對象
		System.out.println("A a2 = new A():" + (a2 instanceof A));
		System.out.println("A a2 = new A():" + (a2 instanceof B));
	}
}
//通過子類實例化的對象同時是子類和父類的實例
程序運行結果:

A a1 = new B():true
A a1 = new B():true
A a2 = new A():true
A a2 = new A():false

//在向下轉型前進行驗證
class A{					//定義類A
	public void fun1(){
		System.out.println("A --> public void fun1(){}");
	}
	public void fun2(){
		this.fun1();
	}
};
class B extends A{				//子類通過extends繼承父類
	public void fun1(){			//覆寫父類中的fun1()方法
		System.out.println("B --> public void fun1(){}");
	}
	public void fun3(){			//子類自己定義的方法
		System.out.println("B --> public void fun3(){}");
	}
};
class C extends A{				//子類通過extends繼承父類
	public void fun1(){			//覆寫父類中的fun1()方法
		System.out.println("C --> public void fun1(){}");
	}
	public void fun5(){			//子類自己定義的方法
		System.out.println("C --> public void fun3(){}");
	}
};
public class InstanceofDemo02{
	public static void main(String []args){
		fun(new B());			//傳遞B類實例,產生向上轉型
		fun(new C());			//傳遞C類實例,產生向上轉型
	}
	public static void fun(A a){	//此方法可以分別調用各自子類單獨定義的方法
		a.fun1();
		if(a instanceof B){			//判斷是否是B類實例
			B b = (B)a;				//進行向下轉型
			b.fun3();				//調用子類自己定義的方法
		}
		if(a instanceof C){			//判斷是否是C類實例
			C c = (C)a;				//進行向下轉型
			c.fun5();				//調用子類自己定義的方法
		}
	}
}
程序運行結果:

B --> public void fun1(){}
B --> public void fun3(){}
C --> public void fun1(){}
C --> public void fun3(){}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章