苗德行

首席讲师

方法和变量在继承时的覆盖和隐藏问题

 2016-05-19 16:52  28人

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

首先我们来看几个概念

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

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

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

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

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

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

还有几点需要注意的是

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

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

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

创建两个父子类关系的类

Java代码  

//父类  

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("parentgetKind()方法被调用了");  

        return kind;  

    }  

  

    //静态方法,返回年龄  

    public static int getAge()  

    {  

        System.out.println("ParentgetAge()方法被调用了");  

        return age;  

    }  

  

    //实例方法,返回姓名  

    public String getName()  

    {  

        System.out.println("ParentgetName()方法被调用了");  

        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("childgetkind()方法被调用了");  

        return kind;  

    }  

      

    //获取父类包名  

    public static String getParentKind()  

    {  

        return Parent.kind;  

    }  

      

    //覆盖父类实例方法  

    public String getName()  

    {  

        System.out.println("childgetName()被调用了");  

        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();  

        //输出:childgetName()被调用了  

  

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

        parent.getName();  

        //输出:childgetName()被调用了  

  

        child.getKind();  

        //输出:childgetkind()方法被调用了  

  

        parent.getKind();  

        //输出:parentgetKind()方法被调用了  

    }  

}  

总结:

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

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

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

分享到: