查看原文
其他

你知道 Java 中的隐藏类吗?

DD SpringForAll 2022-07-05
关注我,回复关键字“spring”
免费领取Spring学习资料

前几天给大家介绍了Java 17中新推出的密封类,今天继续给大家介绍一个Java 15开始推出的一个新内容:隐藏类

如果你喜欢做封装、做框架的话,这个内容可能对你很有用哦!

什么是隐藏类

隐藏类,是一种不能被其他类直接使用的类。引入隐藏类的主要目的是给框架来使用,使得框架可以在运行时生成类,并通过反射间接使用它们。

可能有点抽象,不要紧,下面我们通过一个例子来直观的认识它!

如果你关注Java前沿知识,记得关注公众号:程序猿DD,持续分享前沿技术内容,积累普通技术人的弯道超车资本!

隐藏类案例

第一步:先创建一个普通的Java类

public class JEP371HiddenClasses {

    public static String hello() {
        return "https://www.didispace.com";
    }

}

第二步:编译一下,或得编译后的class文件。然后使用Base64对文件内容Encode,你可以用各种工具,也可以用下面代码来获取:

String filePath = "JEP371HiddenClasses.class";
byte[] b = Files.readAllBytes(Paths.get(filePath));
log.info(Base64.getEncoder().encodeToString(b));

执行一下,获取到内容如下:

yv66vgAAAD0AFAoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCAAIAQAZaHR0cHM6Ly93d3cuZGlkaXNwYWNlLmNvbQcACgEALmNvbS9kaWRpc3BhY2UvZGVidWcvamF2YTE1L0pFUDM3MUhpZGRlbkNsYXNzZXMBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAMExjb20vZGlkaXNwYWNlL2RlYnVnL2phdmExNS9KRVAzNzFIaWRkZW5DbGFzc2VzOwEABWhlbGxvAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAYSkVQMzcxSGlkZGVuQ2xhc3Nlcy5qYXZhACEACQACAAAAAAACAAEABQAGAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAAAwANAAAADAABAAAABQAOAA8AAAAJABAAEQABAAsAAAAbAAEAAAAAAAMSB7AAAAABAAwAAAAGAAEAAAAGAAEAEgAAAAIAEw==

这个内容就是第一步写的类。

第三步:通过反射加载上面生成的类,并调用隐藏类中的hello函数,代码如下:

/**
 * 程序猿DD
 * <a href="https://www.didispace.com/java-features/">Java新特性解读</a>
 */

@Test
void testHiddenClasses() throws Throwable {
  // 1. 加载encode之后的隐藏类
  String CLASS_INFO = "yv66vgAAAD0AFAoAAgADBwAEDAAFAAYBABBqYXZhL2xhbmcvT2JqZWN0AQAGPGluaXQ+AQADKClWCAAIAQAZaHR0cHM6Ly93d3cuZGlkaXNwYWNlLmNvbQcACgEALmNvbS9kaWRpc3BhY2UvZGVidWcvamF2YTE1L0pFUDM3MUhpZGRlbkNsYXNzZXMBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAMExjb20vZGlkaXNwYWNlL2RlYnVnL2phdmExNS9KRVAzNzFIaWRkZW5DbGFzc2VzOwEABWhlbGxvAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAApTb3VyY2VGaWxlAQAYSkVQMzcxSGlkZGVuQ2xhc3Nlcy5qYXZhACEACQACAAAAAAACAAEABQAGAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAAAwANAAAADAABAAAABQAOAA8AAAAJABAAEQABAAsAAAAbAAEAAAAAAAMSB7AAAAABAAwAAAAGAAEAAAAGAAEAEgAAAAIAEw==";
  byte[] classInBytes = getDecoder().decode(CLASS_INFO);
  Class<?> proxy = MethodHandles.lookup()
    .defineHiddenClass(classInBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE)
    .lookupClass();

  // 输出类名
  log.info(proxy.getName());
  // 输出类有哪些函数
  for(Method method : proxy.getDeclaredMethods()) {
    log.info(method.getName());
  }
  // 2. 调用hello函数
  MethodHandle mh = MethodHandles.lookup().findStatic(proxy, "hello", MethodType.methodType(String.class));
  String result = (String) mh.invokeExact();
  log.info(result);
}

具体执行逻辑就不啰嗦了,读者可以根据注释来理解。最后执行这个测试内容,可以获得如下输出:

17:20:50.360 [main] INFO com.didispace.debug.java15.JEP371Test - com.didispace.debug.java15.JEP371HiddenClasses/0x0000000800cb0c00
17:20:50.361 [main] INFO com.didispace.debug.java15.JEP371Test - hello
17:20:50.361 [main] INFO com.didispace.debug.java15.JEP371Test - https://www.didispace.com
  • 第一行:输出了这个隐藏类的类名
  • 第二行:输出了这个隐藏类下的方法名称
  • 第三行:调用隐藏类下的hello方法获得的返回内容

是不是还挺简单?如果你跟我一样平时会参与一些基础框架和平台的开发工作的话,一定觉得这个功能还挺不错的吧,毕竟又多了一种动态功能的实现手段!

好了,今天的分享就到这里!关于Java新特性这个专题,我正在连载Java新特性专栏:https://www.didispace.com/java-features/,文档形式看Java新特性,阅读学习体验更佳!

如果你最近想跳槽的话,年前我花了2周时间收集了一波大厂面经,节后准备跳槽的可以点击这里领取



END



利用多线程批量拆分 List 导入数据库,效率杠杠的!
详解 Java 17中的新特性:“密封类”
一分钟了解switch增强功能,跟Break说再见!
在Java中new一个对象的流程是怎样的?


关注后端面试那些事,回复【2022面经】

获取最新大厂Java面经


最后重要提示:高质量的技术交流群,限时免费开放,今年抱团最重要。想进群的,关注SpringForAll社区,回复关键词:加群,拉你进群。

点击“阅读原文”领取2022大厂面经
↓↓↓ 

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存