• 【未解决】为何子类对象引用可以间接访问父类的私有方法?


    首先请看如下代码

    /**
     * Father.java
     */
    public class Father {
        public int age = 40;
    
        public String getDescription(){
            return "I'm the father.";
        }
    
        @Override
        public String toString() {
            // 通过Son调用时,这里的两个this分别是谁?访问的方法或域又是谁?
            System.out.println(this instanceof Son);
            return "[" + this.getDescription() + /*Father.*/this.age + "]";
        }
    }
    
    /**
     * Son.java
     */
    public class Son extends Father {
        public int age = 20;
    
        @Override
        public String getDescription(){
            return "I'm the son.";
        }
    
        @Override
        public String toString() {
            return super.toString() +
                    "[" + this.getDescription() + this.age + "]";
        }
    
        public static void main(String[] args) {
            System.out.println(new Son());
        }
    }
    

    运行Son.main之后得到输出如下

    true
    [I'm the son.40][I'm the son.20]
    
    Process finished with exit code 0
    

    1.第一个问题

    可以看到,在Son.toString()里调用super.toString()方法,而super.toString()中调用的this.getDescription()居然实际上是Son.getDescription()!

    这个原因可以作如下解释:
    super关键字和this关键字不同,它并不是一个引用,仅仅指示编译器去调用超类的方法。
    所以调用super.toString()时传递过去的对象引用仍然是Son,即此时super.toString()中的this是一个Son对象引用[1],自然会优先调用子类的覆盖方法。

    [1] instanceof语句为ture也可以说明这一点。

    2.第二个问题

    那么问题来了,为什么super.toString()中的this.age却访问的是Father对象的age域呢?

    可以作如下解释:
    Son类在继承Father类时,当然也会把域给继承了过去,也就是说Son对象中的数据域有ageFather.age。这里的this虽然是Son对象的引用,但使用超类的方法访问的数据域将会是超类的域,即Father.age

    此说法为个人理解,存疑。事实上,将Father.age改为private也能被Son的对象引用访问到,这和下面的问题如出一辙。

    3.新的问题

    接下来将Father.getDescription()方法改为私有的,同时去除Son.getDescription()@Override覆盖注解。(注意:此时已不是覆盖了)

    /**
     * Father.java
     */
    public class Father {
        public int age = 40;
    
        private String getDescription(){
            return "I'm the father.";
        }
    
        @Override
        public String toString() {
            System.out.println(this instanceof Son);
            return "[" + this.getDescription() + /*Father.*/this.age + "]";
        }
    }
    
    /**
     * Son.java
     */
    public class Son extends Father {
        public int age = 20;
    
        public String getDescription(){
            return "I'm the son.";
        }
    
        @Override
        public String toString() {
            return super.toString() +
                    "[" + this.getDescription() + this.age + "]";
        }
    
        public static void main(String[] args) {
            System.out.println(new Son());
        }
    }
    

    运行结果如下:

    true
    [I'm the father.40][I'm the son.20]
    
    Process finished with exit code 0
    

    观察输出可以看到,此时竟然调用到了Father类的私有方法,我们可以看到这里的this仍然是Son对象的引用,那就很奇怪了,为什么子类的引用可以访问到超类的私有方法呢?

    此问题待解决,有一个帖子也讨论了这个问题,但是并没有给出能说服我的解答。等学了JVM之后看能不能解惑。

    另一个存疑,第一个问题里,如果我就是想调用到通过子类调用到被覆盖的Father.getDescription(),该怎么做?(不要说在子类方法里用super.getDescription(),我指的是子类调用父类方法Father.toString(),然后在Father.toString()中调用父类被覆盖的方法Father.getDescription())

    要是有高手知道答案欢迎在评论区指教一下

  • 相关阅读:
    IDL读取TXT文件并写入二维数组中【转】
    远程连接ArcSDE
    Silverlight项目启动出现System.NullReferenceException未将对象引用到对象实例
    ENVI扩展工具:HDF5 Browser
    READF: End of file encountered. Unit: 100
    ENVI4.8下从两幅分类结果的栅格图中计算土地利用类型转换矩阵
    IDL中去掉数组中相同的元素方法
    利用IDL程序自动添加ENVI菜单【转】
    WIN7远程桌面连接知识
    对COM组件的调用返回了错误"HRESULT E_FAIL”的错误分析(c#与IDL混合编程)转
  • 原文地址:https://www.cnblogs.com/caophoenix/p/12487594.html
Copyright © 2020-2023  润新知