Java冷门基础知识isSynthetic方法的详细解析
(2018-06-25 17:11:36)今天在使用Java反射的过程中无意间看到了
Class、Field、Method中都定义了一个isSynthetic方法
在好奇心的驱使下开始了解这个东西
首先查看了JDK里面的文档
JDK文档里面对isSynthetic方法的描述是
如果是由Java编译器引入则返回True
如果不是由Java编译器引入则返回False
在看到Java
JDK上面的描述之后还是没有搞明白具体再说的什么
后来经过搜索
得到了一个大概的认识
如果一个类存在内部类的情况下,内部类想要访问外部类的私有方法或属性,外部类想要访问内部类的私有方法或者属性时,编译器会自动生成一些方法来达到上述访问目的
具体可以分以下几种情况
第一种(Method
isSynthetic):外部类或者内部类想要访问这两者之间另一个类的私有变量或者方法
如下图代码结果所示
public class MainClass {
@Getter @Setter private String param1 ="1";@Getter @Setter private String param2 ="2";
private void printMethod(){
System.out.println("this is printMethod");}
private class SubClass{
@Getter @Setter private String subParam1;@Getter @Setter private String subParam2;public void printMethodSub(){
System.out.println("this is printMethodSub");}}
@Test
public void isSynthetic(){
SubClass subClass = new SubClass();
System.out.println(subClass.subParam1);System.out.println(subClass.subParam2);
for (Method method:subClass.getClass().getDeclaredMethods()){
System.out.println("class name:"+subClass.getClass().getName()+"-"+ method.getName()+":"+method.isSynthetic());}
}
}
得到的结果为:
class name:com.synthetic.MainClass$SubClass-access$100:true
class name:com.synthetic.MainClass$SubClass-access$200:true
class name:com.synthetic.MainClass$SubClass-printMethodSub:false
class name:com.synthetic.MainClass$SubClass-setSubParam2:false
class name:com.synthetic.MainClass$SubClass-setSubParam1:false
class name:com.synthetic.MainClass$SubClass-getSubParam1:false
class name:com.synthetic.MainClass$SubClass-getSubParam2:false
这其中access$100、access$200isSynthetic得到的结果是true
这两个方法时怎么来的呢?
我得到的结论是:
这两个方法时实例化内部类之后直接访问内部类的私有变量
但是在实际的编译器会将外部类和内部类编译成两个Class文件
所以为了运行时JVM可以识别,编译器自动在内部类中生成了两个方法
access$100 和access$200 其实现的功能类似于属性的get set方法
来达到外部类可以使用.XXX的方式来访问内部类的私有属性和私有方法的目的
第二种(Field isSynthetic):外部类或者内部类想要访问这两者之间另一个类的私有变量或者方法
在我测试第一种isSynthetic的代码中我我遍历了一边subClass的field,发现不管是否使用suClass调用其私有属性或者方法MSubClass中都会生成一个 名叫this$0的field,并且这个Field的isSynthetic的返回值为True
一开始还以为这个原因是因为内部类为private的关系(内部类的private会影响是否会生成一个行的class的合成类)
但是经过调试发现并不是这么一回事
然后通过打印this$0的Type为MainClass
随即打开了MainClass$SubClass的反编译文件发现文件中多了一个私有的构造方法
private MainClass$SubClass(MainClass var1) {
this.this$0 = var1;
}
且正好这个方法中有一个参数是this$0
所以这里我就有一个猜想
当实例化子类时会实例化一个父类的对象
并且将对象赋值给this$0
在内部类的方法中直接调用外部类的属性时则会调用这个实例化的父类对象
使用如下代码达到验证目的
public void printMethodSub(){
System.out.println("this is printMethodSub");System.out.println(param1+param2);
}
for (Field field:subClass.getClass().getDeclaredFields()){
System.out.println(("class name:"+subClass.getClass().getName()+"-" +field.getName()+":"+field.isSynthetic()+"-type:"+field.getType()));try {
field.setAccessible(true);
if (field.getType().toString().equals("class com.synthetic.MainClass")){MainClass mainClass = (MainClass)field.get(subClass);
mainClass.setParam1("10");
mainClass.setParam2("15");
subClass.printMethodSub();
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
调用subClass.printMethodSub()这个方法时得到的结果为:
this is printMethodSub
1015
所以假设成立
后一篇:lombok的用法说明