加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

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$200 isSynthetic得到的结果是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
所以假设成立

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有