携程Java工程师——一道面向对象面试选择题(转)

public class Base
{
private String baseName = "base";
public Base()
{
callName();
} public void callName()
{
System. out. println(baseName);
} static class Sub extends Base
{
private String baseName = "sub";
public void callName()
{
System. out. println (baseName) ;
}
}
public static void main(String[] args)
{
Base b = new Sub();
}
}

输出:
null

原因:

在Eclipse中Debug运行一下,一步一步观察,就可以看到程序的执行顺序,就知道为什么是null了。

携程Java工程师——一道面向对象面试选择题(转)

其它:

看我大师归来:
1. Base b = new Sub();
2. Base b = 直接忽略,从 new Sub();开始
3. 类加载器加载 Base,Sub 类到jvm;
4. 为Base,Sub 类中的两个属性baseName 分配存储空间,但是不初始化
注意:属性的初始化时放在构造器中,按照代码顺序执行的。
5. new Sub会调用Sub的无参构造器,而在这个构造器中会隐式调用父类Base的无参构造器;
6. 父类Base的构造器中代码本质是
public Base()
{
baseName = "base";
callName();
}
即父类的属性baseName 的值为base。但为何输出null,骚年别急。
7. 因为父类构造器方法是在子类中调用的,即大环境是子类。此时,调用的方法callName()当然是指子类的方法。而这个方法打印的属性baseName当然也是子类的。那现在子类的属性baseName的值是多少呢?答案是null.因为此时子类Sub的构造器内代码本质是:
super();
baseName="sub";
此时baseName="sub"还没执行。

因此,左后的值当然是null.

http://group.jobbole.com/7782/#comm-9787

属性是绑定类型的,而方法是绑定对象的。

或者说属性是在编译器就确认的,而方法是动态绑定多态

属性没有覆盖的概念,如果同名,这是一种隐藏,访问父类中定义的field,使用super.i

类中隐藏了2个引用,一个是this一个是super
在子类中可以用super.访问父类对子类开放的属性和方法
如果子类没有定义与父类中同名的属性,并且子类可以访问父类的这个属性,那么直接用属性名就可调用
如果子类定义与父类同名的属性,而且子类可以访问父类的这个属性,那么用super.调用
如果子类定义了与父类的属性,但子类不对父类的这个属性有访问属性,那么用super.也无法调用

当java的子类和父类具有相同名字的属性时,到底java是怎么处理的。

先看代码:

package com.joyfulmath.study.field;

public class Person {
public String name; public String getName() {
return name;
} }
package com.joyfulmath.study.field;
public class Student extends Person {
public String name;
public Student(String name)
{
this.name = name;
super.name = "Man-Person";//从此处可以看出,java可以通过this,已经super来区分子类和父类。
}
@Override
public String getName() {
return name;
}
}
package com.joyfulmath.study.factory;
import com.joyfulmath.study.field.Person;
import com.joyfulmath.study.field.Student;
import com.joyfulmath.study.utils.TraceLog;
public class FieldMethod implements IWorkMethod {
@Override
public void startWork() {
Student st = new Student("Mark-Student");
Person p = st;
TraceLog.v(p.name+" "+st.name);
TraceLog.v(p.getName()+" "+st.getName());
}
}

其实st.name不用怀疑,肯定是Mark-Student

但是p.name,已经p.getName()呢?

我们先来看p.getName(),虽然P是person,但是它实际代表的地址里面存的是Student,所以

p.getName()实际的调用结果是 st.getName()一样的,也就是student的getname方法。

那p.name呢?

我们在Student里面添加一个属性,level。

public class Student extends Person {
public String name;
public int level;
public Student(String name)
{
this.name = name;
super.name = "Man-Person";
}
@Override
public String getName() {
return name;
}
}

然后还是在startwork中,用p.level,结果编译器不认识?

对呀,p是person的对象,它怎么会认识呢。

所以很显然,p只认识Person中的name,而不是Student中的name.

我们看下运行结果:

startWork: Man-Person Mark-Student [at (FieldMethod.java:13)]
startWork: Mark-Student Mark-Student [at (FieldMethod.java:14)]

验证了我们的猜测,可见属性是绑定类型的,而方法是绑定对象的。

或者说属性是在编译器就确认的,而方法是动态绑定(多态)。

http://www.tuicool.com/articles/ZziiIjJ

上一篇:ASP.NET Core消息队列RabbitMQ基础入门实战演练


下一篇:消息队列rabbitmq/kafka