提到java的多态,想必是很多java新手一个较难跳跃的坎。
下面,我将自己理解的多态在这里给总结下。
多态,分为编译时的多态和运行时多态。
1.编译时的多态。
首先,说到一个科学概念的时候,我们应该清楚,这个概念只是描述了一种现象或者 规律的一个抽象词汇,所以我们应该做的是,去查找这个概念真正描述的现象。
什么是编译时的多态呢?
其实说白了,就是方法的重载,这种现象就体现了编译时的多态,是面向对象语言的 多态的一种体现。但,它是编译时的多态,后面会说运行时多态。
就是说,编译器在编译的时候,它会自己去判断,调用哪一个重载的方法。这种机制 ,就体现了多态,而不需要人为的去指定。
编译器,会自动的根据,方法的参数的个数,类型,自动的调用对应的方法,而不需 要人为的干预,这种现象就体现了多态。
这种多态一个简单的例子就是
void println(int i){};
void println(float i){}; void println(string str){};这三个方法在调用的时候,编译器的自动选择,就体现了多态,这种多态比较简单,这里就不再多做解释了。
2.运行时的多态
说到运行时的多态,当然还是要去看,什么样的现象我们把它称为多态呢?
这样一种现象我们把它称为多态:
class Employee{ void getDetail(){ System.out.println("is a Employee"); } } class Manager extends Employee{ void getDetail(){ System.out.println("is a Manager!"); } void getDepartment(){} } class Secretary extends Employee{ void getDetail(){ System.out.println("is a Secretary"); } void getSalary(){} } //下面那个静态的方法的调用体现了多态。 public class test{ static void getDetails(Employee e){ e.getDetail(); } public static void main(String[] args){ Manager e= new Manager(); Secretary e1= new Secretary(); Employee e2= new Employee(); //下面的三个函数的调用体现了多态
getDetails(e); getDetails(e1); getDetails(e2); } }如上面注释中所示,那三个函数就体现了多态这种现象。
就是说,子类的对象也是父类的对象,我们在用函数调用的时候,如果定义这个函数接口是父类这种类型的,那么所有重写了父类的那些方法的子类,都可以作为这个函数的参数,函数在编译的时候,并不知道,这个参数到底是父类的还是子类的,具体的类型它并不清楚,只有当运行的时候,实实在在的调用的时候,系统会自动的判别是哪种类型,而程序员不用管到底是谁。
看了这种现象之后,很显然的会有很多的疑问在里面。
疑问一:
传过来的那个参数,如果是该类型的子类,那么这个转化合法吗?转换的机理又是什么?
答:如果传进去的参数是子类,会将子类“上溯造型”,将该变量自动转换为父类那种类型。
那么什么叫上溯造型呢?
就是将子类的对象的引用,转换成父类对象的类型的引用,体现了造型,又因为上从下到上的一级转化,又体现了向上,综上可知叫做上溯造型。
疑问二:
你怎么知道传进来的那个类型,这个类中会有要调用的那个方法呢?
答:请看我们多态现象下面的解释,就是说,要实现多态,必须是子类当中重写了父类的方法,这样就可以实现不用管类型,到时候调用的时候运行时自动检测。
如果深入的理解的话,这个问题其实还要说到,上溯造型上,一般课本讲述的时候,会先讲述上溯造型,这里我们是先看多态这个现象,然后看上溯造型,所有这点有点不好理解。
其实呢,本质上,那个传值的过程就是个上溯造型的过程,如Employee e=e1//e1=new manager();就是说,把e1上溯造型为Employee类型的,下面说下上溯造型一些要点。
上溯造型:
把子类的对象的引用,转化为父类类型的变量,那么这个变量就属于父类类型了。
注意:
1.该变量可以调用父类中所有的方法成员。
2.该变量还可以调用子类中重写了父类的方法。
3.该变量不可以调用子类中特有的方法。
注意的三点,很好理解,因为这个变量已经造型为父类类型,那么它就不可以随随便便的调用子类的东西了,它只能要么调用父类中的东西,要么调用父类和子类的共有的东西,反正就是它属于父类,它可以调用父类所有东西,包括哪些被子类重写了的方法,我们多态就是体现在那些被子类重写了的方法上,就是特别的该变量在调用重写的那些方法时,系统怎么判断该调用谁呢?是父类的呢?还是子类的呢?就看运行时这个变量是谁了。这就是多态。
疑问三:
上溯造型可以调用重写的方法,那么那些子类中特有的成员变量被隐藏,那么在多态时候,我如果想调用那些子类的特有的东西的时候该怎么办呢?
答:问的好!我们在多态的时候引用,子类特有的成员呢?ok
我们的强制类型转换应运而生,我们来看看啥是强制类型转换呢?
强制类型转换:
通俗的说,就是把一个对象类型转化为另一个对象类型。(有点像,一般的类型转换机制,但是它又有所自己的限制)
限制:
1、这些类必须之间有继承关系,无关系者不能乱转化。
2.目标对象类型一定是当前转化类型的子类,否则就是上溯造型了,不需要强制转化。
其实呢,这个强制转化是与上溯造型,是同生共死的,就是说,有了上溯造型必然有强制转化,这样为我们多态是访问子类的特有成员,提供方便,不然全是访问的共有的。
所以说,在多态的时候,很多时候,我们会用到强制类型转化,去访问子类的特有成员。
疑问四:
说了这么多,这个强制类型到底杂用啊?来个实例看看。。
好吧!
下面上实例
static void getDetails(Employee e){ if(e instanceof Manager){ Manager m = (Manager)e; m.getDepartment(); } e.getDetail(); }上面的这个方法中,加了一些东西
instanceof 是个关键字,作用是检测,左边的变量是否是右边类型的引用。
第三行,进行强制类型转换,
第四行,调用子类特有的方法。
下面都相同。
////
说了这么多,这些东西都是联系在一起的,先辅相成的,所以不要把上溯造型和,多态,强制类型割裂开来。
// ------------------------ public class pa { public static void main(String[] args){ Employee emp = new Employee("zhao",28,500.0F); Manager mgr = new Manager("xu",35,800.0F,200.0F); Director dor = new Director("huang",45,1000.0F,500.0F,"2222","d01"); System.out.println(emp.getInfo()); System.out.println(mgr.getInfo()); System.out.println(dor.getInfo()); System.out.println(); } } class Employee { String name ; int age ; float salary = 300 ; Employee(String n,int a,float s){ name = n ; if(a>=18 && a<=60) age = a ; else {System.out.println("illegal age"); System.exit(1); } salary = s; } Employee( String n , int a ) { this(n ,a ,300 ) ; } void upSalary(float inc) { salary = salary + inc ; } String getInfo() { return "employee :" + name + "\t" + "salary: " + salary ; } } class Manager extends Employee { float allowance; Manager(String n,int a,float s , float aa){ super(n,a,s); allowance = aa ; } void setAllowance(float a) { allowance = a ; } String getInfo() { return super.getInfo() + "\t" + "allowance :" + allowance ; } } class Director extends Manager { String telephone ; String department ; Director(String n,int a,float s,float aa,String tel,String dep){ super(n,a,s,aa); telephone = tel ; department = dep; } void setTel(String tel) { telephone = tel ; } String getInfo() { return name + " is the management of " + department ; } } //------------------多态-------------- class pb { public static void main(String[] args){ Employee e1 = new Employee("wang1",30,500); Employee e2 = new Manager("wang2",40,800,200); Employee e3 = new Director("wang3",50,1000,500,"3333","d02"); if(e2 instanceof Director)System.out.println("e2 is a Director class!"); else System.out.println("e2 is Manager!"); System.out.println(e2.name); // System.out.println(e2.allowance); e2.upSalary(200.0F); // e2.setAllowance(500.0F) ; e3.age = 55 ; // e3.department = "d03"; e3.upSalary(500); // e3.setTel("8888"); System.out.println(e1.getInfo()); e2 = new Employee("wang122",30,500); System.out.println(e2.getInfo()); System.out.println(e3.getInfo()); } } //----------------up cast ------------------- class pc { public static void main(String[] args){ Director d = new Director("Jack",45,1000.0F,500.0F,"4444","d03");; Manager m =d ; // need? Manger m = (Manger)d d.setAllowance(500); if(m instanceof Director)System.out.println("m is a Director"); else System.out.println("m is a Manager"); System.out.println(m.getInfo()); System.out.println(); // m.setTel("2222"); Employee e = d ; // need? Employee e = (Employee)d e.upSalary(1000.0F) ; System.out.println(e.getInfo()); } } //-----------------down cast-------------------- class pd { public static void main(String[] args){ Employee e1 = new Employee("Tom",30,500); // Manager m1 = e1; // Manager m2 = (Manager)e1; Employee e2 = new Director("Bob",50,1000,500,"5555","d04"); if (e2 instanceof Employee) { //System.out.println( (Director)(e2)).telephone); System.out.println("e2 is a Employee!"); Director d = (Director)e2 ; d.setTel("9999"); d.department="d05"; System.out.println(d.getInfo()); } } }