黑马程序员技术交流社区

标题: Java 中如何访问被父类覆盖的方法? [打印本页]

作者: cat73    时间: 2016-7-12 11:43
标题: Java 中如何访问被父类覆盖的方法?
本帖最后由 cat73 于 2016-7-13 20:28 编辑

我们知道,一个类可以通过 super.xxx() 来访问被自己覆盖的方法。那么要如何访问被父类覆盖的方法呢?


看代码:
  1.     abstract class A extends Object {
  2.         public void xxx() {
  3.             System.out.println("A");
  4.         }
  5.     }
  6.    
  7.     abstract class B extends A {
  8.         public void xxx() {
  9.             System.out.println("B");
  10.         }
  11.     }
  12.    
  13.     class C extends B {
  14.         public void xxx() {
  15.             // call A.xxx();

  16.         }
  17.     }
复制代码

我希望在不改变 A 类与 B 类的代码,并且 C 类要继承 B 类的前提下。
在 C 类的 xxx 方法中调用 A 类的 xxx 方法。
请问要如何写呢?

以下均为错误答案:
  1. super.super.xxx()
  2. A.super.xxx()
  3. A.this.xxx()
复制代码



=========更新======
鉴于有人回答了实例化一个新的 A 类的写法,我重新改了改示例代码,把 A 类跟 B 类增加了 abstract 前缀。
重新实例化的做法并不是访问被覆盖的方法,而是直接访问了方法,所以不予采纳为正确答案。
作者: 小蔡来学java    时间: 2016-7-12 23:49
    class A extends Object {
        public void xxx() {
            System.out.println("A");
        }
    }
   
    class B extends A {
        public void xxx() {
            System.out.println("B");
        }
    }
   
    class C extends B {
        public void xxx() {
            // call A.xxx();
           //方法一             new A().xxx();            //方法二
           Class clazz = Class.foName("A");
          Object object = clazz.newInstance();
          Method mothod = clazz.getDeclaredMethod("xxx");
          mothod.invoke(object);
          乱写一通,哈哈{:2_36:}
           
        }
    }


作者: 15820030540    时间: 2016-7-13 19:29
技术有限,想出一种实现方式,看看是否满足需求:
package com.heima.me;

public class Test4 {

        public static void main(String[] args) {
                C c = new C();
                c.print();
               
        }

}
class A{
        public void print(){
                System.out.println("A");
        }
}
class B extends A{
        public void print(){
                System.out.println("B");
        }
}
class C extends B{
        public void print(){
//                System.out.println("C");
                Class cclazz = C.class;
                String name = cclazz.getSuperclass().getSuperclass().getName();//获取父类的父类类名
                System.out.println(name);                                                                        //打印出类名
                com.heima.me.A a = new com.heima.me.A();                                        //然后创建对象
                a.print();                                                                                                        //调用父类的父类中最初的方法
        }
}
作者: 13266661460    时间: 2016-7-13 23:20
乱写一通,哈哈乱写一通,哈哈乱写一通,哈哈乱写一通,哈哈乱写一通,哈哈乱写一通,哈哈乱写一通,哈哈乱写一通,哈哈乱写一通,哈哈乱写一通,哈哈乱写一通,哈哈
作者: 15242694137    时间: 2016-7-14 09:43
package test;

public class Test2
{
        public static void main(String[] args)
        {
                C c = new C();
                c.xxx();
        }
       
}
abstract class A extends Object {
    public void xxx() {
        System.out.println("A");
    }
}

abstract class B extends A {
    public void xxx() {
        System.out.println("B");
    }
    public void xxx2()
    {
            super.xxx();
    }
}

class C extends B {
    public void xxx() {
       xxx2();
    }
   
}
这是一种取巧的方法 不知道是都合乎你的要求
作者: 15242694137    时间: 2016-7-14 09:58
15820030540 发表于 2016-7-13 19:29
技术有限,想出一种实现方式,看看是否满足需求:
package com.heima.me;

这个题目是抽象类 你这写的已经不是抽象类,这不是限定死了不能用反射吗
作者: 15242694137    时间: 2016-7-14 10:14
我只想说  在你的这种要求下 根本无法做到 !!!!!!!!!!!!!!!!!!!!!!!!
作者: 15242694137    时间: 2016-7-14 10:25
好吧  我服!!!
作者: 紫电_恶魔    时间: 2016-7-15 23:25
好吧,我发现都是大神,不懂啊
作者: wz529377283    时间: 2016-7-16 23:27
我是来看大神解答的
作者: cat73    时间: 2016-7-17 23:12
本帖最后由 cat73 于 2016-7-17 23:15 编辑

