作者:华清远见讲师

  最近有个同学问了我一个小问题,觉得很有意思,之前一直没有想到过。他说“j**a中存在方法覆盖,是否存在变量的覆盖呢?”。我们知道,在j**a中,子类可以继承父类,如果子类声明的方法与父类有重名,这时就发生了方法覆盖。其实,这实际上这又分为两种情况,就是方法和变量在继承时的覆盖和隐藏问题,这些概念性的东西看似无聊,但是在面试中还是比较常见的,所以这里来讨论下

  首先我们来看几个概念

  隐藏 :子类隐藏了父类的变量和方法,那么,子类不能访问父类被隐藏的变量或者方法,但是,将子类转换成父类,可以访问父类被隐藏的变量或者方法

  覆盖 :子类覆盖了父类的变量或者方法,那么,子类不能访问父类被覆盖的变量或者方法,将子类转换成父类后同样不能访问父类被覆盖的变量或者方法

  首先看一下J**A中方法和变量在继承时的覆盖和隐藏规则

  1.父类的实例变量和静态变量能被子类的同名变量隐藏

  2.父类的静态方法被子类的同名静态方法隐藏

  3.父类的实例方法被子类的同名实例变量覆盖

  还有几点需要注意的是

  1.不能用子类的静态方法隐藏 父类中同样标示(也就是返回值 名字 参数都一样)的实例方法

  2.不能用子类的实例方法覆盖 父类中同样标示的静态方法

  3.这点儿请注意,就是变量只会被隐藏 不会被覆盖 ,无论他是实例变量还是静态变量,而且,子类的静态变量可以隐藏 父类的实例变量,子类的实例变量可以隐藏 父类的静态变量

  创建两个父子类关系的类

  J**a代码

  //父类

  class Parent

  {

  public static String kind="cn.com.farsight.parent";

  public static int age=50;

  public String name="Parent";

  //静态方法,返回包名

  public static String getKind()

  {

  System.out.println("parent的getKind()方法被调用了");

  return kind;

  }

  //静态方法,返回年龄

  public static int getAge()

  {

  System.out.println("Parent的getAge()方法被调用了");

  return age;

  }

  //实例方法,返回姓名

  public String getName()

  {

  System.out.println("Parent的getName()方法被调用了");

  return this.name;

  }

  }

  //子类

  class Child extends Parent

  {

  public static String kind="cn.com.farsight.child";

  public int age=25;

  public String name="child";

  //隐藏父类静态方法

  public static String getKind()

  {

  System.out.println("child的getkind()方法被调用了");

  return kind;

  }

  //获取父类包名

  public static String getParentKind()

  {

  return Parent.kind;

  }

  //覆盖父类实例方法

  public String getName()

  {

  System.out.println("child的getName()被调用了");

  return this.name;

  }

  //获取父类名称

  public String getParentName()

  {

  return super.name;

  }

  /*

  *错误,实例方法不能覆盖父类的静态方法

  public int getAge()

  {

  return this.age;

  }

  */

  }

  class TestDemo

  {

  public static void main(String[] args)

  {

  Child child=new Child();

  System.out.printf("子类名称:%s,年龄:%d,包名:%s%n",child.name,child.age,child.kind);

  //输出:子类名称:child,年龄:25,包:cn.com.farsight.child

  //把child转换成parent对象

  Parent parent=child;

  System.out.printf("转换后的名称:%s,年龄:%d,包名:%s%n",parent.name,parent.age,parent.kind);

  //输出:转换后的名称:Parent,年龄:50,包:cn.com.farsight.parent

  System.out.printf("子类访问父类被隐藏的实例变量name:%s%n",child.getParentName());

  //输出:子类访问父类被隐藏的实例变量name:Parent

  System.out.printf("子类访问父类被隐藏的静态变量kind:%s",child.getParentKind());

  //输出:子类访问父类被隐藏的静态变量kind:cn.com.farsight.parent

  child.getName();

  //输出:child的getName()被调用了

  //**************注意看这个方法,返回的还是子类的getName

  parent.getName();

  //输出:child的getName()被调用了

  child.getKind();

  //输出:child的getkind()方法被调用了

  parent.getKind();

  //输出:parent的getKind()方法被调用了

  }

  }

  总结:

  1.同名的实例方法被覆盖 ,同名的静态方法被隐藏 ,child类的getName实例方法覆盖 了parent的getName实例方法,chind的getKind方法隐藏了parent类的getKind方法

  2.隐藏和覆盖的区别在于,子类对象转换成父类对象后,能够访问父类被隐藏 的变量和方法,而不能访问父类被覆盖的方法

  3.如果需要访问父类被隐藏的实例变量,加上super就好了,比如访问父类name,使用super.name

  源文:https://www.embedu.org/column/3224.html

          >>>更多优秀技术博文每日更新