代码之家  ›  专栏  ›  技术社区  ›  Buu

强制调用基类方法

  •  2
  • Buu  · 技术社区  · 15 年前

    运行时,以下代码明显打印出“b1/a2/b2”。现在,是否可以打印“a1/a2/b2”(即a method2()应该在a上调用method1(),而不是在b上)?

    注:我没有这样的需要通过多态性,这个问题只是出于好奇。

    class A {
        public void method1() {
            System.out.println("A1");
        }
    
        public void method2() {
            method1();
            System.out.println("A2");
        }
    }
    
    class B extends A {
        @Override public void method2() {
            super.method2();
            System.out.println("B2");
    
        }
    
        @Override public void method1() {
            System.out.println("B1");
        }
    }
    
    public class Tmp {
        public static void main(String args[]) {
            B b = new B();
            b.method2();
        }
    }
    
    6 回复  |  直到 12 年前
        1
  •  1
  •   jldupont    12 年前

    是的,你能做到。 定义内包 :

    package a;
    public class A {
        void method1() {
            System.out.println("A1");
        }
        public void method2() {
            method1();
            System.out.println("A2");
        }
    }
    

    在包中定义b :

    package b;
    import a.A;
    public class B extends A {
        @Override public void method2() {
            super.method2();
            System.out.println("B2");
        }
        void method1() {
            System.out.println("B1");
        }
    }
    

    把你的测试打包 然后运行它。结果是A1/A2/B2。当然,这是不健康的:注意方法1上@override的必要省略-如果您将其放回,您将得到一个编译器错误:

    method does not override or implement a method from a supertype
    
        2
  •  5
  •   harto    15 年前

    我不这么认为,如果你要凌驾于 method1() 在子类中。如果你真的需要这种行为,你必须声明 A.method1() 作为 final 你无法在 B .

    这样做对我没有意义-如果你认为你需要的话,你应该重新考虑你的设计!

        3
  •  1
  •   artemb    15 年前

    您还可以将a.method1设为私有。然后,即使您有b.method1,也将调用a.method1。但我不确定,你应该查一下

        4
  •  1
  •   tpdi    15 年前

    要做到这一点,您必须非虚方法1。要做到这一点,你必须最终决定:

      public final void method1() {....
    

    或者使它成为私有的;在Java中,PIVATE方法总是非虚拟的:

       private void method1() {....
    

    (注意,在C++中,私有方法可以是虚拟的或非虚的;以及在C++中实现模板方法模式清除器的其他内容。)

    这里发生了什么:当通过对象引用调用非静态方法(这是Java中调用非静态对象方法的唯一方法)时,调用的方法取决于引用的对象的实际类型(指向),而不是引用的类型。

    在对象方法中,对该对象的其他方法(或成员)的调用将隐式地以“this.”作为前缀。因此,在方法2中对方法1的调用实际上是:

    public void method2() {
        this.method1();
        System.out.println("A2");
    }
    

    this 是对象引用。在方法2中(在类A中),引用的类型是A,就好像 已宣布:

    A this;
    

    但是这个引用指向一个类型的对象 B ;它可以做到这一点,因为b是派生自、继承、子类、is-a, A .

    如前所述,“当通过对象引用调用非静态方法时,所调用的方法取决于所引用对象的实际类型,而不是引用的类型。”当您实例化B类型的对象并调用method2()时, 你通过了( 是任何非静态函数的隐藏参数)是 指向一个B对象。当b.method2()调用super()时,同样 已传递给a.method2()。

    因此,当.method2()调用method1()时,实际发生的是我们调用 this.method1() 用同样的方法 ,表示 , the 你一下子就进来了 main() 并在上调用了method2()。

    方法1() 因为我们正在对类型为的对象的引用调用method1()。 编译器确保 方法1()的重新定义就是被调用的方法。

        5
  •  0
  •   Uri    15 年前

    使用标准的“自然”和公认的Java机制是不可能的。Java被设计成使得所有的方法都是动态调度的,除非最终的或静态的(或调用超级),并且在您的情况下。由于方法在B中被重写,因此这些都不是选项。在特定情况下没有“禁用”动态调度的机制,但好消息是很少需要这样做。

    你可以通过反思来克服其中的一些限制,但这就像用大锤打开珍贵的礼物。

        6
  •  0
  •   PC.    13 年前

    甚至我也在寻找这个解决方案。这似乎不可能。 更改基类不是一个选项。也就是说,假设已经编写了基类,并且您正在从它派生一个类,那么在派生类中没有什么可以做的,以便基类调用自己的方法而不是重写的方法。 如果要生成派生类的对象,则基类将调用派生类的重写方法,而不是调用它自己的方法。这是OOP…