第八天(下) 多态

在现实事物,常常会有多态的体现,比如学生,是人.那么学生张三不仅是人,同时也是一个学生.即出现了两种状态.

Java作为面向对象的语言,也可以描述一个事物的两种状态,student继承person 一个student对象即是student也是person

Java中多态的代码体现在一个子类对象(实现类对象)既可以给这个子类(实现类对象)引用变量赋值,又可以给这个子类(实现类对象)的父类(接口)变量赋值。
    Student类可以为Person类的子类。那么一个Student对象既可以赋值给一个Student类型的引用,也可以赋值给一个Person类型的引用。
    最终多态体现为父类引用变量可以指向子类对象。

 

什么是多态:

多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作.

多态分类(这里好像有分歧)

多态一般分为两种:重写式多态和重载式多态。

重载式多态,也叫编译时多态。也就是说这种多态再编译时已经确定好了。重载大家都知道,方法名相同而参数列表不同的一组方法就是重载。在调用这种重载的方法时,通过传入不同的参数最后得到不同的结果。

重写式多态,也叫运行时多态。这种多态通过动态绑定(dynamic binding)技术来实现,是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。也就是说,只有程序运行起来,你才知道调用的是哪个子类的方法。 这种多态通过函数的重写以及向上转型来实现,我们上面代码中的例子就是一个完整的重写式多态。我们接下来讲的所有多态都是重写式多态,因为它才是面向对象编程中真正的多态。

多态的好处

可替换性多态对已存在代码具有可替换性。

可扩充性多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。

接口性

灵活性它在应用中体现了灵活多样的操作,提高了使用效率

简化性多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

多态实现的必要条件:

继承,重写,向上转型.(父类引用指向子类对象)

向上转型

当子类对象赋值给一个父类引用时,便是向上转型,多态本身就是向上转型的过程

使用格式:

父类类型  变量名 = new 子类类型();

如:Person p = new Student();

向上转型存在一些缺陷,那就是他必定会导致引用只能访问父类的变量和方法以及子类重写的方法,不能访问子类特有的方法

向下转型

一个已经向上转型的对象可以使用强制类型转换的格式,将父类引用转换为子类引用,这个过程就是向下转型.

使用格式:

子类类型 变量名 = (子类类型) 父类类型的变量;

:Student stu = (Student) p;  //变量p 实际上指向Student对象

 

java语言的多态机制导致了引用变量的声明类型和其实际引用对象的类型可能不一致,再结合虚方法调用规则可以得出结论:声明为同种类型的两个引用变量调用同一个方法时也可能会有不同的行为。这里就引入了instanceof运算符。

举个例子总不能把狗强制转换成人把

instanceof运算符

java 中的instanceof 是一个二元操作符(运算符)运算符,由于是字母组成,所以是Java的保留关键字,但是和>=,<=,==属同一类,它的作用是用来判断,instanceof 左边对象是否为instanceof 右边类的实例,返回一个boolean类型值。还可以用来判断子父类的所属关系。

用法boolean r = object instanceof class

如果 object 是 class 的一个实例,则 instanceof 运算符返回 true。如果 object 不是指定类的一个实例,或者 object 是 null,则返回 false。

if(p instanceof student) { student s=(student)p;}

 

 

什么时候用向上转型

当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作,这时候就可以使用向上转型

什么时候使用向下转型

要使用子类特有的功能时

转型时要先用instanceof进行判断

 

多态中的成员的特点

成员变量

编译时 参考父类中又没有这个变量,如果有编译成功

运行时 运行的是父类中的变量值

成员方法

编译时 参考父类中又没有这个方法,如果有就编译成功

运行时 运行时运行是子类的重写方法

多态的总结

指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态绑定)

实现多态的核心  动态绑定

动态绑定

动态绑定是指在执行期间半段所引用对象的实际类型,根据实际类型调用其相应的方法

多态调用的三种格式

* A:多态的定义格式:

* 就是父类的引用变量指向子类对象

 父类类型  变量名 = new 子类类型();

 变量名.方法名();


* B: 普通类多态定义的格式

父类 变量名 = new 子类();

举例:

class Fu {}
class Zi extends Fu {}
//类的多态使用
Fu f = new Zi();


* C: 抽象类多态定义格式

抽象类 变量名 = new 抽象类子类();

举例:

abstract class Fu {
         public abstract void method();
     }
class Zi extends Fu {
public void method(){
      System.out.println(“重写父类抽象方法”);
}
}
//类的多态使用
Fu fu= new Zi();


* D: 接口多态定义的格式

//接口 变量名 = new 接口实现类();
 interface Fu {
     public abstract void method();
}
class Zi implements Fu {
     public void method(){
              System.out.println(“重写接口抽象方法”);
}
}
//接口的多态使用
Fu fu = new Zi();


* E: 注意事项

同一个父类的方法会被不同的子类重写。在调用方法时,调用的为各个子类重写后的方法。

Person p1 = new Student();

   Person p2 = new Teacher();

   p1.work(); //p1会调用Student类中重写的work方法

   p2.work(); //p2会调用Teacher类中重写的work方法

当变量名指向不同的子类对象时,由于每个子类重写父类方法的内容不同,所以会调用不同的方法。

 

多态举例

 * A: 毕老师和毕姥爷的故事

 * 案例:

  /*

描述毕老师和毕姥爷,

毕老师拥有讲课和看电影功能

毕姥爷拥有讲课和钓鱼功能

  */

class 毕姥爷 {

void 讲课() {

System.out.println("政治");

}


void 钓鱼() {

System.out.println("钓鱼");

}

}


// 毕老师继承了毕姥爷,就有拥有了毕姥爷的讲课和钓鱼的功能,

// 但毕老师和毕姥爷的讲课内容不一样,因此毕老师要覆盖毕姥爷的讲课功能

class 毕老师 extends 毕姥爷 {

void 讲课() {

System.out.println("Java");

}


void 看电影() {

System.out.println("看电影");

}

}


public class Test {

public static void main(String[] args) {

// 多态形式

毕姥爷 a = new 毕老师(); // 向上转型

a.讲课(); // 这里表象是毕姥爷,其实真正讲课的仍然是毕老师,因此调用的也是毕老师的讲课功能

a.钓鱼(); // 这里表象是毕姥爷,但对象其实是毕老师,而毕老师继承了毕姥爷,即毕老师也具有钓鱼功能


// 当要调用毕老师特有的看电影功能时,就必须进行类型转换

毕老师 b = (毕老师) a; // 向下转型

b.看电影();

}


猜你喜欢

转载自blog.51cto.com/10760006/2156904