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


    首先请看如下代码

    /**
     * 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())

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

  • 相关阅读:
    哥也能写KMP了——实现strstr()
    面试归来,感觉无望,下次再战
    Pow(x, n)
    Length of Last Word
    后缀数组应用
    2倍倍增算法构造后缀数组
    跳台阶问题
    求无序数组中第二大的数--快速选择
    单源最短路径问题
    全局下的isFinite
  • 原文地址:https://www.cnblogs.com/caophoenix/p/12487594.html
Copyright © 2020-2023  润新知