Java 中冷门的 synthetic 关键字原理解读
看JAVA的反射时,看到有个synthetic ,还有一个方法isSynthetic() 很好奇,就了解了一下:
1.定义
Any constructs introduced by a Java compiler that do not have a corresponding construct in the source code must be marked as synthetic, except for default constructors, the class initialization method, and the values and valueOf methods of the Enum class.
大意为:由java编译器生成的(除了像默认构造函数这一类的)方法,或者类
2.实例
既然知道synthetic方法和synthetic类是由编译器生成的,那到底编译器会怎么生成这些东西,又在什么情况下会生成这些东西呢?
先看一段代码:
import static java.lang.System.out; public final class DemonstrateSyntheticMethods
{
public static void main(final String[] arguments)
{
DemonstrateSyntheticMethods.NestedClass nested =
new DemonstrateSyntheticMethods.NestedClass();
out.println("String: " + nested.highlyConfidential);
} private static final class NestedClass
{
private String highlyConfidential = "Don't tell anyone about me";
private int highlyConfidentialInt = 42;
private Calendar highlyConfidentialCalendar = Calendar.getInstance();
private boolean highlyConfidentialBoolean = true;
}
}
编译之后,可以看到三个文件:
其中,最下面的这个类文件很好解释,就是我们的主class,中间的文件,是我们的内部类,上面的文件,后面再讲,我们先看一下中间这个内部类
2.1 内部类的反编译结果
用javap 反编译DemonstrateSyntheticMethods$NestedClass.class,得到如下结果:
javap DemonstrateSyntheticMethods\$NestedClass.class
Compiled from "DemonstrateSyntheticMethods.java"
final class DemonstrateSyntheticMethods$NestedClass {
DemonstrateSyntheticMethods$NestedClass(DemonstrateSyntheticMethods$1);
static java.lang.String access$100(DemonstrateSyntheticMethods$NestedClass);
}
先把构造函数放一边,我们来看这个标黑的方法access$100 这个是怎么回事呢?我们的源文件里找不到这个access方法啊?
2.2 synthetic方法
这个方法就是编译器生成的synthetic方法,读者不信的话,可以用method.isSynthetic() 去验证一下。
为何要生成这样一个方法呢?
可以看到,我们的NestedClass类中,highConfidential是一个私有属性,而我们在外部类DemonstrateSyntheticMethods中,直接引用了这个属性。作为一个内部类,NestedClass的属性被外部类引用,在语义上毫无问题,但是这却苦了编译器。
为了能让一个private的变量被引用到,编译器生成了一个package scope的access方法,这个方法就是一个get方法,在外部类使用highConfidential这个属性时,实际是使用了这个access方法。
在javap中可以看到直接的证据:
图中红框的位置,可以很清楚的看到main方法实际上调用了access$100这个方法。
所以,结论很清楚了,编译器为了方便内部类的私有成员被外部类引用,生成了一个get方法,这可以被理解为一个trick,绕开了private成员变量的限制。
2.3 synthetic类
定义已经提到,编译器不仅仅会生成方法,也会生成synthetic类。
我们回过头来看2.1提到的最后一个类DemonstrateSyntheticMethods$1.class
这个类是一个完全的空类,反编译后是这个样子:
// $FF: synthetic class
class DemonstrateSyntheticMethods$1 {
}
这个类只出场了一次,作为内部类NestedClass的package scope的构造函数,如图所示:
那么,这个类的作用呢?笔者查了很多资料,都没有明确的说明这个类的用途,只能根据代码做推测如下:
NestedClass作为一个private类,其默认构造函数也是private的。那么,事实上,作为外部类的DemonstrateSyntheticMethods类,没有办法new这个内部类的对象,而这和我们需要的语义相违背。
那么,为了实现语义,编译器又用了一个trick,悄悄的生成了一个构造函数NestedClass(DemonstrateSyntheticMethods$1 obj), 这个构造函数是包可见的。
那么,外部类则可以通过new NestedClass(null)的方式,得到内部类的对象。如果读者检查一下main方法的话,可以看到这个方法的调用如下图所示。
这就是这个synthetic类的作用。如果我们给我们的NestedClass 增加一个public级别的默认构造函数的话,则可以看到编译器不会再生成这个synthetic类。
3.结论
编译器通过生成一些在源代码中不存在的synthetic方法和类的方式,实现了对private级别的字段和类的访问,从而绕开了语言限制,这可以算是一种trick。
在实际生产和应用中,基本不存在程序员需要考虑synthetic的地方。
PS: 在此提一个的常见的存在synthetic的案例。
如果同时用到了Enum和switch,如先定义一个enum枚举,然后用switch遍历这个枚举,java编译器会偷偷生成一个synthetic的数组,数组内容是enum的实例。
对于这种情况,笔者找到了一个资料,可供参考:
完。
Java 中冷门的 synthetic 关键字原理解读的更多相关文章
- Java中的两个关键字——super、this
Java中的两个关键字——super.this 神话丿小王子的博客主页 一.super super 是java中方的一个关键字,用它可以引用父类中的成员: super可用于访问父类中定义的属性 sup ...
- Java中的50个关键字
form:http://blog.csdn.net/luoweifu/article/details/6776240 Java中的50个关键字 关键字也称为保留字,是指java语言中规定了特定含义的标 ...
- Java中的HashMap的工作原理是什么?
问答题23 /120 Java中的HashMap的工作原理是什么? 参考答案 Java中的HashMap是以键值对(key-value)的形式存储元素的.HashMap需要一个hash函数,它使用ha ...
- Java中需要知道的关键字
Java中有一些或常用,或不常用,但却不得不知关键字,本篇文章将讨论这些关键字的作用. transient transient关键字可能用的不是那么频繁,但却是一个很重要的关键字,它的作用是在对象序列 ...
- JAVA中堆栈和内存分配原理
1.栈.堆 1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量 ...
- 【每周一译】愚蠢的指标:Java中使用最多的关键字
此翻译纯属个人爱好,由于水平所限,翻译质量可能较低.网络上可能存在其它翻译版本,原文地址:http://blog.jooq.org/2013/08/26/silly-metrics-the-most- ...
- Java中的for each实现原理与坑
文章转载自「开发者圆桌」一个关于开发者入门.进阶.踩坑的微信公众号 在Java中,遍历集合和数组一般有以下三种形式: for (int i = 0; i < list.size(); i++) ...
- Java中的标识符和关键字
1.标识符 含义:标识符用于给程序中的类.变量.方法命名的符号. 组成:数字(0-9).字母(a-z)(A-Z).下划线(_).美元符号$. 命名规则:1.数字不能够作为命名符号的开头 2.不能够使用 ...
- java中this和super关键字的使用
这几天看到类在继承时会用到this和super,这里就做了一点总结,与各位共同交流,有错误请各位指正~ this this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针. this ...
随机推荐
- sed命令基础2
我在sed命令基础里面说了一下sed的基础用法,sed还有一些高级用法,由于我也是在学习中,写的博客可能会有想不到的地方,有问题希望大家指出. sed的高级用法主要在于两个空间的使用,模式空间和保持空 ...
- Selenium+Python自动化测试实战(2)元素定位
1.Selenium2 的原理 第一篇分享简单介绍了基于Python开发的Selenium2的环境配置,这篇主要讲一下基本用法.首先讲一下Selenium2的基本原理.基本上知道了这个东西是怎么回事, ...
- [python学习笔记] 运算符
数学运算符 与大多语言相同的运算符就不介绍了.不同的地方会用 (!不同)标出 与java相同的运算符 , - , * , % , / 不同之处 除法 (!不同) / 与java不同,整数相除,结果为 ...
- All about Div内显示滚动桥
Div内显示滚动桥看似是一个简单的前端问题,然而实际会发现还是有挺多需要注意的, 本文尝试对div内显示滚动桥的各种主要实现及一些难题进行研究. 横向滚动桥 横向滚动桥比较简单,无需设置宽度,直接ov ...
- Https系列之三:让服务器同时支持http、https,基于spring boot
Https系列会在下面几篇文章中分别作介绍: 一:https的简单介绍及SSL证书的生成二:https的SSL证书在服务器端的部署,基于tomcat,spring boot三:让服务器同时支持http ...
- SpringBoot文档翻译系列——29.SQL数据源
原创作品,可以转载,但是请标注出处地址: 因为需要使用到这方面内容,所有对这一部分进行了翻译. 29 使用SQL数据源 SpringBoot为SQL数据源提供了广泛支持,从直接使用JdbcTempl ...
- 使用LayUI展示数据
LayUI是一款免费,开源,轻量级的前端cms框架,适用于企业后端,能快速上手开发,集成了常用的组件,还有完善的文档和社区. 点击查看 文档地址 下载框架 使用: 1.把这个5个文件项都拷贝到项目中 ...
- GitHub Desktop客户端打开文件乱码问题解决方案
今天在使用GitHub Desktop客户端的时候,发添加本地仓库后文件内容显示为乱码. 1.现象 如下图所示: 2.原因分析 后来分析得知原来是由于编码不统一造成 的. 具体来说,我在window ...
- 我的第一个python web开发框架(4)——数据库结构设计与创建
小白做好前端html设计后,马上开始进入数据库结构设计步骤. 在开始之前,小白回忆了一下老大在公司里培训时讲过的数据库设计解说: 对于初学者来说,很多拿到原型时不知道怎么设计数据表结构,这是很正常的事 ...
- Python实战之Selenium自动化测试web登录(2)
#!/usr/bin/env python3 # -*- coding:utf-8 -*- from selenium import webdriver from selenium.webdriver ...