以下是《JAVA2核心技术》一书中的一个关于计算员工工资的实例,有几个问题不太明白。
import java.util.*;public class ManagerTest
{
public static void main(String args[])
{
Manager boss = new Manager("Simon Lo", 80000, 2008, 11, 26);
boss.setBonus(5000);
Employee staff[] = new Employee[3];
staff[0] = boss;
staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
staff[2] = new Employee("Tommy Tester", 40000, 1990, 3, 15);

for (Employee e : staff)
{
System.out.println("Name = " + e.getName() + "\t\tSalary = " + e.getSalary());
}
}
}class Employee
{
private String name;
private double salary;
private Date hireDay;

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 hireDay;
}

public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
}class Manager extends Employee
{
private double bonus;

public Manager(String n, double s, int year, int month, int day)
{
super(n,s,year,month,day);
bonus = 0;
}

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

public void setBonus(double b)
{
bonus = b;
}
}请教问题如下:
1、在代码中的raiseSalary()方法为什么没有生效?
2、整段代码中在class Employee和class Manager中各定义了一个getSalary()方法,那么在class ManagerTest中的main方法里,JVM又是如何确定到底调用的是哪一个getSalary()的?

解决方案 »

  1.   

    回答你第一个问题
    raiseSalary()方法没有生效,是因为你并没有调用该方法,你不是继承了Manager吗,那么Employee自然也会拥有Manager里面的所有public方法和public的属性(),除非你不想要里面的方法,把它重写了。
    如果想要看到raiseSalary()的效果那么就应该把boss.setBonus(5000); 改为
    double raiseSalaryPercent = ((5000)/(double)boss.getSalary())*100;
    boss.raiseSalary(raiseSalaryPercent);
    只是为了让你理解这个raiseSalary方法到底干嘛才这么复杂的写了那么多,raiseSalary方法是按照百分比来增加工资回答你第二问题:
    首先我把你执行的过程分为编译期和运行期
    编译期,由编译器将代码文件(.java)编译成字节码文件(.class),编译期不关jvm的事,只是进行一系列检查。
    boss是一个Manager的引用指向的是一个Manager的对象,所以没什么好说的。
    然后你把staff[0] = boss;staff[0]是一个Employee引用,此时staff[0]和boss都指向了一个Manager对象。
    for (Employee e : staff)就不用的解释了jdk5.0才有的特性,我就根据你的意思大概这样写下staff[0]:
     System.out.println("Name = " + staff[0].getName() + "\t\tSalary = " + staff[0].getSalary());
    编译器会看看staff[0]是啥类型(Employee类型),然后在看看Employee有没有这个方法,没有编译出错,不信你把
    Employee里面的getSalary()删除(其他关联的也得更改下,否则会出现其他错误)由类加载器将字节码加载到jvm中……进入运行期后,在堆空间里创建一个Manager对象,在栈空间里分配空间给一个
    Manager引用,然后返回Manager对象给Manager引用boss,即
     Manager boss = new Manager("Simon Lo", 80000, 2008, 11, 26);
    接下来是将一个Employee引用指向boss所指的那个对象,
    如果你是
    System.out.println(staff[0].getSalary());
    jvm会看看该引用所指向的对象里有没有该方法,如果有就调用此getSalary(),如果没有当然是调用的是引用类里的getSalary()方法,不过你在Manager类里重写了getSalary()方法,那调用的是Manager类里的getSalary()。
    可能是多态你没怎么深度理解吧,呵呵
    上面对于你的问题应该解释的很详细了吧,不过我建议你最好先研究一下多态
    还有一个建议:先看一下尚学堂马士兵的java基础视频,电驴上有下,期待你的提高,呵呵
      

  2.   

    补充:jvm会看看该引用所指向的对象的类中有没有该方法
      

  3.   

    我不明白calendar.getTime()的用法
    对于你的问题
    1.byPercent没有被赋值,默认为0,所以salary += raise等于salary
    2.那是java的动态绑定机制决定的。怎么区别的,一般是通过构造方法区分.
     这个题更好办了,你直接构建的Manager实例,它就知道了,
      

  4.   

    1.你没调用那个方法。2.这个时候JVM会去检查,你的引用到底是哪个类生成的对象。
    如果是Employee类的对象,则调用Employee的getSalary(),
    如果是Manager类的对象,则现在this域(自己本身类)里getSalary(),如果有定义这个方法,
    则调用。如果没有,则到super域(父类,Employee类中)中找,如果找到了就调用方法,否则会再向上(父类,这里假设还有继承关系,比如Employee继承Person类)找。
      

  5.   

    2楼已经说的很明白了。 多态和继承你自己多看看吧。
    给你提的建议。
    1.不要盲目的提问。
    2.java的几个重要特性你应该都理解到。
    3.把学习中的问题记下来。等把书看完了。你回头再看看你的问题还有不明白的再问。这样理解的深刻。
    学习就是逐步提高的过程。不要把希望都寄托在别人身上。