【问题标题】:Java code compiles but yields IllegalAccessErrorJava 代码编译但产生 IllegalAccessError
【发布时间】:2011-11-10 09:55:39
【问题描述】:

在下面的代码中,我给出了两个主要类 - TestWorks 和 TestCompilesButFails。我不确定我是否理解失败 - 似乎 Arrays.asList() 表达式被赋予“AbstractBaseClass 列表”类型,但为什么在这里给出引用包​​本地类的类型是正确的在另一个包中?

// failing test class
import somepackage.*;
import java.util.Arrays;

public class TestCompilesButFails {
    public static void main(String [] args){
        // fails here with java.lang.IllegalAccessError: 
        // tried to access class somepackage.AbstractBaseClass 
        // from class TestCompilesButFails
        for (Object o : Arrays.asList(new ConcreteA(), new ConcreteB())) { 
            System.out.println(o);
        }
    }
}


// package-local abstract base class
package somepackage;

abstract class AbstractBaseClass {
    public abstract void doSomething();
}

// next two classes - public extenders of abstract base class
package somepackage;

public class ConcreteA extends AbstractBaseClass {
    public void doSomething(){
        System.out.print("Look, ma!\n");
    }
}

package somepackage;

public class ConcreteB extends AbstractBaseClass {
    public void doSomething(){
        System.out.print("No types!\n");
    }
}

// working test 
import somepackage.*;

public class TestWorks {
    public static void main(String [] args){
        new ConcreteA().doSomething();
        new ConcreteB().doSomething();
    }
}

【问题讨论】:

  • 只是为了消除另一个因素 - 将 Arrays.asList() 替换为 private static List myAsList(T first, T second) 会出现同样的问题 - 它与可变参数无关在 Arrays.asList()

标签: java generics types module packages


【解决方案1】:

因为Java语言规范中的类型推断算法specified没有考虑类型可见性:

超类型约束 T :> X 暗示解是 X 的超类型之一。给定 T 上的几个这样的约束,我们可以与每个约束隐含的超类型集合相交,因为类型参数必须是成员他们所有人中。然后我们可以选择交叉路口中最具体的类型。

至于他们为什么这样定义它,我怀疑这是为了避免为了处理罕见的极端情况而使已经相当复杂的算法变得更加复杂。毕竟他们也写:

还要注意,类型推断不会以任何方式影响可靠性。如果推断的类型是无意义的,则调用将产生类型错误。类型推断算法应该被视为一种启发式算法,旨在在实践中表现良好。如果它无法推断出所需的结果,则可以使用显式类型参数。

在你的情况下是:

    for (Object o : Arrays.<Object>asList(new ConcreteA(), new ConcreteB())) { 
        System.out.println(o);
    }

【讨论】:

  • 感谢您在 java 规范中找到相关部分 - 我怀疑它只是在寻找最“特定”的共同祖先而不考虑可见性。
  • 我仍然不确定为什么指定最具体的可见祖先在实践中会更加复杂......我必须考虑一下。
【解决方案2】:

认为你指的是java的“包保护”分类;因此,未声明为公共、私有或受保护的方法或变量是“包保护的”,因此可以被该包中的任何类访问。它并没有被太多使用(谢天谢地),我认为它不是一个好的默认值,但从 Java 1.0 开始就是这样。

【讨论】:

  • 将我的问题更改为更明确地引用本地包。不过,我的问题仍然存在。
  • 顺便说一句,我发现包本地类非常有用。
  • 除非真的必要,否则尽量不要使用包范围。这会损害可重用性。
  • @Steven 是的 - 当您想要可重用性时,包范围很有用,但是当您想要在类级别隐藏信息时。
  • 我经常在我的一个中型(大约 20k 本地)项目中创建包本地类。在编写 api 时,编写帮助类供内部使用而不将它们暴露给外部世界通常是有意义的。我不确定我理解什么是“黑客代码”...
猜你喜欢
  • 1970-01-01
  • 2015-11-11
  • 1970-01-01
  • 2020-12-11
  • 1970-01-01
  • 2012-11-10
  • 1970-01-01
  • 1970-01-01
  • 2012-01-03
相关资源
最近更新 更多