super.method() 的调用方法实际的字节码为 invokeinterface,没有参数
所以此题基本应该是无解了。
ASM 没什么卵用,invokeinterface 并没有参数。。。
反射在 Java 代码可控的范围内都是传的 A 类的 xxx 方法,到 native 代码里才根据传递的 obj 转为实际的方法。
所以反射也没什么卵用。。。
想实现这个大概就要改 JVM 虚拟机的源码了。。。

唯一的变通方案大概就是重新写一个继承 A 类的类,并构造一个对象,然后把属性全部复制过去,然后调用 xxx 方法,然后把属性再复制回来。

个人自己的理解,如有错误还请指出,谢谢。

作者: 15820030540    时间: 2016-7-20 10:07
15242694137 发表于 2016-7-14 09:58
这个题目是抽象类 你这写的已经不是抽象类,这不是限定死了不能用反射吗 ...

他这抽象是后加的,不加抽象怎么调用不了??
作者: 15820030540    时间: 2016-7-20 10:10
15820030540 发表于 2016-7-13 19:29
技术有限,想出一种实现方式,看看是否满足需求:
package com.heima.me;

按照你这种需求不创建对象,我想不出来,sorry
作者: 15820030540    时间: 2016-7-20 10:13
15820030540 发表于 2016-7-13 19:29
技术有限,想出一种实现方式,看看是否满足需求:
package com.heima.me;

因为你要想调用一个类方法,不管是父类的父类或者还是其他类,最简单就是创建对象,我就要看这个方法,创建对象就完了呗!你这加个抽象以为就创建不了了吗??匿名内部类可以实现!怎么满足不了需求!
作者: ylca    时间: 2016-7-20 20:05
这个目前个人无法不创建对象去使用A中的方法
作者: cat73    时间: 2016-7-20 20:30
15820030540 发表于 2016-7-20 10:13
因为你要想调用一个类方法,不管是父类的父类或者还是其他类,最简单就是创建对象,我就要看这个方法,创 ...

其实我最初的想法是,方法可能会用到一些本类的字段,重新创建对象无法使用原来类里的字段。
不过实际上通过反射可以把字段都复制过去,执行完再复制回来0.0
作者: 丶侠    时间: 2016-7-20 20:47
反射中,最后的invoke传入的参数可以是this吗? 试一试
作者: liubi01    时间: 2016-7-22 11:30
class c extent B{
void xxx(){
A a=new c();//向上转型
a.xxx();
}
}

