From fb1b3a8a531181d2d69088db21a494bbbd140e32 Mon Sep 17 00:00:00 2001 From: Omooo <869759698@qq.com> Date: Fri, 28 Dec 2018 17:48:09 +0800 Subject: [PATCH] update final --- README.md | 5 ++ blogs/AOP_AspectJ.md | 5 ++ blogs/Question.md | 90 ------------------------------------ blogs/String.md | 11 +++++ blogs/final.md | 106 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 90 deletions(-) delete mode 100644 blogs/Question.md create mode 100644 blogs/String.md create mode 100644 blogs/final.md diff --git a/README.md b/README.md index ef4f792..3ab3e6c 100644 --- a/README.md +++ b/README.md @@ -13,5 +13,10 @@ Android Notes - [SharedPreferences](https://github.com/Omooo/Android-Notes/blob/master/blogs/SharedPreferences.md) - [SQLite](https://github.com/Omooo/Android-Notes/blob/master/blogs/SQLite.md) +2. [埋点](https://github.com/Omooo/Android-Notes/blob/master/blogs/%E5%9F%8B%E7%82%B9.md) +#### Java +[final 你需要知道的一切](https://github.com/Omooo/Android-Notes/blob/master/blogs/final.md) + +[String 你需要知道的一切](https://github.com/Omooo/Android-Notes/blob/master/blogs/String.md) \ No newline at end of file diff --git a/blogs/AOP_AspectJ.md b/blogs/AOP_AspectJ.md index 08a0910..89e4f9f 100644 --- a/blogs/AOP_AspectJ.md +++ b/blogs/AOP_AspectJ.md @@ -18,6 +18,7 @@ AOP 之 AspectJ - 全局点击事件拦截 - 方法统计耗时 - 权限申请 + - 缺点 4. 参考 #### 思维导图 @@ -202,7 +203,11 @@ ProceedingJoinPoint 用于环绕通知,它是 JointPoint 的子类,与其不 以上两个示例都是按照相似性统一切,而通过自定义注解修饰切人点,能够达到精确切。 +##### 缺点 +1. 无法织入第三方的库 +2. 无法兼容 Lambda 语法 +3. 会有一些兼容性问题,比如 D8、Gradle 4.x 等 #### 参考 diff --git a/blogs/Question.md b/blogs/Question.md deleted file mode 100644 index 96c6334..0000000 --- a/blogs/Question.md +++ /dev/null @@ -1,90 +0,0 @@ -```java - - - /** - * 我想统计两个类中方法执行耗时,BootActivity 中的统计没什么问题, - * 但是 CommonRequest 类中的统计直接导致应用崩溃 - * 类转换异常?很萌 - * AspectJ 才学,希望大佬能帮帮我,不胜感激 - */ - -com.xxx.BootActivity -public class BootActivity extends Activity{ - onCreate(){ - CommonRequest.method1(this); - CommonRequest.method2(this); - //... - } -} - -com.yyy.CommonRequest -public class CommonRequest{ - public static void mothod1(Context context){ - //网络请求 - new HttpRequest(context).callback(new CallBack()){ - // - } - } -} - -//切面类 -@Aspect -public class MethodTimeTracker { - - //这个切点执行正常 - @Around("execution( * com.xxx.BootActivity.* (..))") - public void bootTracker(ProceedingJoinPoint joinPoint) throws Throwable { - long beginTime = SystemClock.currentThreadTimeMillis(); - joinPoint.proceed(); - long endTime = SystemClock.currentThreadTimeMillis(); - long dx = endTime - beginTime; - Log.i("2333", joinPoint.getSignature().getDeclaringType().getName() + "#" + joinPoint.getSignature().getName() - + " " + dx + " ms"); - } - - //这个切点直接导致应用崩溃 - @Around("execution( * com.yyy.CommonRequest.* (..))") - public void requestTracker(ProceedingJoinPoint joinPoint) throws Throwable { - long beginTime = SystemClock.currentThreadTimeMillis(); - joinPoint.proceed(); - long endTime = SystemClock.currentThreadTimeMillis(); - long dx = endTime - beginTime; - Log.i("2333", joinPoint.getSignature().getDeclaringType().getName() + "#" + joinPoint.getSignature().getName() - + " " + dx + " ms"); - } -} - -Log 日志: - java.lang.RuntimeException: Unable to start activity ComponentInfo{.BootActivity}: java.lang.ClassCastException: BootActivity cannot be cast to cn.shuhe.dmnetwork.network.CjjHttpRequest - at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913) - at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048) - at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) - at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) - at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) - at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808) - at android.os.Handler.dispatchMessage(Handler.java:106) - at android.os.Looper.loop(Looper.java:193) - at android.app.ActivityThread.main(ActivityThread.java:6669) - at java.lang.reflect.Method.invoke(Native Method) - at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) - at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) - Caused by: java.lang.ClassCastException: BootActivity cannot be cast to CjjHttpRequest - at cn.shuhe.projectfoundation.CommonRequest$AjcClosure15.run(CommonRequest.java:1) - at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:149) - at com.dataseed.cjjanalytics.aspect.MethodTimeTracker.requestTracker(MethodTimeTracker.java:29) - at cn.shuhe.projectfoundation.CommonRequest.checkDeviceInfo(CommonRequest.java:223) - at com.dataseed.huanbei.ui.BootActivity.startUp(BootActivity.java:296) - at com.dataseed.huanbei.ui.BootActivity.onCreate_aroundBody2(BootActivity.java:129) - at com.dataseed.huanbei.ui.BootActivity$AjcClosure3.run(BootActivity.java:1) - at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:149) - at com.dataseed.cjjanalytics.aspect.CjjTraceAspect.weaveActivityOnCreateJoinPoint(CjjTraceAspect.java:225) - at com.dataseed.huanbei.ui.BootActivity.onCreate(BootActivity.java:126) - at android.app.Activity.performCreate(Activity.java:7136) - at android.app.Activity.performCreate(Activity.java:7127) - - -类转换异常是怎么肥事? - - -``` - diff --git a/blogs/String.md b/blogs/String.md new file mode 100644 index 0000000..1871763 --- /dev/null +++ b/blogs/String.md @@ -0,0 +1,11 @@ +--- +String +--- + +#### 目录 + +1. 思维导图 +2. String + - +3. 参考 + diff --git a/blogs/final.md b/blogs/final.md new file mode 100644 index 0000000..4edeead --- /dev/null +++ b/blogs/final.md @@ -0,0 +1,106 @@ +--- +final +--- + +#### 目录 + +1. final + - 引言 + - 内存语义 + - 优势所在 + - 天生线程安全 + - 编译器优化 + - 参考 + +#### 引言 + +说起 final 关键字,脱口而出就是修饰变量变量不可变、修饰方法方法不可重写、修饰类类不可继承。 + +或许你还听过 final 能够提高效率,那如何提高效率的呢?方法内联?方法内联又是个什么东西呢? + +带着疑问来探索一下 final。 + +#### 内存语义 + +##### 写 final 域的重排序规则 + +写 final 域的重排序规则禁止把 final 域的写重排序到构造函数之外,这个规则的实现包含两个方面: + +1. JVM 禁止编译器把 final 域的写重排序到构造函数之外 +2. 编译器会在 final 域的写之后,构造函数 return 之前,插入一个 StoreStore 内存屏障,这个屏障禁止处理器把 final 域的写重排序到构造函数之外 + +写 final 域的重排序规则可以确保:在对象引用为任何线程可见之前,对象的 final 域已经被正确初始化过了,而普通域不具有这个保证。 + +##### 读 final 域的重排序规则 + +在一个线程中,初次读对象引用与初次读改对象包含的 final 域,JMM 禁止处理器重排序这两个操作。编译器会在读 final 域操作的前面插入一个 LoadLoad 内存屏障。 + +读 final 域的重排序可以确保:在读一个对象的 final 域之前,一定会先读包含这个 final 域的对象引用。 + +#### 优势 + +##### 线程安全 + +这个不用多说,不可变对象天生线程安全。 + +##### 编译器优化 + +经常能听到别人说 final 能提高效率,在于编译器在对 final 修饰的方法做了方法内联。这句话对与否先不讨论,先来了解一下方法内联是什么鬼? + +在了解方法内联之前,先来了解一下函数调用过程: + +1. 首先会有个执行栈,存储它们的局部变量、方法名、动态链接地址 +2. 当一个方法调用,一个新的栈桢会被加到栈顶,分配的本地变量和参数会存储在这个栈桢 +3. 调转到目标方法代码执行 +4. 方法返回的时候,本地方法和参数被销毁,栈顶被移除 +5. 返回原来的地址执行 + +其实这就是虚拟机栈执行方法的内存模型。函数调用需要一定的时间开销和空间开销,当一个方法被频繁调用时,这个时间和空间开销会相对变的很大。根据二八原则,80% 的性能消耗其实是发生在 20% 的代码上,对热点代码的针对优化可以提升整体系统的性能。 + +然后我们在看看方法内联到底是什么?其实可以用以下例子粗鄙的解释: + +```java +private int add2(int x1 , int x2 , int x3 , int x4) { +return add1(x1 , x2) + add1(x3,x4); +} + +private int add1(int x1 , int x2) { +return x1 + x2; +} +``` + +在运行一段时间后,代码可能就变成下面这样了: + +```java +private int add2(int x1 , int x2 , int x3 , int x4) { +//return add1(x1 , x2) + add1(x3,x4); +return x1 + x2 + x3 + x4; +} +``` + +嘿,看来方法内联就是把调用的方法函数代码复制到了调用函数内,减少因函数调用而带来的开销。 + +但是方法内联也是有条件的: + +1. 热点代码 +2. 方法体不能太大 + +方法内联会导致拷贝代码副本过多,代码占用内存增加,所以方法体不能太大。 + +其次由于方法可能被继承,导致需要类型检查而没有达到性能的效果,所以想要对热点代码进行方法内联,最好尽量使用 final、private、static 这些修饰方法,避免因为继承而导致额外的类型检查。 + +说到这,其实就能理解 final 能够提高效率的原因在于哪了,**但是如果想通过 final 来提升性能,那几乎是不太可能。** + +现在,让我来回答一下 final 能够提高性能这个说法? + +emmmm,这样的说法太片面。final 的确能够提升性能,但毕竟微乎其微。final 修饰的变量值多数情况下就能在编译阶段确定下来,这就可能导致某些代码被编译器优化掉。其次,关于方法内联的说法,也的确存在。但是方法内联也是需要条件的,首先是被频繁调用的热点代码,方法内联能够减少方法调用所带来的性能消耗;其次是方法体不能过大,原因很简单,方法内联将会导致拷贝代码更多,代码占用更多的内存空间。最后才是方法最好能被 final、private、static 修饰,这样就能避免过多的参数检查、类型检查等等。我们更应该关注 final 所带来的特性,比如属性不可变、方法不可重写、类不可继承,想要通过 final 来提升性能,几乎是不可能的事。 + +#### 参考 + +[深入理解Java中的final关键字](http://www.importnew.com/7553.html) + +[Final of Java,这一篇差不多了](https://www.jianshu.com/p/f68d6ef2dcf0) + +[final修饰递归方法会提高效率吗?](https://www.zhihu.com/question/66083114) + +[Java 方法内联](https://www.cnblogs.com/xyz-star/p/10152564.html) \ No newline at end of file