读完这篇文章你将会收获到

  • synthetic fields
  • synthetic method
  • synthetic class

概述

上一篇 Java 枚举 提及到编译成 class 文件之后、编译器会在枚举类里帮我们生成一个 VALUES 的静态数组 , 这种编译器生成的都有一个 flag 叫做 synthetic

那么 synthetic 的定义是什么、什么情况下才会有这个 flag ?

由编译器生成的,在源代码中没有出现的,都会被标记为 synthetic。当然有一些例外的情况:默认的构造函数、类的初始化方法、以及枚举类中的 valuevalueOf 方法

synthetic fields

非常常见的一个例子

public class Father {
class Son {
}
}

我们都知道在一个内部类中,可以直接访问外部类的属性和方法,因为在内部类中是存在一个外部类的一个引用变量,而这个引用变量即是编译器帮我们生成的、也就是一个 synthetic 的属性

我们再写一个测试来验证下

Class<Father.Son> clazz = Father.Son.class;
Field[] declaredFields = clazz.getDeclaredFields(); for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName() + ":" + declaredField.isSynthetic());
}
this$0:true

我们再来验证一下上一篇文章 Java 枚举 的枚举类

Class<BehaviorEnum> clazz = BehaviorEnum.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName() + ":" + declaredField.isSynthetic());
}
FOLLOW:false
WOW:false
FORWARD_TO_FRIENDS:false
ADD_TO_FAVORITES:false
$VALUES:true

synthetic method

我们再来看看被 synthetic 修饰的方法吧

public class Father {
class Son {
private String name;
} /**
* just for test synthetic
* @return
*/
public String getName() {
// just for test synthetic
return new Son().name;
}
}

Son 类中突然多出了这么一个方法。因为其实 name 属性是一个私有方法、外部类 Father 中却能直接访问这个属性、对于我们写代码来说、这是非常合理的一个事情、但是这都是编译器默默的付出、为我们生成了一个静态的 package 范围的方法、参数就是 Son 的实例、返回值就是 String

Class<Father.Son> sonClass = Father.Son.class;
Method[] declaredMethods = sonClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(
Modifier.toString(declaredMethod.getModifiers()) +
":" + declaredMethod.getName() +
":" + declaredMethod.isSynthetic()); }
static:access$000:true

synthetic class

我们再来看看被 synthetic 修饰的 class

public class Father03 {
public Son generateSon() {
return new Son();
}
private class Son{
}
}

然后我们编译为 class 文件

发现多出来一个匿名类 Father03$1.class 这个是什么鬼鬼

这个类完全是一个空的类、父类直接是 Object、也没额外定义一些自己的方法

我们再看看 Father03$Son.class

发现它居然有两个构造方法,一个带参数的 package scope 的构造参数是编译器生成的。参数是 Father03Father03$1

我们再看看 Father03 里面的 generateSon 方法

发现它调用的是那个带参数的构造方法,并且参数 Father03$1 的值是为 null

根据上面的种种信息来看、我们可以这么认为、对于一个 private 的内部类(其构造函数默认也是 private ) , 外部类也是无法直接去创建它的实例的、其实换句话来说、对于类的定义来说、不管你是作为一个内部类定义在另一个类中、还是单独定义在一个 java 文件,java 的可见性都是起效的。至于为啥可以在外部内直接创建一个 private 的类的实例、无外乎就是 java 编译器帮我们做了一些额外的工作。

回到上面的例子中、因为 Father03$Son. 只有一个私有的构造函数、而为了能在 Father03 中去创建这么一个 Father03$Son 对象,编译器不得不为我们生成一个 package scope 的构造函数、而午餐的构造函数已经存在了、那编译器只能创建一个有参的构造函数啊、那么问题来了、这个参数的类型应该是啥、那就生成一个类呗、专门为这个参数用。而调用这个构造函数的时候、就直接传给 null 值给它

所以说 Father03$1 作用无外乎可能就是作为一个参数的类型被用到

相关文章

