朝花夕拾——Java的synthetic修饰词

转载自  朝花夕拾——Java的synthetic修饰词

Ok,目前为止,我还只是Android coder,一切对其他的学习都是以Android 为主线的支线任务。所以为什么会提到这个方法呢?是来自于google官方的性能建议文档的这样一句话:

Consider Package Instead of Private Access with Private Inner Classes 
考虑包内访问来取代访问私有内部类的私有修饰的方法或变量

为什么呢?下文的回答是:因为使用私有的内部类会产生静态的合成方法,影响性能


1. synthetic方法

如果有看过我的EventBus源码讲解的同学,会发现以下的一个常量 。

private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;/***  省略内容**/ //判断是否为PUBLIC,MODIFIERS_IGNORE 包含(抽象,静态,桥接,合成,后2者是编译器添加的)
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) 

可以看到我在其上的注释 MODIFIERS_IGNORE 包含(抽象,静态,桥接,合成,后2者是编译器添加的)

我的注释写的没有错,后面两种方法是编译器添加的。在此我给大家来一个小demo,让看看合成方法是在怎么生成的:

public class OutClass {private static class InnerClass {public InnerClass(){}private int x;private  void y() {};}public static void main(String[] args) {InnerClass inner = new InnerClass();    inner.x = 2;System.out.println(inner.x);inner.y();for (Method m : InnerClass.class.getDeclaredMethods()) {System.out.println(String.format("%08X", m.getModifiers()) + " "+ m.getName());}}

简单的一个静态内部类,实列化之后通过反射遍历其所有方法。输出方法名的同时,也将所有方法修饰词的十六进制码的格式输出。 
运行结果如下:

这里写图片描述

先不看前面的十六进制码,我们看看后面输出的方法名,看上面的代码,我们知道,我们只写了一个名为 y 的方法。那么前面的两个access$1,2,3 是哪里来鬼怪?

为了解开谜底,我们再继续看看 java.lang.reflect.Modifier 里的几个修饰词的十六进制码:

00001008 SYNTHETIC|STATIC
00000002 PRIVATE
00000111 NATIVE|FINAL|PUBLIC
00000011 FINAL|PUBLIC
00000001 PUBLIC
00001000 SYNTHETIC
00000008 STATIC

我们看到了 00001008 SYNTHETIC|STATIC 合成的静态方法修饰词

所以access$1什么的都是我们编译器合成的方法,且是静态的。


然后问题来了

为什么呢!(ಠ౪ಠ) 
为什么生成这些方法?平时我反射其他没有内部类的class的时候没有出现过的啊….

真相

JVM是如何处理这个的class的?它可不知道什么是内部类或者嵌套类的。JVM对所有的类都一视同仁,它都认为是顶级类。被Javac编译后所有类都会被编译成顶级类,而那些内部类编译完后会生成…$… class的类文件。注意,是所有的内部类,我写静态内部类是因为这样的demo简单,所以如果你创建一个内部类的话,它会被彻底编译成一个顶级类。(原来JVM也是也挺笨的…..)。

既然同时身为顶级类,你OutClass 为什么可以直接调用我的InnerClass的私有方法和私有属性!你算老几?

为了解决这种矛盾,我们的圣母玛丽亚式的Javac编译的时候想到了一个解决冲突办法,在从中做了点手脚,在InnerClass里,为所有私有方法,和私有变量又写了一个合成的静态方法。为了还原真相我写了这样的代码:

private static class InnerClass {public InnerClass(){}private int x;synthetic static void access$1(int x) { this.x=x; }synthetic static int access$2(int x) { return x }private void y() {};synthetic static int access$3() { y() }}

所有说,等于是为了获取我们的x写了getter/setter方法。为了调用 y()写了一个嵌套的调用方法…. 
真是用心良苦啊…..

看完了上文,我们知道了,原来内部类在编译的时候为了给外部类调用,提供了几个静态方法给外部类使用。


补充点:(很重要啊)

1. 如果将y方法的修饰词改为public,就不会出现access$3()合成方法,对x也是同理。;

2.当你对x只赋值,不调用时,或者只调用,不赋值。只会产生相应的getter或setter方法

3.将构造函数变为private 也会生成一个非静态的合成方法,如下:

synthetic  void  OutClass$InnerClass(OuClass this$0) {  }

等下…this$0 这个又是什么鬼? 
别急…我先下文介绍


2. synthetic对象

作为一个Android Coder ,有一点我们都知道:

内部类会持有外部类的指针,有可能发生内存泄漏。所以,我们常常建议在合适的时候,将内部类改为静态内部类,这样就可以不持有外部的指针。

可是,Do you know the reasons ?

我们还是上文的Class,不过将其简单的改造下,不过是将其输出隔离出来

public class OutClass {class InnerClass {public int x;public InnerClass() {}public  void y() {};}
}
public class Demo {/*** @param args*/public static void main(String[] args) {//遍历所有字段for (Field  c  : OutClass.InnerClass.class.getDeclaredFields()) {System.out.println(String.format("%08X",  c.getModifiers()) + " "+ c.getName());}System.out.println("-----------------------------------------");//遍历构造函数 for( Constructor<?> c : OutClass.InnerClass.class.getDeclaredConstructors() ){System.out.println(String.format("%08X", c.getModifiers()) + " " + c.getName()+" ");//遍历构造函数入参for(Class temp:c.getParameterTypes()){System.out.println(temp.getSimpleName());}}}
}

运行~,以下为结果~

这里写图片描述

我们可以看到,我们内部的字段有两个,一个是x, 一个是 this$0 。而我们的构造函数只有一个没错,可是却偷偷的传入了一个OutClass对象。 
(/= _ =)/~┴┴ 
在javac 的编译之下…被改的东西还真多啊….为了让大家更直观。我再模拟下编译后的class 文件内的情况。

public class OutClass {class InnerClass {public int x;synthetic OutClass this$0;public InnerClass(OutClass args) {this.this$0 =args;}public  void y() {};}
}

这样就明白了吧~,我们的内部类之所以可以被外部类调用。原来是传了一个外部类的一个对象!有了this$0,我们可以随意的调用外部类的方法。

看完了上文,我们知道了,原来内部类在编译的时候为了调用外部类的方法,在其构造函数里传入了一个外部类的对象。

再接下上文,Android中为什么要将内部类改为静态内部类。是因为静态内部类是共享给当前类的所有对象的,所以不需要传入当前类的引用


补充点:(很重要啊)

1.如果内部类没有构造函数,就能避免传参么?NO! 
这里写图片描述 
即使是默认的构造函数,也会传外部类引用。 000000不在修饰词内,可以当作没有修饰词的构造方法。


总结

归根结底,作为一个Android的coder。那么多的static方法不适合移动的不算充裕的内存。因此Google不提倡使用私有内部类,最好将其拆开独立成一个Class。还有内部类尽量改为静态内部类,可以避免内存泄漏。有空看看google 的性能建议文档还是挺不错的!XD~~


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329198.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

asp.net MVC 应用程序的生命周期

首先我们知道http是一种无状态的请求&#xff0c;他的生命周期就是发出请求开始&#xff0c;到得到响应结束。那么MVC应用程序从发出请求到获得响应&#xff0c;都做了些什么呢&#xff1f; 本文我们会详细讨论MVC应用程序的生命周期和一个请求&#xff0c;从一个控件到另一个控…

java 刷新界面_利用java如何实现在删除信息后刷新页面功能

利用java如何实现在删除信息后刷新页面功能发布时间&#xff1a;2020-11-17 14:25:49来源&#xff1a;亿速云阅读&#xff1a;74作者&#xff1a;Leah这篇文章给大家介绍利用java如何实现在删除信息后刷新页面功能&#xff0c;内容非常详细&#xff0c;感兴趣的小伙伴们可以参考…

Java中的synthetic

转载自 Java中的synthetic 有synthetic标记的field和method是class内部使用的&#xff0c;正常的源代码里不会出现synthetic field。小颖编译工具用的就是jad.所有反编译工具都不能保证完全正确地反编译class。所以你不能要求太多。 下面我给大家介绍一下synthetic 下面的例子…

java凯撒密码_JAVA凯撒密码 选择问题

以下是加密和解密的程序&#xff1a;加密&#xff1a;importjava.io.*;classJiami26{publicstaticvoidmain(Stringargs[])throwsIOException{charb[];//存放密文BufferedReaderbr2newBufferedReader(newIn...以下是加密和解密的程序&#xff1a;加密&#xff1a;import java.io…

synthetic Java合成类型

转载自 synthetic Java合成类型Synthetic看Class源码的时候&#xff0c;看到有个关键字Synthetic以及isSynthetic()方法&#xff0c;遂有兴趣查阅了一番。   一开始以为&#xff0c;就是复合类型&#xff08;引用类型&#xff09;&#xff0c;也就是非基本类型&#xff0c;…

Java 反射机制深入研究

转载自 Java 反射机制深入研究Java反射机制深入研究Java 反射是Java语言的一个很重要的特征&#xff0c;它使得Java具体了“动态性”。在Java运行时环境中&#xff0c;对于任意一个类&#xff0c;能否知道这个类有哪些属性和方法&#xff1f;对于任意一个对象&#xff0c;能否…

RAML用户应遵循的C#与Web API代码生成模式

在过去几年间&#xff0c;REST规范的各种语言正在逐渐流行起来&#xff0c;例如RAML、Swagger以及API Blueprint。但这些语言的主要范畴在于客户端工具&#xff0c;主要用于生成JavaScript或TypeScript文件、模拟对象&#xff08;mock&#xff09;&#xff0c;以及对应的客户端…

wxpython使用folium_wxPython实现文本框基础组件

本文实例为大家分享了wxPython实现文本框的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下#-*- coding:utf-8 -*-"""#############################################StaticText 参数说明 --即 labelparent&#xff1a; -- 父窗口部件。id&#xff1a;…

教你实践ASP.NET Core Authorization(免看文档教程)

准备 创建一个名为AuthorizationForoNetCore的&#xff08;web&#xff09;解决方案,选择Empty模板添加相关nuget包引用Microsoft.AspNetCore.Mvc&#xff08;选择最新版本&#xff09;编辑Startup.cs文件&#xff0c;添加mvcservice并进行默认路由配置 添加Controllers文件夹&…

Class类中的getEnclosingXX、getDeclaredXX

转载自 Class类中的getEnclosingXX、getDeclaredXX一、getEnclosingXX getEnclosingClass():该类是在那个类中定义的&#xff0c; 比如直接定义的内部类或匿名内部类 getEnclosingConstructor()&#xff1a;该类是在哪个构造函数中定义的&#xff0c;比如构造方法中定义的匿名…

二级MYSQL的语法整理_MySQL语法整理

一、基本语句(大写的代表固定语句&#xff0c;小写的代表自己命名部分)1. 数据库部分增&#xff1a;CREATE DATABASE database_name;删&#xff1a;DROP DATEBASE database_name;用&#xff1a;USE database_name;2. 数据表部分增&#xff1a;CREATE TABLE table_name ( field1…

java反射的field.get(null)

转载自 java反射的field.get(null) 在java的反射中,通过字段获取对象,是通过 public Object get(Object obj) 字段不是静态字段的话,要传入反射类的对象.如果传null是会报 java.lang.NullPointerException 但是如果字段是静态字段的话,传入任何对象都是可以的,包括null 下面是…

JFlow CCFlow工作流引擎北京培训邀请函

各位jFlow, CCFlow 爱好者: 驰骋工作流程引擎是国内开源很成功的一款工作流程引擎&#xff0c;广泛应用于大型集团企业、机关事业单位、部队军区、保密军工行业。设计精巧、功能强大、极高的可配置性、概念名词通俗易懂、成长于中国生产制造、管理审批特有的环境下&#xff0c;…

java按列读取数据再存储_Java指定行读写数据

/*** 根据指定行写数据** param lineNumber 要存的行数* param data 要存储的数据*/public static void setAppointedLineNumber(int lineNumber, String data) throws IOException {Path path Paths.get(configuration);List lines Files.readAllLines(path, StandardCharse…

Java通过Class的对象来获取泛型的class示例

转载自 Java通过Class的对象来获取泛型的class示例 在使用spring的JdbcTemplate实现DAO的时候&#xff0c;经常会用到一个类ParameterizedBeanPropertyRowMapper。它的静态方法newInstance()接受一个Class类型的参数&#xff0c;用于将ResultSet中的属性映射到传入的这个Class…

微软觊觎LinkedIn算法

分析师说&#xff0c;LinkedIn算法的价值远超260亿美元买到的数据。 微软在昨天宣布了即将以262亿美元的价格收购企业社交网络LinkedIn。一名分析师称&#xff0c;这起并购由微软对算法的渴望而起。 “微软对LinkedIn的兴趣有两部分”&#xff0c;Gartner研究总监Jenny Sussin在…

阿卡姆疯人院需要java吗_蝙蝠侠阿甘疯人院 这个报错 怎么解决 哪位大神知道...

有关调用实时(JIT)调试而不是此对话框的详细信息&#xff0c;请参见此消息的结尾。************** 异常文本 **************System.Runtime.InteropServices.SEHException: 外部组件发生异常。在 BmLauncherLib.PhysXSDK.{ctor}(PhysXSDK* )在 BmLauncherUtils.PhysXSDK..ctor(…

Java5泛型的用法,T.class的获取和为擦拭法站台

转载自 Java5泛型的用法&#xff0c;T.class的获取和为擦拭法站台Java 5的泛型语法已经有太多书讲了&#xff0c;这里不再打字贴书。GP一定有用&#xff0c;不然Java和C#不会约好了似的同时开始支持GP。但大家也清楚&#xff0c;GP和Ruby式的动态OO语言属于不同的意识形态&…

asp.net core 使用 Redis 和 Protobuf 进行 Session 缓存

目录 Redis 介绍asp.net core Session 介绍Redis & Session 实例讲解Session的使用使用 Protobuf 给 Session添加扩展方法 Redis 介绍 下面是Redis官网的介绍&#xff1a; Redis is an open source (BSD licensed), in-memory data structure store, used as database, cac…

java后台 flex前台例子_flex+blazeds+java后台消息推送(简单示例)

现在有个问题需要大家思考一下&#xff0c;有个已经上线了的项目&#xff0c;有好好几千甚至上万的客户在使用了。现在项目开发商想发布一个通知。在今天下午6点需要重新启动服务器&#xff0c;想让在线的人在在预定的时间内都收到消息&#xff0c;让大家做好相应的准备&#x…