java是纯粹面向对象编程的语言,弄懂类、对象、方法等之间的关系极其重要。我在学习的时候一下子就踩了一个坑。先给大家推荐一下我正在看的书:《Java核心技术 卷I》。打算入门java的同学可以选择这本书,绝对不亏(虽然我刚才还被这个问题困扰了很久,但后来发现只不过是我看书不用心罢了)。
问题的产生
在学习类的继承时,看到某代码中将子类变量赋值给所对应的超类的变量(staff[0]=boss),
package inheritance;
/**
* This program demonstrates inheritance
* @version 1.00 2020-01-07
* @author 梦劫~VEZ'NAN
*/
public class ManagerTest {
public static void main(String[] args)
{
//construct a Manager object
Manager boss=new Manager("Carl Cracker",80000,1987,12,15);
boss.setBonus(5000);
Employee[] staff=new Employee[3];
//fill the array with Manager and Employee object
staff[0]=boss; //疑惑
staff[0].setBonus(1);
/* Manager bos=(Manager) staff[0];
bos.setBonus(1);
System.out.println(bos.getSalary());*/
staff[1]=new Employee("Harry Hacker",50000,1989,10,1);
staff[2]=new Employee("Tommy Tester",40000,1990,3,15);
//print out information about all Employee objects
for(Employee e:staff)
{
System.out.println("name="+e.getName()+";salary="+e.getSalary()+";hireDay="+e.getHireDay());
}
}
}
于是产生了疑惑:在for each环节对staff[0]使用getSalary方法时为什么会调用Manager类中的getSalary方法呢(从输出结果看出来调用的是Manager中的方法)?除非staff[0]是Manager的实例。后来发现本书在这个代码的前面明确指出:“staff[0]对应的是Manager对象”(真搞不懂我之前是不是眼瞎了)。
进一步探索
于是我尝试对staff[0]使用setBonus方法,然而编译器报错了(第二十行报错)。
不是说好了staff[0]是Manager对象吗?为什么不能对它使用setBonus方法?
于是又开始在百度、CSDN上疯狂寻找合理的解释,无功而返。继续看书,恍然大悟。
这是书上的一句原话
“在这个例子中,变量staff[0]与boss引用同一个对象。但编译器将staff[0]看成Employee对象。
这意味着,可以这样调用
boss.setBonus(5000); //OK
但不能这样调用
staff[0].setBonus(5000); //Error
这是因为staff[0]声明的类型是Employee,而setBonus不是Employee类的方法。”
也就是说
staff[0]与boss引用的是同一个Manager对象(通过断点调试可以很明显地看出来),但是只有在对staff[0]使用getSalary方法(超类与子类重载的方法)时编译器才会把staff[0]看作Manager对象,其它情况都将staff[0]强制看作是Employee对象(置换法则)。
写完这篇博客心里舒服多了。这个法则是真的坑啊。