最近我们公司招人,看了下笔试题,有道题不理解
题目如下
class SuperClass{
private int number;
public SuperClass(){
this.number=0;
}
public SuperClass(int number){
this.number=number;
}
public int getNumber(){
number++;
return number;
}
}class SubClass1 extends SuperClass{
public SubClass1(int number){
super(number);
}
}
class SubClass2 extends SuperClass{
private int number;
public SubClass2(int number){
super(number);
}
}
public class SubClass extends SuperClass{
private int number;
public SubClass(int number){
super(number);
}
public int getNumber(){
number++;
return number;
}
public static void main(String[] args) {
SuperClass s=new SubClass(20 );
SuperClass s1=new SubClass1(20 );
SuperClass s2=new SubClass2(20 );
System.out.println(s.getNumber());
System.out.println(s1.getNumber());
System.out.println(s2.getNumber());
}}
执行结果是
1
21
21
请问:s.getNumber() 结果为什么是 1啊?!!
题目如下
class SuperClass{
private int number;
public SuperClass(){
this.number=0;
}
public SuperClass(int number){
this.number=number;
}
public int getNumber(){
number++;
return number;
}
}class SubClass1 extends SuperClass{
public SubClass1(int number){
super(number);
}
}
class SubClass2 extends SuperClass{
private int number;
public SubClass2(int number){
super(number);
}
}
public class SubClass extends SuperClass{
private int number;
public SubClass(int number){
super(number);
}
public int getNumber(){
number++;
return number;
}
public static void main(String[] args) {
SuperClass s=new SubClass(20 );
SuperClass s1=new SubClass1(20 );
SuperClass s2=new SubClass2(20 );
System.out.println(s.getNumber());
System.out.println(s1.getNumber());
System.out.println(s2.getNumber());
}}
执行结果是
1
21
21
请问:s.getNumber() 结果为什么是 1啊?!!
subclass本身变量number值并没有改变 还是初始值0;
为什么得出的结果是21????
SubClass2也是private int number;但是它在构造方法里调用了super(number);所以和它自己的number没关系的。可以在SubClass2的构造方法用this.number来打印看看,这个值是0。
public class SubClass extends SuperClass{private int number;
public SubClass(int number){
super(number);
}
public int getNumber(){
number++;
return number;
}此代码中当new SubClass(20)的时候,调用构造函数public SubClass(int number)方法,super(number)中的number变量是指的public SubClass(int number)中的number,它是一个局部变量,作用域只限于构造函数。而SubClass类的成员变量private int number初始化为0,所以执行number++以后就变为了1.这应该是考变量作用域以及继承方面的知识。
综上所述,得出的结论就是s.getNumber()==1;s1.getNumber()==21;s2.getNumber()==21 。
不急,慢慢来,打开netbeans,把代码放进去,然后格式化代码,并且根据提示加上@Override,然后看到一般情况下大家喜欢的格式:/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package mytester;/**
*
* @author Rains.C
*/
public class Main { /**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
SuperClass s = new SubClass(20);
SuperClass s1 = new SubClass1(20);
SuperClass s2 = new SubClass2(20);
System.out.println(s.getNumber());
System.out.println(s1.getNumber());
System.out.println(s2.getNumber());
}
}class SuperClass { private int number; public SuperClass() {
this.number = 0;
} public SuperClass(int number) {
this.number = number;
} public int getNumber() {
number++;
return number;
}
}class SubClass1 extends SuperClass { public SubClass1(int number) {
super(number);
}
}class SubClass2 extends SuperClass { private int number; public SubClass2(int number) {
super(number);
}
}class SubClass extends SuperClass { private int number; public SubClass(int number) {
super(number);
} @Override
public int getNumber() {
number++;
return number;
}
}
在第21,22,23,24行打上断点符号,然后“调试”主项目:
运行第21行之前,结果是(netbeans显示):
s有自己的number = 0, 继承的number = 20
s1只有继承的number = 20
s2有自己的number = 0, 继承的number = 20然后“继续”(运行第22行之前)
结果是:
s自己的number = 1, 继承的number = 20
其他不变然后继续:(运行第23行之前)
s不变
s1继承的number = 21
其他不变然后继续(运行第24行之前):
s和s1不变
s2自己的number = 0, 继承的number = 21调试结束。整个过秤的变量中间结果如此,现在反过来推敲是什么步骤导致这样的中间结果。首先变化的是s自己的number,继承的number不变。
这个动作由21行的s.getNumber()引起,
观察s的定义:s是鸡肋(基类),用子类填充(实例化),
子类实例化的具体步骤是super(number),即调用鸡肋的构造器。
鸡肋的构造器对鸡肋自己的number赋值,这个很好理解。
如果我没有看错的话(现在是凌晨2点30,我希望我没看走眼),3个子类的构造器通通是调用鸡肋的,
观察“调试”模式的变量中间结果,可以很轻易的得到结论:number域可以被继承。
因此,第21行执行前,S,S1,S2三个对象的继承来的number域都是20,这个由18,19,20行的实例化方式及参数看得出。回到s.getNumber()方法,这个方法返回的是子类 -自己- 的number域, 系统为这个未初始化的域赋予默认值0,那么get以后得到1,很好理解。继续,s1.getNumber()方法:s1没有定义这个方法,系统找s1的鸡肋的public的getNumber方法,找到了!之行……结果是s1的继承来的number域变成21,嗯,正如所料。继续,s2.getNumber()方法:和s1没区别;
另一个证据是:在netbeans里面,SubClass2的number域下面有波浪线,系统提示:“未使用字段”
。
我模仿处女座举证的方式,罗列了netbeans中的事实,供大家思考。有一些建议如下:
1、建议非对象的私有域最好给个初值,比如int = 0;
如果私有域是对象,最好给个Null,反而不要赋值,避免递归定义,堆栈溢出,比如:public class A {
private A a = null;
//private A a = new A();
}
很难说你的构造器里面有if(A != null) return;2、域放在方法后面,除非写算法。3、继承和接口,首先考虑接口。4、尽量不用默认的访问控制,把域标记为private而不是空着,然后提供访问器和设置器。 ——from 《Effective Java》
创建s1对象时,调用的是父类的带参数的构造方法,于是父类number=20;因为子类SubClass1没有重写父类的getNumber()的方法,只能从父类继承,所以getNumber()所取得的值是父类的number+1;
又因为 subclass 的变量时私有的
导致subclass的值为1
而subclass2没有重写getNumber方法
subclass2又继承了superclass
导致getNumber方法返回的是21
SuperClass s = new SubClass(20); //根据new SubClass(20); 20是进入SubClass的构造方法。
SuperClass s1 = new SubClass1(20);
SuperClass s2 = new SubClass2(20);
System.out.println(s.getNumber());//根据第一行SuperClass s;getNumber()是进入SuperClass的方法。
System.out.println(s1.getNumber());
System.out.println(s2.getNumber());
,所以结果就是1
class SubClass1 extends SuperClass{
public SubClass1(int number){
super.number=number;
}
//getNumber方法没有被继承,多态时使用父类方法
}
class SubClass2 extends SuperClass{
private int number;
public SubClass2(int number){
super.number=number;
}
//getNumber方法没有被继承,多态时使用父类方法
}
public class SubClass extends SuperClass{private int number;
public SubClass(int number){
super.number=number;
}
public int getNumber(){
this.number++;
return this.number;
}
我的微薄:http://t.sina.com.cn/teststar