JEP 371- 隐藏类 介绍

简介

本文介绍最新的JEP 371提案: 隐藏类,目前该提案正在征求社区意见建议


创建者: Mandy Chung

类型:特性

作用于:SE

状态:提议中

目标版本:15

组件:core-libs / java.lang.invoke

讨论:valhalla dash dev at openjdk dot java dot net

预审:by Alex Buckley, David Holmes, John Rose, Maurizio Cimadamore, Paul Sandoz

认可: by John Rose

创建: 2019/03/13 17:37

更新:2020/04/01 23:24

问题跟踪: 8220607


JEP 371- 隐藏类 介绍

摘要

介绍隐藏的类,这些类是其他类的字节码不能直接使用的类。 隐藏类适用于在运行时生成类并通过反射间接使用它们的框架。 隐藏类可以定义为访问控制嵌套的成员,并且可以独立于其他类进行卸载。


目标

允许框架将类定义为框架的不可发现的实现细节,以便它们不能被其他类链接,也不能通过反射来发现。

支持使用不可发现的类扩展访问控制嵌套。

支持主动卸载不可发现的类,因此框架可以灵活地定义所需数量。

弃用非标准API sun.misc.Unsafe :: defineAnonymousClass,以弃用该API以在将来的发行版中将其删除。

请勿以任何方式更改Java编程语言。


非目标

支持sun.misc.Unsafe :: defineAnonymousClass的所有功能(例如恒定池补丁程序)不是目标。


提案背景原因

基于JVM构建的许多语言实现都依赖于动态类生成,以提高灵活性和效率。 例如,对于Java语言,javac不会在编译时将lambda表达式转换为专用的类文件,而是发出字节码,该字节码可动态生成并实例化一个类以在需要时产生与lambda表达式相对应的对象。 同样,非Java语言的运行时通常使用动态代理来实现那些语言的高级功能,这些代理也可以动态生成类。

语言实现者通常希望动态生成的类在逻辑上成为静态生成的类的实现的一部分。 此意图建议了动态生成的类所需的各种属性:

  • 不可发现性。 通过名字独立地被发现不仅是不必要的,而且是有害的。 它破坏了动态生成的类仅是静态生成的类的实现细节的目标。
  • 访问控制。 可能希望将静态生成的类的访问控制上下文扩展为包括动态生成的类。
  • 生命周期。 动态生成的类可能只需要有限的时间,因此在静态生成的类的生命周期内保留它们可能会不必要地增加内存占用。 针对这种情况的现有解决方法(例如,按类装载器)既麻烦又效率低下。

不幸的是,定义类的标准API(ClassLoader :: defineClass和Lookup :: defineClass)对于该类的字节码是动态生成(在运行时)还是静态生成(在编译时)并不重要。 这些API始终定义一个可见的类,该类将在每次在同一加载器层次结构中的另一个类尝试链接该名称的类时使用。 因此,该类可能比所需的类更容易发现或具有更长的生命周期。 此外,如果嵌套的宿主类事先知道成员类的名称,则API只能定义一个将充当嵌套成员的类。 实际上,这可以防止动态生成的类成为嵌套成员。

如果标准API可以定义无法发现的且具有有限生命周期的隐藏类,则动态生成类的JDK内部和外部框架都可以定义隐藏类。 这将提高所有基于JVM的语言实现的效率。 例如:

  • java.lang.reflect.Proxy 可以定义隐藏类以充当实现代理接口的代理类;
  • java.lang.invoke.StringConcatFactory 可以生成隐藏类来保存常量连接方法;
  • java.lang.invoke.LambdaMetaFactory可以生成隐藏的nestmate类,以保存访问封闭变量的lambda主体;
  • JavaScript引擎可以为从JavaScript程序转换的字节码生成隐藏的类,因为当引擎不再使用它们时,这些类将被卸载。

描述

Java 7中引入的Lookup API允许类获取提供对类,方法和字段的反射访问的查找对象。 至关重要的是,无论最终使用查找对象的代码是什么,反射访问总是在最初获得查找对象的类(查找类)的上下文中发生。 实际上,查找对象将查找类的访问权限传输给接收该对象的任何代码。

Java 9通过引入方法Lookup :: defineClass(byte [])增强了查找对象的传输功能。 根据提供的字节,此方法在与最初获得查找对象的类相同的上下文中定义一个新类。 也就是说,新定义的类与查找类具有相同的定义类加载器,运行时程序包和保护域。

该JEP建议扩展Lookup API以支持定义只能通过反射访问的隐藏类。 JVM在字节码链接期间无法发现隐藏的类,也不能通过显式使用类加载器的程序(例如,通过Class :: forName和ClassLoader :: loadClass)发现隐藏的类。 当隐藏的类不再可访问时,可以将其卸载,也可以共享一个类加载器的生存期,以便仅在对类加载器进行垃圾回收时才将其卸载。 (可选)可以将隐藏类创建为访问控制嵌套的成员。

为简便起见,此JEP称“隐藏类”,但应理解为表示隐藏类或接口。 同样,“普通类”表示普通类或接口,即ClassLoader :: defineClass的结果。


更多详细,请参考原始文章,后面太长了,就是描述他们准备怎么实现


分享到:


相關文章: