处理继承时出现IllegalAccessError - 为什么?

时间:2017-09-27 09:46:29

标签: java inheritance

我找到this JDK bug并想了解它为什么会发生。

方案(取自the bug report)非常简单:class声明private方法,interface声明public方法相同的签名。它编译没有错误。

但是,当我运行此代码时,我收到IllegalAccessError

interface I {
    public void m();
}

class A {
    private void m() {
        System.out.println("Inside Class A");
    }

}

abstract class B extends A implements I {
}

class C extends B {
    public void m() {
        System.out.println("Inside Class C");
    }
}

public class Test {
    public static void main(String... args) {
        B b = new C();
        b.m();
    }
}

请帮助我理解为什么会出现此错误我的代码编译正常

Exception in thread "main" java.lang.IllegalAccessError:  
tried to access method A.m()V from class Test
    at Test.main(Test.java:25)

3 个答案:

答案 0 :(得分:7)

它汇总,因为一切似乎都很好。

然而,mswinpr2被翻译为在Ghostscript中搜索签名b.m(),显然在m()中首先搜索并且稍后在接口中(预期)。在B中找到了私人A 爆炸

语言行为不一致,编译器在理论上可以避免。

<强> 重述

在编译期间找到了公共接口方法 - 很好。在运行期间,在A中找到(无修饰符)签名,其中方法是私有的,永远不会到达方法公开的接口中的签名。

[FYI]使用javap进行反汇编

A

当然是在m()对象上。

答案 1 :(得分:1)

它编译,因为类B是一个抽象类,声明它实现了接口I - 它假定实现将具有所需的方法。

对象b的类型在编译时声明为B.你可以看到它是B而不是C,如下所示:

如果你在c类中有一个新方法

,那么用一个例子来简化它
FTP.retrbinary

然后尝试在你的主程序中调用它,不会编译。

class C extends B {
    public void m() {
        System.out.println("C.m");
    }

    public void testFromC() {}
}

如果你在B中添加一个方法,那就没关系。

public static void main(String[] args) {
    B b = new C();
    b.testFromC(); // doesnt compile
}

当它运行程序时,将其视为B类的对象,它从A中找到了私有的实现。如果强制b通过强制转换为C类型,它将起作用。

abstract class B extends A implements I {
    public void testFromB() { }
}

public static void main(String[] args) {
    B b = new C();
    b.testFromB(); // compiles
}

此外,如果您删除A的私有实现,它也可以在没有强制转换的情况下工作。

public static void main(String[] args) {
    B b = new C();
    ((C)b).testFromC();
}

现在可以使用:

class A {
    //private void m() {
    //System.out.println("A.m");
    //}
}

正如我现在所理解的那样,它首先在运行时检查B或其父级上的方法m,如果没有找到任何内容,则转到B类的实现。

答案 2 :(得分:1)

这是一个已知问题,目前已在此处进行跟踪:

JDK-8021581 Private class methods interfere with invocations of interface methods

此票证确实包含对问题的详细分析,对兼容性问题的讨论以及提议的解决方案的风险,并且仍然是开放的。

可以在此处找到关于该主题的较早讨论:

JDK-6684387 IllegalAccessError for code passed by compiler
shmosel中的his commentJDK-6691741 JLS membership algorithm is too strong for JVMS method resolution相关联 - 感谢您的支持

class bindings