jep122_JEP 181不兼容,嵌套类/ 2

jep122

JEP 181是基于嵌套的访问控制https://openjdk.java.net/jeps/181 。 它是在Java 11中引入的,它故意引入了与先前版本的不兼容性。 这是一个很好的例子,与Java的早期版本兼容并不是刻板的规则,而是保持语言的一致性和稳定发展。 在本文中,我将通过几年前遇到的一个示例来研究这种变化,以及在这种特殊情况下Java 11如何使生活更轻松,更一致。

Java向后兼容性仅限于功能而非行为

原始情况

几年前,当我编写可以用Java方法扩展的ScriptBasic for Java解释器时,使它们就像用BASIC编写一样可用,我创建了一些单元测试。 单元测试类包含一些内部类,其中具有一些可用于BASIC代码的方法。 内部类是静态的和私有的,因为它与除测试之外的任何其他类无关,但是,该类和方法仍可被测试代码访问,因为它们位于同一类中。 令我沮丧的是,这些方法无法通过BASIC程序访问。 当我尝试通过本身使用反射访问的BASIC解释器调用方法时,出现了IllegalAccessException

为了纠正这种情况,经过几个小时的调试和学习,我创建了以下简单代码:

package javax0;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflThrow {
    private class Nested {
        private void m(){
            System.out.println("m called");
        }
    }
    public static void main(String[] args)
            throws NoSuchMethodException,
            InvocationTargetException,
            IllegalAccessException {
        ReflThrow me = new ReflThrow();
        Nested n = me.new Nested();
        n.m();
        Method m = Nested.class.getDeclaredMethod("m");
        m.invoke(n);
    }
}

如果使用Java N(其中N <11)运行此代码,则会得到类似以下内容:

m called
Exception in thread "main" java.lang.IllegalAccessException: class ReflThrow cannot access a member of class ReflThrow$Nested with modifiers "private"
    at java.base/jdk.internal.reflect.Reflection.throwIllegalAccessException(Reflection.java:423)
    at java.base/jdk.internal.reflect.Reflection.throwIllegalAccessException(Reflection.java:414)
...

但是,它可以在Java 11上正常运行(并且大概在更高版本的Java中也可以正常运行)。

说明

直到Java 11版本,JVM都不处理内部和嵌套类。 JVM中的所有类都是顶级类。 Java编译器从内部和嵌套类创建一个特别命名的顶级类。 例如,一个Java编译器可以创建类文件ReflThrow.classReflThrow$Nested.class 。 因为它们是JVM的顶级类,所以当ReflThrow类是两个不同的顶级类时,它们中的代码无法调用Nested的私有方法m()

但是,在Java级别,从嵌套结构创建这些类是可能的。 为了实现这一点,编译器在Nested类中创建了一个额外的合成方法, ReflThrow中的代码可以调用该方法,而Nested已经存在的该方法将调用m()

合成方法具有修饰符SYNTHETIC因此编译器随后知道其他代码不应“看到”这些方法。 这样,调用方法m()效果很好。
另一方面,当我们尝试使用名称和反射访问来调用方法m() ,路由直接通过类边界,而无需调用任何合成方法,并且由于该方法对于它所在的类是私有的,因此调用引发异常。

Java 11对此进行了更改。 包含在已经发布的Java 11中的JEP 181引入了概念嵌套。 “嵌套允许类在逻辑上属于同一代码实体,但被编译成不同的类文件,而无需编译器插入可扩展访问性的桥方法,即可访问彼此的私有成员。” 它仅表示存在作为嵌套的类,并且存在属于嵌套​​的类。 从Java生成代码时,顶级类是嵌套类,而内部的类是嵌套的。 JVM级别的此结构为不同的语言结构留有很大空间,并且不会在执行环境中出现Java结构的麻烦。 JVM旨在成为多语言的,并且随着将来GraalVM的推出,它甚至将成为“更多”的多语言。 使用这种结构的JVM仅仅看到两个类在同一个嵌套中,因此它们可以互相访问private方法,字段和其他成员。 这也意味着没有桥接方法具有不同的访问限制,并且反射与普通的Java调用完全通过相同的访问边界。

摘要/外卖

Java不会一夜之间发生变化,并且大部分是向后兼容的。 但是,向后兼容性仅限于功能而非行为。 JEP181没有,并且它从未真正打算重现对嵌套类的反射访问的并非绝对完美的IllegalAccessException抛出行为。 此行为是实现行为/错误,而不是语言功能,并且已在Java 11中修复。

翻译自: https://www.javacodegeeks.com/2018/10/jep-181-incompatibility-nesting-classes.html

jep122

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值