您的位置:首页 > 编程语言 > Java开发

[2014-3-14]JAVA笔记_多态(Polymophism)、instanceof关键字

2014-03-14 14:26 309 查看
一、什么是多态?

         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(){}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  多态 polymorphism