多态性是面向对象的最后一个主要特征,主要有两个方面:方法的多态性,对象的多态性.
1.方法的多态性:
①重载:同一个方法名称,根据不同的参数类型及个数完成不同的功能.
②覆写:同一个方法,根据操作的子类不同,所完成的功能也不同.
2.对象的多态性:
①向上转型:子类对象变为父类对象,格式如下:
父类 父类对象 = 子类实例
②向下转型:父类对象变为子类对象,格式如下:
子类 子类对象 = (子类) 父类实例 //强制转换
范例1,向上转型:
class A{
public void print(){
System.out.println("A.public void print(){}") ;
}
}
class B extends A{
public void print(){
System.out.println("B.public void print(){}") ;
}
}
public class Demo{
public static void main(String args[]){
A a = new B() ;
a.print() ;
}
}
运行结果:
以上程序实现了一个对象的向上转型操作,虽然最后调用print()方法的是A类对象,但是由于此时实例化的是子类对象"new B()",而且print()方法被子类覆写了,所以最终调用的就是被B类覆写过的print()方法.
范例2,向下转型:
class A{
public void print(){
System.out.println("A.public void print(){}") ;
}
}
class B extends A{
public void print(){
System.out.println("B.public void print(){}") ;
}
}
public class Demo{
public static void main(String args[]){
A a = new B() ; //向上转型
B b = (B) a ; //向下转型
b.print() ;
}
}
运行结果:
本程序强制将父类对象变为子类对象,由于本程序在开始实例化的依然是子类对象(new B()),所以最终调用的print()方法依然是被子类覆写过的方法.
范例3:
class A{
public void print(){
System.out.println("A.public void print(){}") ;
}
}
class B extends A{
public void print(){
System.out.println("B.public void print(){}") ;
}
}
public class Demo{
public static void main(String args[]){
A a = new A() ; //没有转型
B b = (B) a ; //向下转型
b.print() ;
}
}
运行结果:
以上程序在编译时没有任何错误信息,但在实行时出现了"ClassCastException"错误提示,表示的是类转换异常,即两个没有关系的类相互发生了对象的强制转型.(当我们只看A类时,并不知道谁是其子类,但是如果看B类时可以得出它的父类的,在范例2中,通过A a = new B()使A知道了它的子类是B,)由此可得:当对象发生向下转型关系前,一定要首先发生对象的向上转型关系.
既然在发生向下转型的操作中会存在一些问题,我们可以先判断一下再转型.使用instanceof关键字即可(返回boolean值).
范例4:
class A{
public void print(){
System.out.println("A.public void print(){}") ;
}
}
class B extends A{
public void print(){
System.out.println("B.public void print(){}") ;
}
public void getB(){
System.out.println("b.getB()") ;
}
}
public class Demo{
public static void main(String args[]){
A a = new B() ;
System.out.println(a instanceof A) ;
System.out.println(a instanceof B) ;
if(a instanceof B){
B b = (B) a ;
b.getB() ;
}
}
}
运行结果:
为了日后的操作方便,在写代码时,尽量不要去执行向下转型操作.即子类尽量不要扩充新的方法名称(父类没有的方法名称),应该依据父类定义的操作完善方法.
范例5:
class Person{
private String name ;
private int age ;
public Person(String name , int age){
this.name = name ;
this.age = age ;
}
public String getInfo(){
return "姓名:" + this.name + ",年龄: " +this.age ;
}
}
class Student extends Person{
private String school ;
public Student(String name ,int age, String school){
super(name,age) ;
this.school = school ;
}
public String getInfo(){
return super.getInfo() + ",学校:" +this.school ; //仅仅是完善!
}
}
public class Demo{
public static void main(String args[]){
Person per = new Student("张三",20,"清华大学") ;
System.out.println(per.getInfo()) ;
}
}
运行结果:
一切的操作都要以父类为主!!!
范例6:要求定义一个方法,这个方法可以接受A类的任意子类对象.
实现方式1,不使用对象转型,采用方法重载完成:
class A{
public void print(){
System.out.println("A.public void print(){}") ;
}
}
class B extends A{
public void print(){
System.out.println("B.public void print(){}") ;
}
}
class C extends A{
public void print(){
System.out.println("C.public void print(){}") ;
}
}
public class Demo{
public static void main(String args[]){
fun(new B()) ;
fun(new C()) ;
}
public static void fun(B b){
b.print() ;
}
public static void fun(C c){
c.print() ;
}
}
运行结果:
以上的程序实现了要求,但是!如果A类有5000万个子类,方法重载5000万次.所以,使用对象的向上转型可解决此问题:
实现方式二:
class A{
public void print(){
System.out.println("A.public void print(){}") ;
}
}
class B extends A{
public void print(){
System.out.println("B.public void print(){}") ;
}
}
class C extends A{
public void print(){
System.out.println("C.public void print(){}") ;
}
}
public class Demo{
public static void main(String args[]){
fun(new B()) ;
fun(new C()) ;
}
public static void fun(A a){
a.print() ;
}
}
运行结果:
本程序在定义fun()方法时直接使用A类作为接收的参数,这样它的所有子类都可以利用对象的向上转型调用fun()方法,此时由于fun()方法得到了统一,所以即使出现了再多的子类,方法也不需要进行修改了.注意:在子类的操作中,尽量向父类靠拢,即如果此时子类自己扩充了父类的方法,那么这些方法也无法直接使用了(可以使用向下转型实现).
最后一句:向上转型居多.