在Java中重载重写的方法

在Java中重载重写的方法,java,inheritance,Java,Inheritance,我有一个实现接口a的类B,这样: public interface A { Map<String, Object> doStuff(Integer param1, Integer Param2); } public class B implements A { public Map<String, Object> doStuff(Integer param1, Integer param2) { return doStuff(para

我有一个实现接口a的类B,这样:

public interface A {

    Map<String, Object> doStuff(Integer param1, Integer Param2);
}

public class B implements A {

    public Map<String, Object> doStuff(Integer param1, Integer param2) {
        return doStuff(param1, param2, newParam3);
    }

    public Map<String, Object> doStuff(Integer param1, Integer Param2, boolean param3) {
        if (param3)
            doSomething;
        return doneStuff;
    }
}
公共接口A{
Map doStuff(整数参数1,整数参数2);
}
公共类B实现了{
公共映射doStuff(整数参数1,整数参数2){
返回doStuff(参数1、参数2、新参数3);
}
公共映射doStuff(整数参数1、整数参数2、布尔参数3){
如果(参数3)
剂量测定法;
返回doneStuff;
}
}

但是,当我试图访问重载但未重写的方法时,会出现编译时错误。这不是很好吗?

在java方法调用中有两个完全分离的步骤

步骤1是:将方法调用(在源代码中)转换为完全限定的方法ID。这完全发生在编译时

第2步是:现在我们有了一个完全限定的方法ID,通过动态查找,从对象的实际实例类型(
x.getClass()
)开始,在层次结构中向上查找,直到找到一个实现,从而找到该ID的实际实现这完全发生在运行时

完全限定的方法ID包括包、类、方法名称、参数类型和返回类型

因此,在B类中,您有两个不同的方法ID。不同的方法id是不同的方法;名称相同这一事实与此无关

换言之,这:

A x = new B();
x.doStuff(param1, param2);
存储为方法
com.foo.pkg.A::doStuff(Ljava/lang/Integer;L/java/lang/Integer;)Ljava/util/Map的INVOKEVIRTUAL/INVOKEINTERFACE。那确实在班级档案里;看看
javap
的输出,或者用十六进制编辑器打开它,你会发现其中的字符串,至少从
doStuff
开始

然后,仅在运行时,“INVOKEINTERFACE com.foo.pkg.A doStuff(Ljava/lang/Integer;L/java/lang/Integer;)Ljava/util/Map
bytecode指令检查您的
x
变量指向的对象的类型,发现它是
com.foo.pkg.B`,然后将实际调用B的这个方法的实现来完成这项工作

第二个doStuff方法具有方法ID
bdostuff(Ljava/lang/Integer;Ljava/lang/Integer;Z)Ljava/util/Map-注意这是一个完全不同的方法(这个方法中有一个Z)

因此,这:

A x = new B();
x.doStuff(1, 2, true);

是一个编译错误:a接口根本没有这个方法。

“我得到编译时错误”-哪一个?你的编译时错误是什么?我的猜测是你试图在
a
引用上访问
doStuff(1,2,3)
,在这种情况下是禁止的,因为该方法不是接口的一部分哦,没错,引用是指向接口,而不是实现的类。哇,很好的猜测哈,我完全没有意识到这个答案对于一个部分形成的问题来说太好了:)Andrew Tobilko和rzwitserloot关于引用到接口而不是实现类的说法都是正确的。在我的辩护中,两者的类名都有50多个字符长,实现类以“Impl”结尾是它们之间唯一的区别(X)