当我运行下面的源代码时,我在shell窗口中看到的运行时错误如下:
Exception in thread "main" java.lang.IllegalAccessError: tried to access method
pkgs.test.B.mStaPro()V from class pkgs.main.Main3
at pkgs.main.Main3.m6(Main3.java:919)
at pkgs.main.Main3.main(Main3.java:9)
字母V的含义是什么,在上面的mStaPro()之后看到了什么?
这是我的源代码,全部编译:
类Main3,包main:
package pkgs.main;
import pkgs.test.B;
class Main3 {
static public void main(String args[]) {
new Main3().m6();
}
void m6() {
B.mStaPro();
}
}
A类,包主:
package pkgs.main;
public class A {
static protected void mStaPro() { System.out.println("A mStaPro()"); }
}
B类,包测试:
package pkgs.test;
import pkgs.main.A;
public class B extends A {
// Note: if this line below is commented out, then the runtime exception
// mentioned in this post's title is not seen.
static protected void mStaPro() { System.out.println("B mStaPro()"); }
}
以下是基于shell的编译和运行批处理文件的内容:
REM For compilation:
javac -Xlint -sourcepath ..\src -d ..\cls ..\src\pkgs\main\Main3.java
REM For running:
java -cp ..\cls pkgs.main.Main3
请注意我在B班内发表的评论。非常感谢任何评论。
修改
我尝试使用Apache Ant构建我的源代码,但获得的结果是相同的:
run:
[java] Exception in thread "main" java.lang.IllegalAccessError: tried to access method pkgs.test.B.mStaPro()V from class pkgs.main.Main3
[java] at pkgs.main.Main3.m6(Main3.java:11)
[java] at pkgs.main.Main3.main(Main3.java:7)
[java] Java Result: 1
main:
BUILD SUCCESSFUL
请注意,在本文顶部的第一个异常错误消息中,我在源代码中注释了很多代码,因此该错误消息与Ant上面的错误消息之间的行号不同。
我尝试过的另一件事是将JDK从版本1.7.0_40升级到版本1.7.0_55。
编辑2:
这是我的Apache Ant build.xml文件。它几乎与Apache Ant网站上提供的教程build.xml文件完全相同:
<project name="Main3 test" basedir="." default="main">
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.dir" value="${build.dir}/jar"/>
<property name="main-class" value="pkgs.main.Main3"/>
<target name="clean">
<delete dir="${build.dir}"/>
</target>
<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}"
includeantruntime="false" debug="true"
debuglevel="lines,vars,source" />
</target>
<target name="jar" depends="compile">
<mkdir dir="${jar.dir}"/>
<jar destfile="${jar.dir}/${ant.project.name}.jar"
basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
</manifest>
</jar>
</target>
<target name="run" depends="jar">
<java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/>
</target>
<target name="clean-build" depends="clean,jar"/>
<target name="main" depends="clean,run"/>
</project>
答案 0 :(得分:5)
Java类通常在三个阶段验证(粗略地说):
Java编译器捕获了大多数编程错误。但是,pkgs.main.A#mStaPro
方法的pkgs.test.B#mStaPro
方法会欺骗Java编译器。以下是发生的事情:
编译Main
课程时,您正在static
上调用mStaPro
方法B
。问题是,您是否正在调用pkgs.main.A
类中定义的阴影方法或pkgs.test.B
类中定义的隐藏方法?在这个问题中,Java编译器和Java运行时得出了不同的结论,这就是为什么Java编译器在Java运行时拒绝它时批准你的代码的原因:
mStaPro
中定义的A
方法。 A
类与Main
位于同一个包中,因此其protected
方法Main
类为mStaPro
类。B
中定义的protected
方法。此方法也是pkgs.test
,但它在mStaPro
包中定义。因此,不得从位于其他包中的Main
调用此IllegalAccessError
。为了通知您有关此非法代码的信息,Java运行时会抛出您遇到的Main#m
。让我们在这里更进一步。如果查看生成的method shadowing (hiding),invokestatic #5 // Method pkgs/test/B.mStaPro:()V
return
方法编译如下:
B.mStaPro()
return // a void return statement is implicit in Java source code
类似于您的Java源代码:
B
此编译结果与mStaPro
类是否定义方法B
无关。这是您遇到异常的原因。如果mStaPro
类定义方法invokestatic
,则B#mStaPro
调用绑定到A#mStaPro
方法(什么是非法的)。否则,调用绑定到A.mStaPro()
(什么是合法的)。
要解决此问题,您应该将实际目标类命名为B
,而不是在static
上调用该方法。但是,我必须诚实地说,我发现Java编译器的行为反直觉。 B.mStaPro()
方法是静态的而非动态的。因此,Java编译器应该在编译时静态绑定pkgs/main/A.mStaPro:()V
到B
的调用。实际上,没有这种假设,编译就不会成功。更好的是,当它遇到无法访问的A
正在static
中隐藏目标并且代码无法成功运行时,它应该只是产生编译错误。
最后,在{{1}} {{1}}调用中可能会给出一个关于此行为的小提示,其中提到了这种行为:
被调用的隐藏静态方法的版本取决于 是否从超类或子类调用它。
然而,由于我上面提到的原因,这还不够好。但是,我多年来一直使用Java,因为阴影不是推荐的做法,我从来没有遇到过这个问题。像这样,你真的找到了一个边缘情况。
Info :我将其发布到Java编译器邮件列表中。得到答案后,我会将信息添加到此帖子中。
答案 1 :(得分:1)
更改此行
static protected void mStaPro() { System.out.println("B mStaPro()"); }
到
static public void mStaPro() { System.out.println("B mStaPro()"); }
javadocs-Controlling Access to Members of a Class
在成员级别,您也可以使用public修饰符或no修饰符(package-private),就像使用顶级类一样,并且具有相同的含义。对于成员,还有两个额外的访问修饰符:private和protected。 private修饰符指定只能在自己的类中访问该成员。 protected修饰符指定只能在自己的包中访问该成员(与package-private一样),此外,还可以在另一个包中通过其类的子类访问该成员。
答案 2 :(得分:0)
你的A和B类不在同一个包中,函数B.mStaPro()
是protected
,它不能从其他包中访问,你应该将它们放在同一个包中或使其成为公共
答案 3 :(得分:0)
您无法访问其他包中的类(即,子类以外的类)中的一个包的受保护方法。