gpt4 book ai didi

java - "method ___() in ___ is defined in inaccessible class or interface"编译错误

转载 作者:IT老高 更新时间:2023-10-28 20:54:18 24 4
gpt4 key购买 nike

我发现了一个奇怪的编译限制,我无法解释,我不明白这个限制的原因。

示例 1:

考虑这些类:

包e1;:

public class C1 {
enum E1 { A, B, C }
public E1 x;
}

包e2;:

import e1.C1;
public class C2 {
public String test(C1 c1) {
return c1.x.toString(); // here compilation error
}
}

这会导致以下编译错误:

Error:(5,20) java: toString() in java.lang.Enum is defined in an inaccessible class or interface

示例 2:

考虑这些类:

包i1;:

public interface I1 {
int someMethod();
}

public class C1 {
static class I2 implements I1 {
public int someMethod() {
return 1;
}
}
public I2 x = new I2();
}

i2包中;:

import i1.C1;
import i1.I1;
public class C2 {
public static void main(String[] args) {
C1 c1 = new C1();
System.out.println(c1.x.someMethod()); // compilation error
}
}

这也会导致相同的编译错误,但如果我们将违规行更改为:

System.out.println(((I1)c1.x).someMethod());

然后可以编译并正常工作。


所以,问题是:

为什么需要这种可访问性限制?

是的,我知道 example-1) 中的类 C1.E 和 example-2) 中的 C1.I2 类是包私有(private)的。 但同时很明显,没有人可以为基接口(interface)(I1 of Object)的方法分配较弱的访问权限,因此直接使用总是安全的将对象转换为其基本接口(interface)并访问受限方法。

有人能解释一下这个限制的目的和原因吗?

更新:assylias指出 JLS §6.6.1 :

A member (class, interface, field, or method) of a reference (class, interface, or array) type or a constructor of a class type is accessible only if the type is accessible...

看起来这是限制,但它没有解释为什么需要这个限制(在上述示例的情况下)...

最佳答案

用于调用实例方法invokevirtual使用指令。要调用这个方法类必须有一个对该方法的解析引用

来自invokevirtual规范:

Linking Exceptions

During resolution of the symbolic reference to the method, any of the exceptions pertaining to method resolution (§5.4.3.3) can be thrown.

5.4.3.3。方法解析:

To resolve an unresolved symbolic reference from D to a method in a class C, the symbolic reference to C given by the method reference is first resolved (§5.4.3.1).

5.4.3.1。类和接口(interface)解析:

If C is not accessible (§5.4.4) to D, class or interface resolution throws an IllegalAccessError.

5.4.4。访问控制:

A class or interface C is accessible to a class or interface D if and only if either of the following conditions is true:

  • C is public.

  • C and D are members of the same run-time package (§5.3).

C 和 D 不是来自同一个包。所以即使java为你编译了这段代码,它也会在调用过程中抛出一个IllegalAccessError。编译器足够聪明,可以防止这种明显的错误。 这些限制来自 java 的类解析过程的要求。

要调用实例方法,JVM 需要两件事:对对象的引用和对象(类或接口(interface))的描述。通过 resolution process 访问描述.如果失败,则调用失败。

If an error occurs during resolution of a symbolic reference, then an instance of IncompatibleClassChangeError (or a subclass) must be thrown at a point in the program that (directly or indirectly) uses the symbolic reference.

在您的情况下,C2 可以访问 I1。所以接口(interface)调用效果很好。但 C2 无权访问 I2 类。这就是为什么如果这段代码编译,IllegalAccessError 可能会在运行时抛出。

如何重现 IllegalAccessError:

  1. 例如公开内部类并在 IDE 中编译所有内容
  2. 将内部类包设为私有(private),并在命令行中使用 javac 对其进行编译。
  3. 将 IDE 生成的类替换为 cmd generated
  4. 您会看到如下内容:

Exception in thread "main" java.lang.IllegalAccessError: tried to access class qq.Test1$I2 from class Test at Test.main(Test.java:30)

关于java - "method ___() in ___ is defined in inaccessible class or interface"编译错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15722184/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com