[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(){}





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