zoukankan      html  css  js  c++  java
  • 携程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了。

    其它:

    看我大师归来:
    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

  • 相关阅读:
    小达同学软件测试第四讲-执行测试
    小达同学软件测试第四讲-执行测试
    Android Studio一直显示Building“project name”Gradle project info问题详解
    Android Studio一直显示Building“project name”Gradle project info问题详解
    安卓入门基础(九)-对应用结构进行分析
    安卓入门基础(九)-对应用结构进行分析
    深入浅出的排序算法-冒泡排序
    深入浅出的排序算法-冒泡排序
    【程序人生】献给还不知道怎么坚持的你
    【程序人生】献给还不知道怎么坚持的你
  • 原文地址:https://www.cnblogs.com/softidea/p/4859641.html
Copyright © 2011-2022 走看看