解释java.lang.NoSuchMethodError消息

dou*_*mer 66 java nosuchmethoderror

我收到以下运行时错误消息(以及堆栈跟踪的第一行,指向第94行).我试图弄清楚为什么它说不存在这样的方法.

java.lang.NoSuchMethodError: 
com.sun.tools.doclets.formats.html.SubWriterHolderWriter.printDocLinkForMenu(
    ILcom/sun/javadoc/ClassDoc;Lcom/sun/javadoc/MemberDoc;
    Ljava/lang/String;Z)Ljava/lang/String;
at com.sun.tools.doclets.formats.html.AbstractExecutableMemberWriter.writeSummaryLink(
    AbstractExecutableMemberWriter.java:94)
Run Code Online (Sandbox Code Playgroud)

writeSummaryLink的第94行如下所示.

问题
"ILcom"或"Z"是什么意思?
为什么括号中有四种类型(ILcom/sun/javadoc/ClassDoc; Lcom/sun/javadoc/MemberDoc; Ljava/lang/String; Z),括号后面有一个Ljava/lang/String; 当方法printDocLinkForMenu显然有五个参数?

代码详细信息
writeSummaryLink方法是:

protected void writeSummaryLink(int context, ClassDoc cd, ProgramElementDoc member) {
    ExecutableMemberDoc emd = (ExecutableMemberDoc)member;
    String name = emd.name();
    writer.strong();
    writer.printDocLinkForMenu(context, cd, (MemberDoc) emd, name, false);  // 94
    writer.strongEnd();
    writer.displayLength = name.length();
    writeParameters(emd, false);
}
Run Code Online (Sandbox Code Playgroud)

这是第94行调用的方法:

public void printDocLinkForMenu(int context, ClassDoc classDoc, MemberDoc doc,
        String label, boolean strong) {
    String docLink = getDocLink(context, classDoc, doc, label, strong);
    print(deleteParameterAnchors(docLink));
}
Run Code Online (Sandbox Code Playgroud)

JRL*_*JRL 87

从JVM规范的4.3.2节:

Character     Type          Interpretation
------------------------------------------
B             byte          signed byte
C             char          Unicode character
D             double        double-precision floating-point value
F             float         single-precision floating-point value
I             int           integer
J             long          long integer
L<classname>; reference     an instance of class 
S             short         signed short
Z             boolean       true or false
[             reference     one array dimension

4.3.3节,方法描述符:

方法描述符表示方法采用的参数及其返回的值:

MethodDescriptor:
        ( ParameterDescriptor* ) ReturnDescriptor
Run Code Online (Sandbox Code Playgroud)

从而,

(ILcom/sun/javadoc/ClassDoc;Lcom/sun/javadoc/MemberDoc;Ljava/lang/String;Z) Ljava/lang/String;

翻译为:

用的方法int,ClassDoc,MemberDoc,Stringboolean作为参数,并且返回一个String.请注意,只有参考参数用分号分隔,因为分号是其字符表示的一部分.


所以,总结一下:

为什么括号中有四种类型(ILcom/sun/javadoc/ClassDoc; Lcom/sun/javadoc/MemberDoc; Ljava/lang/String; Z),括号后面有一个Ljava/lang/String; 当方法printDocLinkForMenu显然有五个参数?

有五个参数(int,ClassDoc,MemberDoc,String,boolean)和一个返回类型(String).

  • 谢谢.我删除了我的类文件,重新编译,不再收到错误消息.显然,错误是一个没有得到更新的旧班级.我非常感谢类型引用的JVM规范的引用,解释为什么错误消息在原始类型之后没有分号,以及如何识别返回类型. (2认同)
  • 我在最后一个括号后猜测一个V意味着该方法没有返回值(void). (2认同)

Bal*_*usC 18

"ILcom"或"Z"是什么意思?

这些是本机类型的映射类型.你可以在这里找到一个概述.

Native Type    | Java Language Type | Description      | Type signature
---------------+--------------------+------------------+----------------
unsigned char  | jboolean           | unsigned 8 bits  | Z
signed char    | jbyte              | signed 8 bits    | B
unsigned short | jchar              | unsigned 16 bits | C
short          | jshort             | signed 16 bits   | S
long           | jint               | signed 32 bits   | I
long long      | jlong              | signed 64 bits   | J
__int64        |                    |                  |
float          | jfloat             | 32 bits          | F
double         | jdouble            | 64 bits          | D

另外,签名"L fully-qualified-class ;"意味着该名称唯一指定的类; 例如,签名"Ljava/lang/String;"指的是类java.lang.String.此外,[签名前缀使得该类型的数组; 例如,[I表示int数组类型.


至于你的下一个问题:

为什么括号中有四种类型(ILcom/sun/javadoc/ClassDoc; Lcom/sun/javadoc/MemberDoc; Ljava/lang/String; Z),括号后面有一个Ljava/lang/String; 当方法printDocLinkForMenu显然有五个参数?

因为您没有运行您认为正在运行的代码.在实际运行的代码试图精确地调用错误消息中描述该方法中,与实际的五个参数(的I应单独计算)和一个String返回类型,但这种方法不会在运行时类路径存在(而这是在现有编译时类路径),因此这个错误.另见NoSuchMethodErrorjavadoc:

如果应用程序试图调用类的指定方法(静态或实例),并且该类不再具有该方法的定义,则抛出该异常.

通常,编译器会捕获此错误; 如果类的定义发生了不兼容的更改,则此错误只能在运行时发生.

因此,请验证您是否实际运行了正确版本的代码,因为您已在问题中发布并且在运行时类路径中使用了正确的依赖项,并且在类路径中没有重复的不同版本库.

更新:该异常表示实际代码(隐式)尝试使用如下方法:

String s = printDocLinkForMenu(context, cd, (MemberDoc) emd, name, false);
Run Code Online (Sandbox Code Playgroud)

因为它String在宣布时期待结果void.

  • @JRL:啊所以显然没有分隔符.`;`似乎是一个分隔符,实际上是`L`类型的一部分. (2认同)