作者: cat73    时间: 2016-7-22 12:06
liubi01 发表于 2016-7-22 11:30
class c extent B{
void xxx(){
A a=new c();//向上转型

这样子实际被调用的还是 C 的方法哟。
作者: 黑马YJM    时间: 2016-7-22 22:16
来看大神解答!
作者: LiuWei2015    时间: 2016-7-25 22:30
悬赏分数提高点啊
作者: 15114111253    时间: 2016-7-26 22:09
通过super调用父类的方法

举例:

public class Father{//定义父类
   public void s(){//定义父类的方法s
   }
}
public class Son extends Father{//定义子类son,继承父类father
   public void s(){//定义子类的s方法,覆盖了父类的s方法
     super.s();//通过super调用父类的s方法
   }
}

补充:

Java中,在继承关系中,super指向当前对象里面的父对象
作者: 13411939415    时间: 2016-7-28 10:52
首先,super要在类的声明中调用,再创建的对象中无法通过 对象名.super来进行。
想要用C类调用A类中的方法,就要在类声明的时候下功夫;
class A {
        public void xxx(){
                System.out.println("A");
        }
}
class B extends A {
        public void xxx(){
                System.out.println("B");
        }
       
    public void A_xxx() {           //用A_xxx()方法调用A类中的xxx()方法
                super.xxx();
        }
}
class C extends B {
        public void xxx(){
                System.out.println("C");
        }
       
    public void B_xxx() {                    //用B_xxx()方法调用B中的xxx()方法
                super.xxx();
        }
}
类中的代码就这样了,
使用的时候:
C c = new C();
c.A_xxx();
c.B_xxx();
由于方法已经被重写,在创建对象之后是无法加以访问的,必须在类中创建新的方法来调用
作者: 13411939415    时间: 2016-7-28 11:36
13411939415 发表于 2016-7-28 10:52
首先,super要在类的声明中调用,再创建的对象中无法通过 对象名.super来进行。
想要用C类调用A类中的方法 ...

直接调用时办不到的,方法已经重写了
作者: 15820030540    时间: 2016-8-4 21:30
其实有方法的,得去问谷歌程序员,他们既然能添加super作为调用父类的关键字,自然能做出来调用父类的父类的关键字,所以不是没有方法,只是我们技术不够!
作者: 心尘    时间: 2016-8-15 13:26
目前好像是       如果希望调用父类中的方法,则需要通过父类创建类的实例,然后通过该实例才能访问父类定义的方法。   此父类是题中的A类,     在方法的重写的面试题中,看到很多答案好像就是是这么说的
作者: 彭鸿儒    时间: 2016-8-16 17:33
本帖最后由 彭鸿儒 于 2016-8-16 17:34 编辑

你忘了暴力反射??????只要类里有的都可以拿来用

作者: 彭鸿儒    时间: 2016-8-16 17:40
本帖最后由 彭鸿儒 于 2016-8-16 17:59 编辑

刚刚一个答案说的太含糊了,重新回答
首先super这个隐式参数是类私有的,也就是子类中是无法使用父类的super的,那么我们也就无法调用父类的父类中被覆盖的方法,
           
额,失败了,A是抽象类连实例都无法获得,即使用暴力反射获得了A中的xxx方法,没有A的实例任然无法调用A中被覆盖的方法
容我再想想
B中可以添加方法吗?还是A,B,C三个类是不能改变的

作者: lrwillinggerry    时间: 2016-8-19 13:44
这个属于"匿名内部类"的问题
作者: lrwillinggerry    时间: 2016-8-19 13:59
本帖最后由 lrwillinggerry 于 2016-8-19 14:00 编辑

这个属于"匿名内不类"的问题

根据:
new 抽象类名或者接口名(){
        重写方法;
}
可得:
class C extends B {
        public void xxx() {
           new A(){}.xxx();
        }
}

以上代码的意思为:
由于A为抽象类,要能够在C的xxx()方法实例化一个A的子类并在里面创建该子类的对象调用A的xxx()方法才能访问A的方法,如下:
class C extends B{
     public void xxx() {
        class test extends A{
        }
        Test t = new Test();
        t.xxx();
     }
}
又根据以上匿名内部内的公式,可简化成:
class C extends B {
        public void xxx() {
           new A(){}.xxx();
        }
}   
注意:A中没有抽象方法,所以大括号里面不需要重写xxx()方法.
综上可得:
public class HelloWorld {

        /**
         * @param args
         */
        public static void main(String[] args) {
                C cc = new C();
                cc.xxx();

        }
}

abstract class A extends Object {
        public void xxx() {
                System.out.println("A");
        }
}

abstract class B extends A {
        public void xxx() {
                System.out.println("B");
        }
}

class C extends B {
        public void xxx() {
                new A() {
                }.xxx();
        }
}

作者: lrwillinggerry    时间: 2016-8-20 00:33
lrwillinggerry 发表于 2016-8-19 13:59
这个属于"匿名内不类"的问题

根据:

在main中创建的是当前对象啊
作者: 小超超    时间: 2016-8-25 11:49
可以在父类的方法中在用super.XXX()来访问父类的父类中的方法。这是取巧的方法,不知能不能帮助到你。
作者: 雪连城    时间: 2016-8-28 23:21
6666666666666,看不懂

作者: Android一米阳光    时间: 2016-9-1 22:09
你都重写了,记住重写的目的就是让子类更强,拥有更多属性,你要回去调用就违背这一原则,不然就不要重写,或者从父类到子类都用super()一下,那么爷爷的方法输出的东西以及父类输出的东西在子类方法实现调用时,都会输出
作者: dmyz3214382    时间: 2016-9-4 18:18
静看大神们
作者: 存少    时间: 2016-9-10 08:38
要是把你写的方法都写成静态的方法呢
作者: 菜鸟V    时间: 2016-9-20 23:24
楼主 要逆天啊!
作者: 浪弦丶    时间: 2016-11-17 00:39
本帖最后由 浪弦丶 于 2016-11-17 00:41 编辑

/*
    需求:我希望在不改变A类和B类的代码,并且C类要继承B类的前提下,
         在C类的XXX方法中调用A类的XXX方法。
    分析:并没有说在C类方法里面不能传参。

*/

   abstract class A extends Object {
        public void xxx() {
            System.out.println("A");
        }
    }
   
    abstract class B extends A {
        public void xxx() {
            System.out.println("B");
        }
    }
   
    class C extends B {
        public void xxx(Object A) {
           this.get();

        }
    }

public class ATest {
        public static void main(String[] args) {
                A a =new C();
            //这里掉A的get方法其实就是调B覆盖方法
                a.get();
        }
        

}

作者: liudan    时间: 2016-11-24 14:02
使用super关键字就可以访问被子类重写的方法。





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2