日期:2014-05-20  浏览次数:20714 次

Java核心技术书中关于Manger和staff例子中多态的问题
各位大侠;先贴出原代码:
import java.lang.*;
import java.util.*;
public class EmployeeTest{
public static void main(String[] args){
Manger boss=new Manger("qiq",7777,1987,10,15);
Employee[] staff=new Employee[3];
staff[0]=boss;
boss.setBonus(500);
staff[1]=new Employee("lucy",100,2000,1,1);
staff[2]=new Employee("lilly",200,2011,1,1);
for(Employee e:staff){
System.out.println(e.getName()+e.getSalary());
}

}
}
class Employee{
public Employee(String n,double s,int year,int month,int day){
name=n;
salary=s;
GregorianCalendar calendar=new GregorianCalendar(year,month-1,day);
hireDay=calendar.getTime();
}
public String getName(){
return name;
}

public double getSalary(){
return salary;
}
public Date getHireDay(){
return(Date) hireDay.clone();
}

public void raiseSalary(double byPercent){
double raise=salary*byPercent/100;
salary=salary+raise;
}
private String name;
private double salary;
private Date hireDay;
}


class Manger extends Employee{
public Manger(String n,double s,int year,int month,int day){
super(n,s,year,month,day);
bonus=0;
}
public void setBonus(double b){
this.bonus=b;
}

public double getSalary(){
return super.getSalary()+bonus;
}
private double bonus;
}


书上这里说:变量staff[0]和boss引用同一个对象,但是编译器将staff[0]看成Employee对象,意味这可以这样调用:
boss.setBonus(500);
不可以这样调用:
staff[0].setBonus(500);


我的理解是BOSS是子类,staff[0]是父类,那为何输出结果的时候,staff[0]还能调用子类中的getSalary()方法,求解释~~~~~


------解决方案--------------------
变量staff[0]和boss引用同一个对象这句话是对的。
Employee e = new Manger("qiq",7777,1987,10,15);
e的实际类型是Manger,但是声明为Employee,只能调用Employee ,
要是要调用Manger的方法必须类型转换((Employee) e).setBonus

------解决方案--------------------
LZ如果清楚编译期和运行期就能理解了
首先,程序要先编译,这个阶段属于编译期
程序是 Employee[] staff 定义的
所以编译器只知道staff[0]是Employee类型,至于运行期它指向哪个实例编译器并不知道
所以staff[0].setBonus(500);是编译通不过的,因为Employee没有setBonus方法,所以如果想让编译通过,就要强行转换((Boss)staff[0]).setBonus(500);这样才能编译通过

程序运行的时候叫做运行期
上面说了,staff[?]在编译期编译器没法知道它运行期会指向什么实例
所以staff[1]强行转换,就像staff[0]强行转换一样,可以编译通过
但是运行期的时候,因为staff[1]指向的是Employee,父类对象不能强行转换为子类对象,所以运行期会报错

注意上述情况的区别,错误分别出现在,一个是编译期出错,也就是编译没法通过,一个是运行期出错,也就是编译可以通过,但是运行时出异常