• 子类重写父类成员方法


    最近在学习到Java的继承和多态时遇到了这样的一个问题:关于继承链中子类对父类的私有方法是否可以覆盖的问题,在此记录一下自己对这个问题解决以后的一些心得。

    首先要明确:子类是不能够覆盖(重写)父类的私有方法的。比较直观的理由是,子类要能够重写父类的方法的前提条件是继承,子类对父类的私有方法并不继承,也没有访问权限,自然也是不能重写的。接下来看一个例子:

    [java] view plaincopy

    <span style="font-size:14px;">public class Test {  

        public static void main(String[] args) {  

            new A().printPerson();  

            new B().printPerson();  

        }  

    }  

      

    class A {  

        public void printPerson() {  

            System.out.println(getInfo());  

        }  

        private String getInfo() {  

            return "A";  

        }  

    }  

      

    class B extends A{  

        public String getInfo() {  

            return "B";  

        }  

    }</span>  

    运行结果是 A A。如果将private修饰词去掉,换成protected和public修饰,运行结果是A B这是毫无疑问的,因为那正是B重写了父类A的getInfo方法;而加上了private修饰词以后,父类A的getInfo和子类B的getInfo实际上就是两个无关的方法,因为私有方法是不能被子类重写的,私有方法并不是父类接口的一部分,只是隐藏在父类中的一段程序代码。

    可是为什么使用子类B的实例调用printPerson,结果是打印A呢?要注意到printPerson方法是在父类A中定义的,因此刚执行new B().printPerson()这行代码时,编译器在子类B中无法找到匹配的printPerson方法,于是到父类A中去寻找;此时在父类A中找到了匹配的printPerson方法,并调用该方法。

    此处需要提及一下子类在继承父类时对父类的成员变量及方法继承的问题。对于使用protected或者public修饰的成员变量及方法,会被子类继承,且可通过子类直接调用,那么,对于子类不可见的private成员,以及没有修饰词修饰的成员(若子类与父类在不同的包中,这一类成员也是对子类不可见的),他们不被子类继承,那么在子类的实例所代表的内存空间中,这些成员是否存在呢?答案是肯定的,父类的私有变量及方法虽然不会被子类继承,对于子类来说不可见,但当创建了子类的实例的时候,这些成员一样会被加载入内存,并“隐藏”在内存当中。

    因此,通过子类B的实例调用printPerson方法,会在父类的成员中寻找匹配的printPerson方法,找到以后,进入printPerson的方法体,调用getInfo方法,程序回到上层去寻找getInfo方法的匹配,并在内存空间中寻找到了A中的getInfo方法,同时由于该getInfo方法是私有的,无法被重写,因此不会触发java的动态绑定机制,于是直接调用该方法。因此,通过B的实例调用printPerson,打印的结果也是A了。

    ============================================

    最近学习继承,从书中看到子类继承父类,子类拥有父类所有的属性和方法,于是使用程序去验证,发现父类的私有属性和私有方法,子类是不能访问的,当然一些父类的私有属性可能可以通过相应的方法访问到,但是私有的方法似乎不能简单的访问,这里暂不考虑Java反射机制,于是我分析,子类不能继承父类私有的属性及方法,但是分析了内存后,我发现我是错的,在一个子类被创建的时候,首先会在内存中创建一个父类对象,然后在父类对象外部放上子类独有的属性,两者合起来形成一个子类的对象。所以所谓的继承使子类拥有父类所有的属性和方法其实可以这样理解,子类对象确实拥有父类对象中所有的属性和方法,但是父类对象中的私有属性和方法,子类是无法访问到的,只是拥有,但不能使用。就像有些东西你可能拥有,但是你并不能使用。所以子类对象是绝对大于父类对象的,所谓的子类对象只能继承父类非私有的属性及方法的说法是错误的。可以继承,只是无法访问到而已。

    当子类覆盖父类的成员变量时,父类方法使用的是父类的成员变量,子类方法使用的是子类的成员变量

    (1)子类覆盖父类的方法,必须有同样的参数返回类型,否则编译不能通过

              (2)子类覆盖父类的方法,在jdk1.5后,参数返回类可以是父类方法返回类的子类

             (3)子类覆盖父类方法,可以修改方法作用域修饰符,但只能把方法的作用域放大,而不能把public修改为private

              (4)子类方法能够访问父类的protected作用域成员,不能够访问默认的作用域成员

             (5)子类的静态方法不能隐藏同名的父类实例方法

     不能继承,子类只能在父类中写一个public的getXXX的方法来获取父类中的private属性,子类就调用父类的getXXX来获取private属性

     父类中的公有方法和域(属性),在类继承中将会被子类继承,但是私有的将不能被继承。

    那么在继承中子类如何才能继承到父类的私有域呢?

    答案是:在子类的构造方法中通过super()方法调用父类的构造方法。

    也就是,在构造子类的同时,为子类构造出跟父类相同的域。如此就在子类的对象中,也拥有了父类声明的域了。

    并且我们也应该这样做。

    [html] view plaincopy

    public class Person{  

        private String name;  

          

        public Person(String name){  

            this.name = name;  

        }  

          

        public void setName(String name){  

            this.name = name;  

        }  

          

        public String getName(){  

            return name;  

        }  

    }  

    [html] view plaincopy

    public class Student extends Person{  

          

        public Student(String name){  

            super(name);  

        }  

    }  

    [html] view plaincopy

    public class TestStudent{  

        public static void main(String[] args){  

          

            Student mStudent = new Student("abc");  

            String mName = mStudent.getName();  

            System.out.println("Name is : " + mName);  

              

            mStudent.setName("efg");  

            mName = mStudent.getName();  

            System.out.println("Name is : " + mName);  

              

        }  

    }  

    打印结果为:

    Name is : abc

    Name is efg

     ============================================

    Java-子类没有继承父类的私有变量和私有方法

      在Java子类有没有继承父类的私有变量?关于这个问题在网上找了很久,也没有一个明确的答案。于是综合大家的观点,自己总结了一下。 

       

      官方文档的解释:“A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.”。原文地址:Inheritance 

      那么问题来了。之前在做Java实验时,为什么Manger类能使用Employee的私有属性呢? 

      我找了一下答案: 

      观点一: 

      “父类中的公有方法和域(属性),在类继承中将会被子类继承,但是私有的将不能被继承。那么在继承中子类如何才能继承到父类的私有域呢?答案是:在子类的构造方法中通过super()方法调用父类的构造方法。”参考:Java中子类继承了父类的私有属性及方法吗?、 

      写了测试代码体会了一下:

    public class Father 

    {

        private int a;

        public Father()

        {

        }

        public Father(int a)

        {

            this.a = a;

        }

        public int getA()

        {

            return this.a;

        }

    }

    public class Children extends Father

    {

        int b;

        public Children()

        {

        }

        public Children(int a,int b)

        {

            //this.a = a;

            super(a);

            this.b = b;

        }

    }

    public class Main 

    {

        public static void main(String[] args) 

        {

            Children child1 = new Children(13,35);

            System.out.println(child1.b+"  "+child1.getA());

        }

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

      观点二: 

      “父类的任何成员变量都是会被子类继承下去的。实际上,private,public,protected和继承没有关系,他们对成员函数和变量的限制只是在成员的可见性上。”参考:私有的成员能被子类继承吗? 

       

      观点三: 

      “父类的private变量,也会被继承并且初始化在子类父对象中,只不过对外不可见。”。他这个观点的提出是从内存上分析的,值得借鉴。参考:JAVA 继承 父类子类 内存分配 

       

      我的总结: 

      从继承的概念来说,private和final不被继承。Java官方文档上是这么说的。 

      从内存的角度来说,父类的一切都被继承(从父类构造方法被调用就知道了,因为new一个对象,就会调用构造方法,子类被new的时候就会调用父类的构造方法,所以从内存的角度来说,子类拥有一个完整的父类)。子类对象所引用的内存有父类变量的一份拷贝。 

      如图所示,父类为Person类,子类为Student类。首先明确子类不能继承父类的构造方法。这就是为什么子类的默认的构造方法会自动调用父类的默认的构造方法。 

      在子类的构造方法中通过super()方法调用父类的构造方法。也就是,在构造子类的同时,为子类构造出跟父类相同的域。如此就在子类的对象中,也拥有了父类声明的域了。

  • 相关阅读:
    luogu P5325 Min_25筛
    P5468 [NOI2019]回家路线 斜率优化 dp
    退役了
    6.18 省选模拟赛 树 倍增 LCT
    导出excel时一个页面问题-X11GraphicsEnvironment
    2019首篇
    Glide:重新加载失败的问题
    Android上传图片的两种方式
    Bug:No mapping for GET /onepill//swagger-ui.html
    Android集成百度地图
  • 原文地址:https://www.cnblogs.com/celine/p/8798610.html
Copyright © 2020-2023  润新知