首先参考一下 Java8 虚拟机规范中对The Synthetic Attribute的相关描述:A class member that does not appear in the source code must be marked using a Synthetic attribute, or else it must have its ACC_SYNTHETIC flag set. The only exceptions to this requirement are compiler-generated methods which are not considered implementation artifacts, namely the instance initialization method representing a default constructor of the Java programming language, the class initialization method, and the Enum.values() and Enum.valueOf() methods.

The Synthetic attribute was introduced in JDK 1.1 to support nested classes and interfaces.

一个类的源码中未出现的成员必须使用synthetic属性或者ACC_SYNTHETIC标志,但例外是编译期所生成的默认构造函数、类初始化方法,以及Enum.values()和Enum.valueOf()。

首先我来尝试着编译出一些存在synthetic访问权限的字节码:

public final class Singleton {

public static Singleton getInstance() {

return Holder.INSTANCE;

}

private static final class Holder {

private static final Singleton INSTANCE = new Singleton();

private Holder() {

throw new UnsupportedOperationException();

}

}

private Singleton() {

// TODO }

}

这是一个典型的静态内部类单例模式,人工反编译结果如下:

public final class Singleton {

public static Singleton getInstance() {

return Holder.access$000();

}

private static final class Holder {

private static final Singleton INSTANCE;

static {

INSTANCE = new Singleton(null);

}

private Holder() {

throw new UnsupportedOperationException();

}

static Singleton access$000() { // synthetic return INSTANCE;

}

}

private Singleton() {

super();

// TODO }

Singleton(Singleton$1 var0) { // synthetic this();

}

static class Singleton$1 { // synthetic }

}

在 Java8 版本下,编译出的代码实际上会多出来两个方法和一个类,从而增大包体积,如果比较在意二进制包体积的大小,建议在这种场景下不要添加private访问权限修饰符。

private访问权限我们很熟悉,私有成员仅被允许在其所在的类以及与其有嵌套关系的类中使用,在 Java11 以下的版本中,实现嵌套类之间访问私有成员的方式,就是在编译期额外生成一些包私有的方法,比如上例中的三处。

嵌套类之间访问私有方法与私有变量,编译期会额外生成带有ACC_SYNTHETIC标志的包私有方法去间接地访问私有成员,这些方法的名字形如 access$000,数字与这些自动生成的方法的顺序有关。对于构造函数,由于其名称必然为,无法用改名的方式实现,因此编译器会额外定义一个类,并以重载的方式自动生成包私有构造函数。实际上在编译后将上例中自动生成的类直接删除也不会影响程序正常运行,因为这个参数被传入null,所以这个类并不会被加载。

在我上次一篇文章讲switch枚举的时候所生成的类,和这里生成的类是同一个,那个用于switch枚举的int[]也带有ACC_SYNTHETIC标志。

由于这些类、方法、字段在源代码中并不存在,因此当发布二进制包后,引用这些二进制包的代码,也不应访问得到这些带有ACC_SYNTHETIC标志的符号,于是编译器将以找不到符号为理由拒绝编译,甚至即使带有ACC_PUBLIC符号也不行。

可以通过使用asm框架修改字节码的方式,强行添加ACC_SYNTHETIC标志,从而将一部分public的API隐藏起来。我已经通过实验证实了这种操作的可行性,在此就不详细展开了。

从 Java11 开始,嵌套类的私有访问权限控制,从编译期被转移到了运行时,编译器不再为此生成synthetic的类与方法,调用私有方法的字节码也从invokespecial换成了invokevirtual,详情请看JEP 181: Nest-Based Access Control。

参考文献

java的synthetic_探索Java中隐藏的访问权限synthetic相关推荐

  1. java 类中有几种访问权限_类中成员的访问权限_Java语言程

    类中成员的访问权限_Java语言程 4.7.2 类中成员的访问权限 Java将类中成员(成员变量和成员方法)的访问权限(可见性)划分为4种情况,按照访问权限的范围大小从小到大列出如下. ·私有(pri ...

  2. centos sudo不能运行_如何在 Linux 中配置 sudo 访问权限 | Linux 中国

    Linux 系统中 root 用户拥有 Linux 中全部控制权力.Linux 系统中 root 是拥有最高权力的用户,可以在系统中实施任意的行为.-- Magesh Maruthamuthu Lin ...

  3. centos sudo不能运行_如何在Linux中配置sudo访问权限

    Linux 系统中 root 用户拥有 Linux 中全部控制权力.Linux 系统中 root 是拥有最高权力的用户,可以在系统中实施任意的行为. 如果其他用户想去实施一些行为,不能为所有人都提供 ...

  4. java中四种默认的权限修饰符,Java中四种访问权限资料整理

    一.Java中有四种访问权限, 其中三种有访问权限修饰符,分别为private.public.protected,还有一种不带任何修饰符(default). 1. private: Java语言中对访 ...

  5. java 爬虫_探索Java 多线程爬虫及分布式爬虫架构

    在我们调试爬虫程序的时候,单线程爬虫没什么问题,但是当我们在线上环境使用单线程爬虫程序去采集网页时,单线程就暴露出了两个致命的问题: 采集效率特别慢,单线程之间都是串行的,下一个执行动作需要等上一个执 ...

  6. Java中四种访问权限总结

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 一.Java中有四种访问权限, 其中三种有访问权限修饰符,分别为private.public.pro ...

  7. Java中4种访问权限修饰符

    在Java编程语言中有四种权限访问控制符,这四种访问权限的控制符能够控制类中成员的可见性. 一.public (1)定义:public是公共的,被public所修饰的成员可以在任何类中都能被访问到. ...

  8. java 权限修饰符_java中4种访问权限修饰符

    在Java编程语言中有四种权限访问控制符,这四种访问权限的控制符能够控制类中成员的可见性. 一.public (1) 定义:public是公共的,被public所修饰的成员可以在任何类中都能被访问到. ...

  9. java 修饰符默认_Java中的默认访问修饰符是什么?

    Java中的默认访问修饰符是什么? 这个问题在这里已有答案: 什么是默认访问修饰符?                                     12个答案 如果我没有明确说明方法或实例变 ...

最新文章

  1. 1.4 满足和优化指标-深度学习第三课《结构化机器学习项目》-Stanford吴恩达教授
  2. 使用@required注解完成依赖检查
  3. python 获取首字母_python获取汉字首字母-Go语言中文社区
  4. Eclipse中部署hadoop2.3.0
  5. oracle导出建表主键,oracle主键自动生成 配合hibernate的生成策略详解
  6. ACM 博弈专题(5种模板)
  7. 刚写的代码,就变成了遗留系统?
  8. ModuleNotFoundError No module named urllib2
  9. 【报告分享】2021年中国人工智能产业研究报告:数字经济时代的产业升级探索.pdf(附下载链接)...
  10. ad采样频率_AD转换器是什么?快来一起学习一下
  11. oracle rman 用户,Oracle RMAN介绍
  12. 字符串压缩-连续字符压缩并输出次数
  13. cjson 对象是json数组型结构体_CJSON中有关于在对象中放数组,数组中放对象,以及其解析...
  14. ubuntu16.04出现重复进入登陆界面问题
  15. 积分商城功能表设计结构以及积分功能模块
  16. RINEX3文件中的toc,toe,IODE区分和了解
  17. 数据分析(2)——假设检验的详细原理步骤
  18. 如何在win7 64下安装ipython notebook
  19. 对比灵敏度丨信噪比 - 开会用的全向麦克风应该怎么选?
  20. Excel怎么设置每页都打印标题行?

热门文章

  1. 计算机在材料中的应用论文,计算机应用毕业论文计算机技术在建筑材料检测中的应用.docx...
  2. 物理层 - 频分复用技术
  3. ESP32的CAN通信
  4. Oracle排序后获取第一条和最后一条值
  5. 访问网络计算机运行里输入IP,开始→运行里输入IP地址后无法访问网络邻居怎么办?...
  6. 微信退款 v2版本 invalid detail参数格式错误
  7. IOS 隐藏 app 桌面 图标
  8. 【5】深度学习之Pytorch——如何使用张量处理文本数据集(语料库数据集)
  9. Q-learning算法辅助求解柔性作业车间调度问题--附带源码测试集模型
  10. Windows 命令使用之 type 命令