Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java字节码,没有这样的方法错误_Java_Bytecode_Return Type - Fatal编程技术网

Java字节码,没有这样的方法错误

Java字节码,没有这样的方法错误,java,bytecode,return-type,Java,Bytecode,Return Type,我们可能看到了错误: java.lang.NoSuchMethodError:com.nhn.user.UserAdmin.addUser(Ljava/lang/String;)V 这表示找不到没有返回类型的方法addUser。这可能是因为库可能会更新,但应用程序的字节码仍然很旧 但是当我们研究Java重载时,我们可以知道Java不支持只改变返回类型的重载 既然这是正确的,为什么字节码会记下被调用方法的返回类型,并在使用该方法的返回类型更新库时引发错误呢 该方法可能已在接口中声明,然后重载。因此

我们可能看到了错误:

java.lang.NoSuchMethodError:com.nhn.user.UserAdmin.addUser(Ljava/lang/String;)V

这表示找不到没有返回类型的方法
addUser
。这可能是因为库可能会更新,但应用程序的字节码仍然很旧

但是当我们研究Java重载时,我们可以知道Java不支持只改变返回类型的重载


既然这是正确的,为什么字节码会记下被调用方法的返回类型,并在使用该方法的返回类型更新库时引发错误呢

该方法可能已在接口中声明,然后重载。因此,当您更改该方法的实现版本时,它导致了一个错误。如果返回类型不匹配,但名称相同,仍然会导致错误。无法仅更改返回类型,因为编译器在调用方法时无法知道要使用哪种返回类型。

Java字节码是强类型并经过验证的,这意味着调用方的代码必须与调用的方法返回的内容兼容。因此,即使调用方的方法引用不包含预期的返回类型,代码仍然包含隐式假设,例如,尝试执行
long
算术,结果表明该方法预期返回
long
,而不是
Object
void

让方法引用指示预期的返回类型可以简化验证,并使整个过程更加高效。您可以使用预期的方法签名来验证方法代码的正确性,而无需执行实际链接。当方法调用指令最终链接时,无需验证可执行代码,只需匹配签名即可

这就是为什么Java字节码是这样设计的,即使Java源代码不能定义不同的返回类型,至少在早期版本中是这样。从Java5开始,规则不再那么严格了

考虑以下接口:

interface StringFunction<R> {
    R apply(String input);
}
声明更具体的返回类型不仅是允许的,而且实际上是Java语言所需要的,因为根据泛型类型系统,它继承了
Integer apply(String)
的抽象方法
StringFunction

在字节码级别上,它将有实际的实现方法
整数应用(字符串)
以及桥接方法
对象应用(字符串输入)
正式履行字节码级别上的
接口
合同,并委托给实际的实现方法

由于泛型有效地允许缩小返回类型,因此对于非泛型方法没有理由拒绝它,因此,Java也允许自Java 5以来的所谓协变返回类型:

class Base {
    Object getValue() {
        return null;
    }
}
class Sub extends Base {
    @Override String getValue() {
        return "now a string";
    }
}
因此,可以生成具有多个方法的类,这些方法具有相同的参数类型,但返回类型不同,尽管不是通过重载


这些情况可以交替处理,例如,通过定义方法仅通过参数类型进行区分,并且它们的返回类型必须相同或更具体,以便与协变返回类型兼容,但这意味着JVM在构建类的方法表时必须急切地解析所有返回类型,验证类型是否确实更具体。尽管如此,它仍然需要对返回类型进行编码,以便在调用者和被调用者之间建立适当的契约。

我理解了错误背后的原因,我的问题是,当我们不能重载一个方法时,只改变返回类型,为什么JVM会记录该方法的返回类型详细信息?存储方法的返回类型信息有什么用。如果返回类型发生更改,是否应该引发错误?如果您正在从库中指定方法的结果,但随后该库发生了更改,因此它返回void或不兼容的对象,那么会发生什么情况?这是我第二次阅读您关于协方差的答案。我很确定我在读它们之前理解了这意味着什么,男孩,我错了…@尤金:我真的很喜欢解释差异…
class Base {
    Object getValue() {
        return null;
    }
}
class Sub extends Base {
    @Override String getValue() {
        return "now a string";
    }
}