Java synthetic的更多相关文章

  1. Javac语法糖之TryCatchFinally

    https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20.3 Optionally replace a try s ...

  2. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  3. Java 中冷门的 synthetic 关键字原理解读

    看JAVA的反射时,看到有个synthetic ,还有一个方法isSynthetic() 很好奇,就了解了一下: 1.定义 Any constructs introduced by a Java co ...

  4. Java中的synthetic

    有synthetic标记的field和method是class内部使用的,正常的源代码里不会出现synthetic field.小颖编译工具用的就是jad.所有反编译工具都不能保证完全正确地反编译cl ...

  5. 《深入理解Java虚拟机》类文件结构

    上节学习回顾 在上一节当中,主要以自己的工作环境简单地介绍了一下自身的一些调优或者说是故障处理经验.所谓百变不离其宗,这个宗就是我们解决问题的思路了. 本节学习重点 在前面几章,我们宏观地了解了虚拟机 ...

  6. Java内部类final语义实现

    本文描述在java内部类中,经常会引用外部类的变量信息.但是这些变量信息是如何传递给内部类的,在表面上并没有相应的线索.本文从字节码层描述在内部类中是如何实现这些语义的. 本地临时变量 基本类型 fi ...

  7. (9) 深入了解Java Class文件格式(八)

    转载:http://blog.csdn.net/zhangjg_blog/article/details/22205831 在本专栏的第一篇文章 深入理解Java虚拟机到底是什么 中, 我们主要讲解了 ...

  8. 使用Proguard做Java代码混淆

    下载Proguard, 我下的是最新的Proguad5.2 在windows下运行bin/proguardgui.bat, 可以看见图形界面, 载入配置, 然后process. 配置文件例子 -inj ...

  9. 使用proguard混淆java web项目代码

    1.首先下载proGuard.zip到本地: proguard4.5beta4.tar.zip解压开,2.新建文本文档,修改文件名为XXX.pro,然后复制下面内容到.pro -injars 'Y:\ ...

随机推荐

  1. Java实现 蓝桥杯 基础练习 特殊的数字

    基础练习 特殊的数字 时间限制:1.0s 内存限制:512.0MB 提交此题 锦囊1 锦囊2 问题描述 153是一个非常特殊的数,它等于它的每位数字的立方和,即153=111+555+333.编程求所 ...

  2. Java实现 蓝桥杯 算法提高 复数四则运算

    算法提高 6-17复数四则运算 时间限制:1.0s 内存限制:512.0MB 提交此题 设计复数库,实现基本的复数加减乘除运算. 输入时只需分别键入实部和虚部,以空格分割,两个复数之间用运算符分隔:输 ...

  3. 第六届蓝桥杯JavaC组国(决)赛真题

    解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.机器人数目 少年宫新近邮购了小机器人配件,共有3类,其中, A类含有:8个轮子,1个传感器 B类含有: 6个轮子,3个传感器 C类含有 ...

  4. java实现 蓝桥杯 算法提高 Problem S4: Interesting Numbers 加强版

    1 问题描述 Problem Description We call a number interesting, if and only if: 1. Its digits consists of o ...

  5. MySQL基本DML

    DML: 数据操纵语言, 主要用来向数据库中添加. 删除. 修改数据用的.在开发中经常会用到,所以,在此也小小总结一下: CREATE DATABASE db2 DEFAULT CHARSET UTF ...

  6. ReentrantReadWriteLock(读写锁)全部源码注释

    package java.util.concurrent.locks; import java.util.concurrent.TimeUnit; import java.util.Collectio ...

  7. JavaScript使用for循环和splice删除数组指定元素的注意点

    在JavaScript里可以结合for循环和splice来删除数组指定的元素.但是要注意删除元素后,数组索引会发生改变 示例 var arr = ["a","b" ...

  8. linux系统判断内存是否达到瓶颈的小技巧

    1.linux下最常用的系统状态监控工具top 工具,可以使用top -c 来进行查看当前内存的占用情况 free 为内存的剩余状态,当前为3.8G的空闲内存,总的物理内存是8G,按键 shift+m ...

  9. Python面试进阶问题,__init__和__new__的区别是什么?

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天这篇是Python专题的第17篇文章,我们来聊聊Python当中一个新的默认函数__new__. 上一篇当中我们讲了如何使用type函数 ...

  10. mysql 错误:Table is marked as crashed and should be repaired 解决办法

    遇到这个问题几个敲命令轻松搞定 1.首先进入mysql命令台: mysql -u root -p 回车 输入密码 2.查询所有的库 mysql> show databases; 3.进入数据库“ ...