提到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());
}
}
}