是否可以在 Java 中使方法成为非虚拟方法?

Is it possible to make methods non-virtual in Java?

我是 java 的新手,我通常使用 C++ 我只是想知道这段代码是否有效

public class ParentClass {
    public void methodA() {
        System.out.println("This is Parent A Method");
        whoAmI();
    }

    public void methodB() {
        System.out.println("This is Parent B Method and I am Calling Method A");
        whoAmI();
        methodA();
    }
}

public class ChildClass extends ParentClass{
    @Override
    public void methodA() {
        System.out.println("This is Child A Method and I am Calling Parents Method A");
        whoAmI();
        super.methodA();
    }

    @Override
    public void methodB() {
        System.out.println("This is Child B Method and I am Calling Parents Method B");
        whoAmI();
        super.methodB();
    }
}
ChildClass c = new ChildClass();
c.methodB();

我期望这样的输出

This is Child B Method and I am Calling Parents Method B
This is Parent B Method and I am Calling Method A
This is Parent A Method

但是

This is Child B Method and I am Calling Parents Method B
This is Parent B Method and I am Calling Method A
This is Child A Method and I am Calling Parents Method A
This is Parent A Method

所以我意识到在java中,所有非静态方法默认都是虚函数,比如c++中的virtual关键字。

有什么办法可以这样输出吗?

This is Child B Method and I am Calling Parents Method B
This is Parent B Method and I am Calling Method A
This is Parent A Method

您可以将 methodAParentClass 实现包装在单独的私有方法中:

public class ParentClass {
    public void methodA() {
        interMethodA();
    }

    private void interMethodA() {
        System.out.println("This is Parent A Method");
        whoAmI();
    }

    public void methodB() {
        System.out.println("This is Parent B Method and I am Calling Method A");
        whoAmI();
        interMethodA();
    }
}

ChildClass 保持不变。

代码 - 按原样 - 无法编译,因为方法 whoAmI() 未定义。通过删除对此方法的调用,I was able to reproduce the output.


据我了解,您想确保 Parent 中的 methodA 是从 Parent 中的 methodB 调用的。由于在 Jjava 中使用 dynamic dispatching 来确定调用哪个实际实现,因此我们必须强制执行 methodA 不能被覆盖。正如@MarquisofLorne 指出的那样,如果 methodAParent.

中定义为 virtual,则 C++ 也使用动态调度

为了强制执行动态调度总是导致调用 ParentmethodA,我想到了两种通用方法:将 methodA 声明为 final 并将 methodA 声明为 private.


方法一:将 Parent 中的 methodA 声明为 final

沿着这条路线走时,Child 不能 re-define methodA,即如果不删除 methodA,代码将导致 compile-time 错误来自 Child.

Ideone demo


方法二:将 Parent 中的 methodA 声明为 private

此方法类似于第一种方法,但允许您在 Child 中保留 methodA,尽管必须删除 @Override-注释,因为无法覆盖私有方法。

Ideone demo

你得到了:

This is Child B Method and I am Calling Parents Method B
This is Parent B Method and I am Calling Method A
This is Child A Method and I am Calling Parents Method A
This is Parent A Method 

而不是

This is Child B Method and I am Calling Parents Method B
This is Parent B Method and I am Calling Method A
This is Parent A Method

只是因为,在 Java 中调用 methodA()this.methodA()ParentClassmethodB() 中调用调用对象或实例的方法,然而这个实例是一个 instanceof ChildClass。 Java 将 methodA()this.methodA() 视为相同。 Java 中的 this 关键字实际上指的是“您正在使用的对象的当前 运行 实例”。意思是,将调用 ChildClass 的覆盖 methodA() 而不是 ParentClass 的 methodA()

这里有一个建议,要获得预期的输出,只需通过注释掉打印行来对 ChildClass 的覆盖 methodA() 进行修改。 否则参考 this 了解更多详情。