diff --git a/Part1/Android/AIDL.md b/Part1/Android/AIDL.md index aa90825..8c74568 100644 --- a/Part1/Android/AIDL.md +++ b/Part1/Android/AIDL.md @@ -1,4 +1,4 @@ -#AIDL +# AIDL --- 1. 创建一个接口,再里面定义方法 @@ -335,7 +335,7 @@ public class MainActivity extends Activity { 将服务端的aidl文件完整的复制过来,包名一定要一致。 -##分析AIDL生成的代码 +## 分析AIDL生成的代码 1. 服务端 @@ -441,7 +441,7 @@ reply.writeInt(_result); add同理,可以看到服务端通过AIDL生成Stub的类,封装了服务端本来需要写的代码。 -###客户端 +### 客户端 客户端主要通过ServiceConnected与服务端连接 diff --git "a/Part1/Android/ANR\351\227\256\351\242\230.md" "b/Part1/Android/ANR\351\227\256\351\242\230.md" index 1e22049..817906c 100644 --- "a/Part1/Android/ANR\351\227\256\351\242\230.md" +++ "b/Part1/Android/ANR\351\227\256\351\242\230.md" @@ -1,4 +1,4 @@ -#ANR +# ANR --- 1、ANR排错一般有三种类型 @@ -42,13 +42,13 @@ 最近出来一个叫LeakCanary -#FC(Force Close) -##什么时候会出现 +# FC(Force Close) +## 什么时候会出现 1. Error 2. OOM,内存溢出 3. StackOverFlowError 4. Runtime,比如说空指针异常 -##解决的办法 +## 解决的办法 1. 注意内存的使用和管理 2. 使用Thread.UncaughtExceptionHandler接口 diff --git "a/Part1/Android/APP\345\220\257\345\212\250\350\277\207\347\250\213.md" "b/Part1/Android/APP\345\220\257\345\212\250\350\277\207\347\250\213.md" index 4d295c4..86aa1fc 100644 --- "a/Part1/Android/APP\345\220\257\345\212\250\350\277\207\347\250\213.md" +++ "b/Part1/Android/APP\345\220\257\345\212\250\350\277\207\347\250\213.md" @@ -1,4 +1,4 @@ -#APP启动过程 +# APP启动过程 --- ![](http://7xntdm.com1.z0.glb.clouddn.com/activity_start_flow.png) diff --git "a/Part1/Android/Activity\345\220\257\345\212\250\350\277\207\347\250\213\345\205\250\350\247\243\346\236\220.md" "b/Part1/Android/Activity\345\220\257\345\212\250\350\277\207\347\250\213\345\205\250\350\247\243\346\236\220.md" index e48d7f4..60becb4 100644 --- "a/Part1/Android/Activity\345\220\257\345\212\250\350\277\207\347\250\213\345\205\250\350\247\243\346\236\220.md" +++ "b/Part1/Android/Activity\345\220\257\345\212\250\350\277\207\347\250\213\345\205\250\350\247\243\346\236\220.md" @@ -1,7 +1,8 @@ -#Activity启动过程 +# Activity启动过程 + --- -###一些基本的概念 +### 一些基本的概念 * ActivityManagerServices,简称AMS,服务端对象,负责系统中所有Activity的生命周期 * ActivityThread,App的真正入口。当开启App之后,会调用main()开始运行,开启消息循环队列,这就是传说中的UI线程或者叫主线程。与ActivityManagerServices配合,一起完成Activity的管理工作 @@ -12,7 +13,7 @@ * ActivityRecord,ActivityStack的管理对象,每个Activity在AMS对应一个* ActivityRecord,来记录Activity的状态以及其他的管理信息。其实就是服务器端的Activity对象的映像。 * TaskRecord,AMS抽象出来的一个“任务”的概念,是记录ActivityRecord的栈,一个“Task”包含若干个ActivityRecord。AMS用TaskRecord确保Activity启动和退出的顺序。如果你清楚Activity的4种launchMode,那么对这个概念应该不陌生。 -###回答一些问题 +### 回答一些问题 **zygote是什么?有什么作用?** diff --git "a/Part1/Android/Android\345\205\263\344\272\216oom\347\232\204\350\247\243\345\206\263\346\226\271\346\241\210.md" "b/Part1/Android/Android\345\205\263\344\272\216oom\347\232\204\350\247\243\345\206\263\346\226\271\346\241\210.md" index faab430..200bbb6 100755 --- "a/Part1/Android/Android\345\205\263\344\272\216oom\347\232\204\350\247\243\345\206\263\346\226\271\346\241\210.md" +++ "b/Part1/Android/Android\345\205\263\344\272\216oom\347\232\204\350\247\243\345\206\263\346\226\271\346\241\210.md" @@ -1,14 +1,14 @@ -#Android关于OOM的解决方案 -##OOM +# Android关于OOM的解决方案 +## OOM * 内存溢出(Out Of Memory) * 也就是说内存占有量超过了VM所分配的最大 -##出现OOM的原因 +## 出现OOM的原因 1. 加载对象过大 2. 相应资源过多,来不及释放 -##如何解决 +## 如何解决 1. 在内存引用上做些处理,常用的有软引用、强化引用、弱引用 2. 在内存中加载图片时直接在内存中作处理,如边界压缩 3. 动态回收内存 diff --git "a/Part1/Android/Android\345\206\205\345\255\230\346\263\204\346\274\217\346\200\273\347\273\223.md" "b/Part1/Android/Android\345\206\205\345\255\230\346\263\204\346\274\217\346\200\273\347\273\223.md" index 445f397..24e075c 100644 --- "a/Part1/Android/Android\345\206\205\345\255\230\346\263\204\346\274\217\346\200\273\347\273\223.md" +++ "b/Part1/Android/Android\345\206\205\345\255\230\346\263\204\346\274\217\346\200\273\347\273\223.md" @@ -1,11 +1,11 @@ -#Android 内存泄漏总结 +# Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例所持有却不再被使用导致 GC 不能回收。最近自己阅读了大量相关的文档资料,打算做个 总结 沉淀下来跟大家一起分享和学习,也给自己一个警示,以后 coding 时怎么避免这些情况,提高应用的体验和质量。 我会从 java 内存泄漏的基础知识开始,并通过具体例子来说明 Android 引起内存泄漏的各种原因,以及如何利用工具来分析应用内存泄漏,最后再做总结。 -##Java 内存分配策略 +## Java 内存分配策略 Java 程序运行时的内存分配策略有三种,分别是静态分配,栈式分配,和堆式分配,对应的,三种存储策略使用的内存空间主要分别是静态存储区(也称方法区)、栈区和堆区。 @@ -15,7 +15,7 @@ Java 程序运行时的内存分配策略有三种,分别是静态分配,栈式 * 堆区 : 又称动态内存分配,通常就是指在程序运行时直接 new 出来的内存,也就是对象的实例。这部分内存在不使用时将会由 Java 垃圾回收器来负责回收。 -##栈与堆的区别: +## 栈与堆的区别: 在方法体内定义的(局部变量)一些基本类型的变量和对象的引用变量都是在方法的栈内存中分配的。当在一段方法块中定义一个变量时,Java 就会在栈中为该变量分配内存空间,当超过该变量的作用域后,该变量也就无效了,分配给它的内存空间也将被释放掉,该内存空间可以被重新使用。 @@ -48,7 +48,7 @@ mSample3 指向的对象实体存放在堆上,包括这个对象的所有成 了解了 Java 的内存分配之后,我们再来看看 Java 是怎么管理内存的。 -##Java是如何管理内存 +## Java是如何管理内存 Java的内存管理就是对象的分配和释放问题。在 Java 中,程序员需要通过关键字 new 为每个对象申请内存空间 (基本类型除外),所有的对象都在堆 (Heap)中分配空间。另外,对象的释放是由 GC 决定和执行的。在 Java 中,内存的分配是由程序完成的,而内存的释放是由 GC 完成的,这种收支两条线的方法确实简化了程序员的工作。但同时,它也加重了JVM的工作。这也是 Java 程序运行速度较慢的原因之一。因为,GC 为了能够正确释放对象,GC 必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC 都需要进行监控。 @@ -61,7 +61,7 @@ Java的内存管理就是对象的分配和释放问题。在 Java 中,程序 Java使用有向图的方式进行内存管理,可以消除引用循环的问题,例如有三个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的。这种方式的优点是管理内存的精度很高,但是效率较低。另外一种常用的内存管理技术是使用计数器,例如COM模型采用计数器方式管理构件,它与有向图相比,精度行低(很难处理循环引用的问题),但执行效率很高。 -##什么是Java中的内存泄露 +## 什么是Java中的内存泄露 在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。 @@ -190,14 +190,14 @@ this.a=a; 显然B采用singleton模式,它持有一个A对象的引用,而这个A类的对象将不能被回收。想象下如果A是个比较复杂的对象或者集合类型会发生什么情况 -##Android中常见的内存泄漏汇总 +## Android中常见的内存泄漏汇总 --- -###集合类泄漏 +### 集合类泄漏 集合类如果仅仅有添加元素的方法,而没有相应的删除机制,导致内存被占用。如果这个集合类是全局性的变量 (比如类中的静态属性,全局性的 map 等即有静态引用或 final 一直指向它),那么没有相应的删除机制,很可能导致集合所占用的内存只增不减。比如上面的典型例子就是其中一种情况,当然实际上我们在项目中肯定不会写这么 2B 的代码,但稍不注意还是很容易出现这种情况,比如我们都喜欢通过 HashMap 做一些缓存之类的事,这种情况就要多留一些心眼。 -###单例造成的内存泄漏 +### 单例造成的内存泄漏 由于单例的静态特性使得其生命周期跟应用的生命周期一样长,所以如果使用不恰当的话,很容易造成内存泄漏。比如下面一个典型的例子, @@ -274,7 +274,7 @@ return instance; } ``` -###匿名内部类/非静态内部类和异步线程 +### 匿名内部类/非静态内部类和异步线程 非静态内部类创建静态实例造成的内存泄漏 @@ -305,7 +305,7 @@ return instance; 其中: NO1表示 Application 和 Service 可以启动一个 Activity,不过需要创建一个新的 task 任务队列。而对于 Dialog 而言,只有在 Activity 中才能创建 -###匿名内部类 +### 匿名内部类 android开发经常会继承实现Activity/Fragment/View,此时如果你使用了匿名类,并被异步线程持有了,那要小心了,如果没有任何措施这样一定会导致泄露 @@ -333,7 +333,7 @@ ref1和ref2的区别是,ref2使用了匿名内部类。我们来看看运行 this$0这个引用指向MainActivity.this,也就是说当前的MainActivity实例会被ref2持有,如果将这个引用再传入一个异步线程,此线程和此Acitivity生命周期不一致的时候,就造成了Activity的泄露。 -###Handler 造成的内存泄漏 +### Handler 造成的内存泄漏 Handler 的使用造成的内存泄漏问题应该说是最为常见了,很多时候我们为了避免 ANR 而不在主线程进行耗时操作,在处理网络任务或者封装一些请求回调等api都借助Handler来处理,但 Handler 不是万能的,对于 Handler 的使用代码编写一不规范即有可能造成内存泄漏。另外,我们知道 Handler、Message 和 MessageQueue 都是相互关联在一起的,万一 Handler 发送的 Message 尚未被处理,则该 Message 及发送它的 Handler 对象将被线程 MessageQueue 一直持有。 @@ -464,7 +464,7 @@ public final void removeMessages(int what); public final void removeMessages(int what, Object object); ``` -###尽量避免使用 static 成员变量 +### 尽量避免使用 static 成员变量 如果成员变量被声明为 static,那我们都知道其生命周期将与整个app进程生命周期一样。 @@ -475,7 +475,7 @@ public final void removeMessages(int what, Object object); 不要在类初始时初始化静态成员。可以考虑lazy初始化。 架构设计上要思考是否真的有必要这样做,尽量避免。如果架构需要这么设计,那么此对象的生命周期你有责任管理起来。 -###避免 override finalize() +### 避免 override finalize() 1、finalize 方法被执行的时间不确定,不能依赖与它来释放紧缺的资源。时间不确定的原因是: 虚拟机调用GC的时间不确定 @@ -488,11 +488,11 @@ public final void removeMessages(int what, Object object); 3、含有Finalize方法的object需要至少经过两轮GC才有可能被释放。 -###资源未关闭造成的内存泄漏 +### 资源未关闭造成的内存泄漏 对于使用了BraodcastReceiver,ContentObserver,File,游标 Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。 -###一些不良代码造成的内存压力 +### 一些不良代码造成的内存压力 有些代码并不造成内存泄露,但是它们,或是对没使用的内存没进行有效及时的释放,或是没有有效的利用已有的对象而是频繁的申请新内存。 @@ -500,7 +500,7 @@ public final void removeMessages(int what, Object object); Bitmap 没调用 recycle()方法,对于 Bitmap 对象在不使用时,我们应该先调用 recycle() 释放内存,然后才它设置为 null. 因为加载 Bitmap 对象的内存空间,一部分是 java 的,一部分 C 的(因为 Bitmap 分配的底层是通过 JNI 调用的 )。 而这个 recyle() 就是针对 C 部分的内存释放。 构造 Adapter 时,没有使用缓存的 convertView ,每次都在创建新的 converView。这里推荐使用 ViewHolder。 -##总结 +## 总结 对 Activity 等组件的引用应该控制在 Activity 的生命周期之内; 如果不能就考虑使用 getApplicationContext 或者 getApplication,以避免 Activity 被外部长生命周期的对象引用而泄露。 diff --git "a/Part1/Android/Android\345\207\240\347\247\215\350\277\233\347\250\213.md" "b/Part1/Android/Android\345\207\240\347\247\215\350\277\233\347\250\213.md" index 5276186..35034f4 100644 --- "a/Part1/Android/Android\345\207\240\347\247\215\350\277\233\347\250\213.md" +++ "b/Part1/Android/Android\345\207\240\347\247\215\350\277\233\347\250\213.md" @@ -1,4 +1,4 @@ -#Android几种进程 +# Android几种进程 --- 1. 前台进程:即与用户正在交互的Activity或者Activity用到的Service等,如果系统内存不足时前台进程是最后被杀死的 diff --git "a/Part1/Android/Android\345\233\276\347\211\207\344\270\255\347\232\204\344\270\211\347\272\247\347\274\223\345\255\230.md" "b/Part1/Android/Android\345\233\276\347\211\207\344\270\255\347\232\204\344\270\211\347\272\247\347\274\223\345\255\230.md" index 8c0dd56..b4b3614 100644 --- "a/Part1/Android/Android\345\233\276\347\211\207\344\270\255\347\232\204\344\270\211\347\272\247\347\274\223\345\255\230.md" +++ "b/Part1/Android/Android\345\233\276\347\211\207\344\270\255\347\232\204\344\270\211\347\272\247\347\274\223\345\255\230.md" @@ -1,25 +1,25 @@ -#Android图片中的三级缓存 +# Android图片中的三级缓存 --- -##为什么要使用三级缓存 +## 为什么要使用三级缓存 * 如今的 Android App 经常会需要网络交互,通过网络获取图片是再正常不过的事了 * 假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量。在当前的状况下,对于非wifi用户来说,流量还是很贵的,一个很耗流量的应用,其用户数量级肯定要受到影响 * 特别是,当我们想要重复浏览一些图片时,如果每一次浏览都需要通过网络获取,流量的浪费可想而知 * 所以提出三级缓存策略,通过网络、本地、内存三级缓存图片,来减少不必要的网络交互,避免浪费流量 -##什么是三级缓存 +## 什么是三级缓存 * 网络加载,不优先加载,速度慢,浪费流量 * 本地缓存,次优先加载,速度快 * 内存缓存,优先加载,速度最快 -##三级缓存原理 +## 三级缓存原理 * 首次加载 Android App 时,肯定要通过网络交互来获取图片,之后我们可以将图片保存至本地SD卡和内存中 * 之后运行 App 时,优先访问内存中的图片缓存,若内存中没有,则加载本地SD卡中的图片 -* 总之,只在初次访问新内容时,才通过网络获取图片资源 +* 总之,只在初次访问新内容时,才通过网络获取图片资源 参考链接 diff --git "a/Part1/Android/Android\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/Part1/Android/Android\345\237\272\347\241\200\347\237\245\350\257\206.md" index 359b62f..cc6299f 100644 --- "a/Part1/Android/Android\345\237\272\347\241\200\347\237\245\350\257\206.md" +++ "b/Part1/Android/Android\345\237\272\347\241\200\347\237\245\350\257\206.md" @@ -1,5 +1,7 @@ -#Android: +# Android: + --- + **五种布局: FrameLayout 、 LinearLayout 、 AbsoluteLayout 、 RelativeLayout 、 TableLayout 全都继承自ViewGroup,各自特点及绘制效率对比。** * FrameLayout(框架布局) @@ -178,7 +180,7 @@ public void onRestoreInstanceState(Bundle savedInstanceState) { **Fragment的生命周期和activity如何的一个关系** 这我们引用本知识库里的一张图片: -![Mou icon](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/FlowchartDiagram.jpg?raw=true) +![Mou icon](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/FlowchartDiagram.jpg?raw=true) **为什么在Service中创建子线程而不是Activity中** diff --git "a/Part1/Android/Android\346\200\247\350\203\275\344\274\230\345\214\226.md" "b/Part1/Android/Android\346\200\247\350\203\275\344\274\230\345\214\226.md" index 2945c5f..2c3528b 100644 --- "a/Part1/Android/Android\346\200\247\350\203\275\344\274\230\345\214\226.md" +++ "b/Part1/Android/Android\346\200\247\350\203\275\344\274\230\345\214\226.md" @@ -1,38 +1,38 @@ -#Android性能优化 +# Android性能优化 --- -##合理管理内存 +## 合理管理内存 --- -###节制的使用Service +### 节制的使用Service 如果应用程序需要使用Service来执行后台任务的话,只有当任务正在执行的时候才应该让Service运行起来。当启动一个Service时,系统会倾向于将这个Service所依赖的进程进行保留,系统可以在LRUcache当中缓存的进程数量也会减少,导致切换程序的时候耗费更多性能。我们可以使用IntentService,当后台任务执行结束后会自动停止,避免了Service的内存泄漏。 -###当界面不可见时释放内存 +### 当界面不可见时释放内存 当用户打开了另外一个程序,我们的程序界面已经不可见的时候,我们应当将所有和界面相关的资源进行释放。重写Activity的onTrimMemory()方法,然后在这个方法中监听TRIM_MEMORY_UI_HIDDEN这个级别,一旦触发说明用户离开了程序,此时就可以进行资源释放操作了。 -###当内存紧张时释放内存 +### 当内存紧张时释放内存 onTrimMemory()方法还有很多种其他类型的回调,可以在手机内存降低的时候及时通知我们,我们应该根据回调中传入的级别来去决定如何释放应用程序的资源。 -###避免在Bitmap上浪费内存 +### 避免在Bitmap上浪费内存 读取一个Bitmap图片的时候,千万不要去加载不需要的分辨率。可以压缩图片等操作。 -###是有优化过的数据集合 +### 是有优化过的数据集合 Android提供了一系列优化过后的数据集合工具类,如SparseArray、SparseBooleanArray、LongSparseArray,使用这些API可以让我们的程序更加高效。HashMap工具类会相对比较低效,因为它需要为每一个键值对都提供一个对象入口,而SparseArray就避免掉了基本数据类型转换成对象数据类型的时间。 -###知晓内存的开支情况 +### 知晓内存的开支情况 * 使用枚举通常会比使用静态常量消耗两倍以上的内存,尽可能不使用枚举 * 任何一个Java类,包括匿名类、内部类,都要占用大概500字节的内存空间 * 任何一个类的实例要消耗12-16字节的内存开支,因此频繁创建实例也是会在一定程序上影响内存的 * 使用HashMap时,即使你只设置了一个基本数据类型的键,比如说int,但是也会按照对象的大小来分配内存,大概是32字节,而不是4字节,因此最好使用优化后的数据集合 -###谨慎使用抽象编程 +### 谨慎使用抽象编程 在Android使用抽象编程会带来额外的内存开支,因为抽象的编程方法需要编写额外的代码,虽然这些代码根本执行不到,但是也要映射到内存中,不仅占用了更多的内存,在执行效率上也会有所降低。所以需要合理的使用抽象编程。 -###尽量避免使用依赖注入框架 +### 尽量避免使用依赖注入框架 使用依赖注入框架貌似看上去把findViewById()这一类的繁琐操作去掉了,但是这些框架为了要搜寻代码中的注解,通常都需要经历较长的初始化过程,并且将一些你用不到的对象也一并加载到内存中。这些用不到的对象会一直站用着内存空间,可能很久之后才会得到释放,所以可能多敲几行代码是更好的选择。 -###使用多个进程 +### 使用多个进程 谨慎使用,多数应用程序不该在多个进程中运行的,一旦使用不当,它甚至会增加额外的内存而不是帮我们节省内存。这个技巧比较适用于哪些需要在后台去完成一项独立的任务,和前台是完全可以区分开的场景。比如音乐播放,关闭软件,已经完全由Service来控制音乐播放了,系统仍然会将许多UI方面的内存进行保留。在这种场景下就非常适合使用两个进程,一个用于UI展示,另一个用于在后台持续的播放音乐。关于实现多进程,只需要在Manifast文件的应用程序组件声明一个android:process属性就可以了。进程名可以自定义,但是之前要加个冒号,表示该进程是一个当前应用程序的私有进程。 -##分析内存的使用情况 +## 分析内存的使用情况 --- 系统不可能将所有的内存都分配给我们的应用程序,每个程序都会有可使用的内存上限,被称为堆大小。不同的手机堆大小不同,如下代码可以获得堆大小: @@ -42,18 +42,18 @@ int heapSize = manager.getMemoryClass(); ``` 结果以MB为单位进行返回,我们开发时应用程序的内存不能超过这个限制,否则会出现OOM。 -###Android的GC操作 +### Android的GC操作 Android系统会在适当的时机触发GC操作,一旦进行GC操作,就会将一些不再使用的对象进行回收。GC操作会从一个叫做Roots的对象开始检查,所有它可以访问到的对象就说明还在使用当中,应该进行保留,而其他的对系那个就表示已经不再被使用了。 -###Android中内存泄漏 +### Android中内存泄漏 Android中的垃圾回收机制并不能防止内存泄漏的出现导致内存泄漏最主要的原因就是某些长存对象持有了一些其它应该被回收的对象的引用,导致垃圾回收器无法去回收掉这些对象,也就是出现内存泄漏了。比如说像Activity这样的系统组件,它又会包含很多的控件甚至是图片,如果它无法被垃圾回收器回收掉的话,那就算是比较严重的内存泄漏情况了。 举个例子,在MainActivity中定义一个内部类,实例化内部类对象,在内部类新建一个线程执行死循环,会导致内部类资源无法释放,MainActivity的控件和资源无法释放,导致OOM,可借助一系列工具,比如LeakCanary。 -##高性能编码优化 +## 高性能编码优化 --- 都是一些微优化,在性能方面看不出有什么显著的提升的。使用合适的算法和数据结构是优化程序性能的最主要手段。 -###避免创建不必要的对象 +### 避免创建不必要的对象 不必要的对象我们应该避免创建: * 如果有需要拼接的字符串,那么可以优先考虑使用StringBuffer或者StringBuilder来进行拼接,而不是加号连接符,因为使用加号连接符会创建多余的对象,拼接的字符串越长,加号连接符的性能越低。 @@ -63,10 +63,10 @@ Android中的垃圾回收机制并不能防止内存泄漏的出现导致内存 尽可能地少创建临时对象,越少的对象意味着越少的GC操作。 -###静态优于抽象 +### 静态优于抽象 如果你并不需要访问一个对系那个中的某些字段,只是想调用它的某些方法来去完成一项通用的功能,那么可以将这个方法设置成静态方法,调用速度提升15%-20%,同时也不用为了调用这个方法去专门创建对象了,也不用担心调用这个方法后是否会改变对象的状态(静态方法无法访问非静态字段)。 -###对常量使用static final修饰符 +### 对常量使用static final修饰符 ``` static int intVal = 42; static String strVal = "Hello, world!"; @@ -84,7 +84,7 @@ static final String strVal = "Hello, world!"; 这种优化方式只对基本数据类型以及String类型的常量有效,对于其他数据类型的常量是无效的。 -###使用增强型for循环语法 +### 使用增强型for循环语法 ``` static class Counter { @@ -121,18 +121,18 @@ zero()最慢,每次都要计算mArray的长度,one()相对快得多,two()f Tips:ArrayList手写的循环比增强型for循环更快,其他的集合没有这种情况。因此默认情况下使用增强型for循环,而遍历ArrayList使用传统的循环方式。 -###多使用系统封装好的API +### 多使用系统封装好的API 系统提供不了的Api完成不了我们需要的功能才应该自己去写,因为使用系统的Api很多时候比我们自己写的代码要快得多,它们的很多功能都是通过底层的汇编模式执行的。 举个例子,实现数组拷贝的功能,使用循环的方式来对数组中的每一个元素一一进行赋值当然可行,但是直接使用系统中提供的System.arraycopy()方法会让执行效率快9倍以上。 -###避免在内部调用Getters/Setters方法 +### 避免在内部调用Getters/Setters方法 面向对象中封装的思想是不要把类内部的字段暴露给外部,而是提供特定的方法来允许外部操作相应类的内部字段。但在Android中,字段搜寻比方法调用效率高得多,我们直接访问某个字段可能要比通过getters方法来去访问这个字段快3到7倍。但是编写代码还是要按照面向对象思维的,我们应该在能优化的地方进行优化,比如避免在内部调用getters/setters方法。 -##布局优化技巧 +## 布局优化技巧 --- -###重用布局文件 +### 重用布局文件 **** 标签可以允许在一个布局当中引入另一个布局,那么比如说我们程序的所有界面都有一个公共的部分,这个时候最好的做法就是将这个公共的部分提取到一个独立的布局中,然后每个界面的布局文件当中来引用这个公共的布局。 @@ -145,7 +145,7 @@ Tips:如果我们要在标签中覆写layout属性,必须要将layout 举例:比如在LinearLayout里边使用一个布局。里边又有一个LinearLayout,那么其实就存在了多余的布局嵌套,使用merge可以解决这个问题。 -###仅在需要时才加载布局 +### 仅在需要时才加载布局 某个布局当中的元素不是一起显示出来的,普通情况下只显示部分常用的元素,而那些不常用的元素只有在用户进行特定操作时才会显示出来。 diff --git "a/Part1/Android/Android\347\263\273\347\273\237\346\234\272\345\210\266.md" "b/Part1/Android/Android\347\263\273\347\273\237\346\234\272\345\210\266.md" index 0871f4c..4484ecb 100644 --- "a/Part1/Android/Android\347\263\273\347\273\237\346\234\272\345\210\266.md" +++ "b/Part1/Android/Android\347\263\273\347\273\237\346\234\272\345\210\266.md" @@ -1,12 +1,12 @@ -#Android系统机制 +# Android系统机制 --- -###APP启动过程 +### APP启动过程 1. Launcher线程捕获onclick的点击事件,调用Launcher.startActivitySafely,进一步调用Launcher.startActivity,最后调用父类Activity的startActivity。 2. Activity和ActivityManagerService交互,引入Instrumentation,将启动请求交给Instrumentation,调用Instrumentation.execStartActivity 3. -###Android内核解读-应用的安装过程 +### Android内核解读-应用的安装过程 [http://blog.csdn.net/singwhatiwanna/article/details/19578947](http://blog.csdn.net/singwhatiwanna/article/details/19578947) apk的安装过程分为两步: @@ -15,14 +15,14 @@ apk的安装过程分为两步: 2. 为应用创建数据目录(/data/data/package name/)、提取dex文件到指定目录(/data/delvik-cache/)、修改系统包管理信息。 -###View的事件体系 +### View的事件体系 -###Handler消息机制 +### Handler消息机制 -###AsyncTask +### AsyncTask AyncTask是一个抽象类。 需要重写的方法有四个: @@ -88,7 +88,7 @@ new DownloadTask().execute(); -###图片缓存机制 +### 图片缓存机制 diff --git "a/Part1/Android/Art\345\222\214Dalvik\345\214\272\345\210\253.md" "b/Part1/Android/Art\345\222\214Dalvik\345\214\272\345\210\253.md" index 08df309..7a28d20 100644 --- "a/Part1/Android/Art\345\222\214Dalvik\345\214\272\345\210\253.md" +++ "b/Part1/Android/Art\345\222\214Dalvik\345\214\272\345\210\253.md" @@ -1,4 +1,4 @@ -#ART和Dalvik区别 +# ART和Dalvik区别 --- Art上应用启动快,运行快,但是耗费更多存储空间,安装时间长,总的来说ART的功效就是"空间换时间"。 diff --git "a/Part1/Android/Asynctask\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/Part1/Android/Asynctask\346\272\220\347\240\201\345\210\206\346\236\220.md" index 4867eab..a75c9e6 100644 --- "a/Part1/Android/Asynctask\346\272\220\347\240\201\345\210\206\346\236\220.md" +++ "b/Part1/Android/Asynctask\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -1,4 +1,4 @@ -#AsyncTask +# AsyncTask --- diff --git "a/Part1/Android/Binder\346\234\272\345\210\266.md" "b/Part1/Android/Binder\346\234\272\345\210\266.md" index 657b813..3e2e21c 100644 --- "a/Part1/Android/Binder\346\234\272\345\210\266.md" +++ "b/Part1/Android/Binder\346\234\272\345\210\266.md" @@ -1,4 +1,4 @@ -#Binder机制 +# Binder机制 --- 首先Binder是Android系统进程间通信(IPC)方式之一。 @@ -12,7 +12,7 @@ Server创建了Binder实体,为其取一个字符形式,可读易记的名 --- -###为什么Binder只进行了一次数据拷贝? +### 为什么Binder只进行了一次数据拷贝? Linux内核实际上没有从一个用户空间到另一个用户空间直接拷贝的函数,需要先用copy_from_user()拷贝到内核空间,再用copy_to_user()拷贝到另一个用户空间。为了实现用户空间到用户空间的拷贝,mmap()分配的内存除了映射进了接收方进程里,还映射进了内核空间。所以调用copy_from_user()将数据拷贝进内核空间也相当于拷贝进了接收方的用户空间,这就是Binder只需一次拷贝的‘秘密’。 diff --git "a/Part1/Android/Bitmap\347\232\204\345\210\206\346\236\220\344\270\216\344\275\277\347\224\250.md" "b/Part1/Android/Bitmap\347\232\204\345\210\206\346\236\220\344\270\216\344\275\277\347\224\250.md" index 32344ed..0e2cb6a 100644 --- "a/Part1/Android/Bitmap\347\232\204\345\210\206\346\236\220\344\270\216\344\275\277\347\224\250.md" +++ "b/Part1/Android/Bitmap\347\232\204\345\210\206\346\236\220\344\270\216\344\275\277\347\224\250.md" @@ -123,7 +123,7 @@ 上面介绍了``BitmapFactory``通过``InputStream``去创建`Bitmap`的这种方式,以及``BitmapFactory.Options.inSimpleSize`` 和 ``BitmapFactory.Options.inJustDecodeBounds``的使用方法,但将单个Bitmap加载到UI是简单的,但是如果我们需要一次性加载大量的图片,事情就会变得复杂起来。`Bitmap`是吃内存大户,我们不希望多次解析相同的`Bitmap`,也不希望可能不会用到的`Bitmap`一直存在于内存中,所以,这个场景下,`Bitmap`的重用变得异常的重要。 *在这里只介绍一种``BitmapFactory.Options.inBitmap``的重用方式,下一篇文章会介绍使用三级缓存来实现Bitmap的重用。* - 根据官方文档[在Android 3.0 引进了BitmapFactory.Options.inBitmap](https://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inBitmap),如果这个值被设置了,decode方法会在加载内容的时候去重用已经存在的bitmap. 这意味着bitmap的内存是被重新利用的,这样可以提升性能, 并且减少了内存的分配与回收。然而,使用inBitmap有一些限制。特别是在Android 4.4 之前,只支持同等大小的位图。 + 根据官方文档[在Android 3.0 引进了BitmapFactory.Options.inBitmap](https://developer.android.com/reference/android/graphics/BitmapFactory.Options.html# inBitmap),如果这个值被设置了,decode方法会在加载内容的时候去重用已经存在的bitmap. 这意味着bitmap的内存是被重新利用的,这样可以提升性能, 并且减少了内存的分配与回收。然而,使用inBitmap有一些限制。特别是在Android 4.4 之前,只支持同等大小的位图。 我们看来看看这个参数最基本的运用方法。 ``` diff --git "a/Part1/Android/EventBus\347\224\250\346\263\225\350\257\246\350\247\243.md" "b/Part1/Android/EventBus\347\224\250\346\263\225\350\257\246\350\247\243.md" index 28c7ce0..bd2779b 100644 --- "a/Part1/Android/EventBus\347\224\250\346\263\225\350\257\246\350\247\243.md" +++ "b/Part1/Android/EventBus\347\224\250\346\263\225\350\257\246\350\247\243.md" @@ -1,11 +1,11 @@ -#EventBus +# EventBus --- -###概述 +### 概述 EventBus是一款针对Android优化的发布/订阅(publish/subscribe)事件总线。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间传递消息。简化了应用程序内各组件间、组件与后台线程间的通信。优点是开销小,代码更优雅。以及将发送者和接收者解耦。比如请求网络,等网络返回时通过Handler或Broadcast通知UI,两个Fragment之间需要通过Listener通信,这些需求都可以通过EventBus实现。 -###EventBus作为一个消息总线,有三个主要的元素: +### EventBus作为一个消息总线,有三个主要的元素: * Event:事件。可以是任意类型的对象 * Subscriber:事件订阅者,接收特定的事件。在EventBus中,使用约定来指定事件订阅者以简化使用。即所有事件订阅都都是以onEvent开头的函数,具体来说,函数的名字是onEvent,onEventMainThread,onEventBackgroundThread,onEventAsync这四个,这个和 @@ -13,7 +13,7 @@ ThreadMode(下面讲)有关。 * Publisher:事件发布者,用于通知 Subscriber 有事件发生。可以在任意线程任意位置发送事件,直接调用eventBus.post(Object) 方法,可以自己实例化 EventBus 对象,但一般使用默认的单例就好了:EventBus.getDefault(), 根据post函数参数的类型,会自动调用订阅相应类型事件的函数。 -###关于ThreadMode +### 关于ThreadMode 前面说了,Subscriber的函数只能是那4个,因为每个事件订阅函数都是和一个ThreadMode相关联的,ThreadMode指定了会调用的函数。有以下四个ThreadMode: @@ -34,9 +34,9 @@ ThreadMode(下面讲)有关。 **onEventAsync**:使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync。 -##基本用法 +## 基本用法 -###引入EventBus: +### 引入EventBus: ``` compile 'org.greenrobot:eventbus:3.0.0' @@ -84,7 +84,7 @@ eventBus.unregister(this); 最后,proguard 需要做一些额外处理: ``` -#EventBus +# EventBus -keepclassmembers class ** { public void onEvent*(**); void onEvent*(**); diff --git a/Part1/Android/Fragment.md b/Part1/Android/Fragment.md index fb2b3ea..d6f426c 100755 --- a/Part1/Android/Fragment.md +++ b/Part1/Android/Fragment.md @@ -1,24 +1,24 @@ -#Fragment +# Fragment -##为何产生 +## 为何产生 * 同时适配手机和平板、UI和逻辑的共享。 -##介绍 +## 介绍 * Fragment也会被加入回退栈中。 * Fragment拥有自己的生命周期和接受、处理用户的事件 * 可以动态的添加、替换和移除某个Fragment -##生命周期 +## 生命周期 * 必须依存于Activity ![Mou icon](http://img.blog.csdn.net/20140719225005356?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG1qNjIzNTY1Nzkx/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) * Fragment依附于Activity的生命状态 -* ![Mou icon](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/FlowchartDiagram.jpg?raw=true) +* ![Mou icon](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/FlowchartDiagram.jpg?raw=true) 生命周期中那么多方法,懵逼了的话我们就一起来看一下每一个生命周期方法的含义吧。 -##Fragment生命周期方法含义: +## Fragment生命周期方法含义: * `public void onAttach(Context context)` * onAttach方法会在Fragment于窗口关联后立刻调用。从该方法开始,就可以通过Fragment.getActivity方法获取与Fragment关联的窗口对象,但因为Fragment的控件未初始化,所以不能够操作控件。 @@ -55,19 +55,19 @@ * `public void onDetach()` * 为Fragment生命周期中的最后一个方法,当该方法执行完后,Fragment与Activity不再有关联(分手!我们分手!!(╯‵□′)╯︵┻━┻)。 -##Fragment比Activity多了几个额外的生命周期回调方法: +## Fragment比Activity多了几个额外的生命周期回调方法: * onAttach(Activity):当Fragment和Activity发生关联时使用 * onCreateView(LayoutInflater, ViewGroup, Bundle):创建该Fragment的视图 * onActivityCreate(Bundle):当Activity的onCreate方法返回时调用 * onDestoryView():与onCreateView相对应,当该Fragment的视图被移除时调用 * onDetach():与onAttach相对应,当Fragment与Activity关联被取消时调用 -###注意:除了onCreateView,其他的所有方法如果你重写了,必须调用父类对于该方法的实现 +### 注意:除了onCreateView,其他的所有方法如果你重写了,必须调用父类对于该方法的实现 -##Fragment与Activity之间的交互 +## Fragment与Activity之间的交互 * Fragment与Activity之间的交互可以通过`Fragment.setArguments(Bundle args)`以及`Fragment.getArguments()`来实现。 -##Fragment状态的持久化。 +## Fragment状态的持久化。 由于Activity会经常性的发生配置变化,所以依附它的Fragment就有需要将其状态保存起来问题。下面有两个常用的方法去将Fragment的状态持久化。 * 方法一: @@ -123,11 +123,11 @@ ``` -##静态的使用Fragment +## 静态的使用Fragment 1. 继承Fragment,重写onCreateView决定Fragment的布局 2. 在Activity中声明此Fragment,就和普通的View一样 -##Fragment常用的API +## Fragment常用的API * android.support.v4.app.Fragment 主要用于定义Fragment * android.support.v4.app.FragmentManager 主要用于在Activity中操作Fragment,可以使用FragmentManager.findFragmenById,FragmentManager.findFragmentByTag等方法去找到一个Fragment * android.support.v4.app.FragmentTransaction 保证一些列Fragment操作的原子性,熟悉事务这个词 @@ -174,7 +174,7 @@ ``` -##管理Fragment回退栈 +## 管理Fragment回退栈 * 跟踪回退栈状态 * 我们通过实现*``OnBackStackChangedListener``*接口来实现回退栈状态跟踪,具体如下 ``` diff --git "a/Part1/Android/Git\346\223\215\344\275\234.md" "b/Part1/Android/Git\346\223\215\344\275\234.md" index cb55eff..270921a 100644 --- "a/Part1/Android/Git\346\223\215\344\275\234.md" +++ "b/Part1/Android/Git\346\223\215\344\275\234.md" @@ -133,7 +133,7 @@ git checkout [branch-name] git checkout -b [branch-name] ``` -##与github建立ssh通信,让Git操作免去输入密码的繁琐。 +## 与github建立ssh通信,让Git操作免去输入密码的繁琐。 * 首先呢,我们先建立ssh密匙。 > ssh key must begin with 'ssh-ed25519', 'ssh-rsa', 'ssh-dss', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', or 'ecdsa-sha2-nistp521'. -- from github diff --git "a/Part1/Android/Handler\345\206\205\345\255\230\346\263\204\346\274\217\345\210\206\346\236\220\345\217\212\350\247\243\345\206\263.md" "b/Part1/Android/Handler\345\206\205\345\255\230\346\263\204\346\274\217\345\210\206\346\236\220\345\217\212\350\247\243\345\206\263.md" index fcfef72..2448df5 100644 --- "a/Part1/Android/Handler\345\206\205\345\255\230\346\263\204\346\274\217\345\210\206\346\236\220\345\217\212\350\247\243\345\206\263.md" +++ "b/Part1/Android/Handler\345\206\205\345\255\230\346\263\204\346\274\217\345\210\206\346\236\220\345\217\212\350\247\243\345\206\263.md" @@ -1,7 +1,7 @@ -#Handler内存泄漏分析及解决 +# Handler内存泄漏分析及解决 --- -###一、介绍 +### 一、介绍 首先,请浏览下面这段handler代码: @@ -23,7 +23,7 @@ public class SampleActivity extends Activity { ``` -###二、分析 +### 二、分析 1、 Android角度 @@ -31,13 +31,13 @@ public class SampleActivity extends Activity { 另外,主线程的Looper对象会伴随该应用程序的整个生命周期。 -然后,当主线程里,实例化一个Handler对象后,它就会自动与主线程Looper的消息队列关联起来。所有发送到消息队列的消息Message都会拥有一个对Handler的引用,所以当Looper来处理消息时,会据此回调[Handler#handleMessage(Message)]方法来处理消息。 +然后,当主线程里,实例化一个Handler对象后,它就会自动与主线程Looper的消息队列关联起来。所有发送到消息队列的消息Message都会拥有一个对Handler的引用,所以当Looper来处理消息时,会据此回调[Handler# handleMessage(Message)]方法来处理消息。 2、 Java角度 在java里,非静态内部类 和 匿名类 都会潜在的引用它们所属的外部类。但是,静态内部类却不会。 -###三、泄漏来源 +### 三、泄漏来源 请浏览下面一段代码: @@ -76,7 +76,7 @@ public class SampleActivity extends Activity { 注意,上面代码中的Runnable类--非静态匿名类--同样持有对其外部类的引用。从而也导致泄漏。 >>>>>>> c67abfcfd66909095068cb5f0c8632dc5547131b -###四、泄漏解决方案 +### 四、泄漏解决方案 首先,上面已经明确了内存泄漏来源: @@ -137,7 +137,7 @@ public class SampleActivity extends Activity { } ``` -###五、小结 +### 五、小结 <<<<<<< HEAD 虽然静态类与非静态类之间的区别并不大,但是对于Android开发者而言却是必须理解的。至少我们要清楚,如果一个内部类实例的生命周期比Activity更长,那么我们千万不要使用非静态的内部类。最好的做法是,使用静态内部类,然后在该类里使用弱引用来指向所在的Activity。 diff --git "a/Part1/Android/Listview\350\257\246\350\247\243.md" "b/Part1/Android/Listview\350\257\246\350\247\243.md" index ee533a7..9269594 100644 --- "a/Part1/Android/Listview\350\257\246\350\247\243.md" +++ "b/Part1/Android/Listview\350\257\246\350\247\243.md" @@ -1,10 +1,10 @@ -#ListView详解 +# ListView详解 --- 直接继承自AbsListView,AbsListView继承自AdapterView,AdapterView又继承自ViewGroup。 Adpater在ListView和数据源之间起到了一个桥梁的作用 -###RecycleBin机制 +### RecycleBin机制 RecycleBin机制是ListView能够实现成百上千条数据都不会OOM最重要的一个原因。RecycleBin是AbsListView的一个内部类。 diff --git "a/Part1/Android/MVC,MVP,MVVM\347\232\204\345\214\272\345\210\253.md" "b/Part1/Android/MVC,MVP,MVVM\347\232\204\345\214\272\345\210\253.md" index 0624a52..b690a07 100644 --- "a/Part1/Android/MVC,MVP,MVVM\347\232\204\345\214\272\345\210\253.md" +++ "b/Part1/Android/MVC,MVP,MVVM\347\232\204\345\214\272\345\210\253.md" @@ -1,8 +1,8 @@ -#MVC,MVP,MVVM的区别 +# MVC,MVP,MVVM的区别 --- -#MVC +# MVC 软件可以分为三部分 * 视图(View):用户界面 @@ -17,13 +17,13 @@ Tips:所有的通信都是单向的。 -#互动模式 +# 互动模式 接受用户指令时,MVC可以分为两种方式。一种是通过View接受指令,传递给Controller。 另一种是直接通过Controller接受指令 -#MVP +# MVP MVP模式将Controller改名为Presenter,同时改变了通信方向。 @@ -32,7 +32,7 @@ MVP模式将Controller改名为Presenter,同时改变了通信方向。 3. View非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而Presenter非常厚,所有逻辑都部署在那里。 -#MVVM +# MVVM MVVM模式将Presenter改名为ViewModel,基本上与MVP模式完全一致。 diff --git a/Part1/Android/MVP.md b/Part1/Android/MVP.md index d8ec8d0..2bae6d1 100644 --- a/Part1/Android/MVP.md +++ b/Part1/Android/MVP.md @@ -1,13 +1,13 @@ -#MVP +# MVP --- -###为什么需要MVP +### 为什么需要MVP 1. 尽量简单 大部分的安卓应用只使用View-Model结构,程序员现在更多的是和复杂的View打交道而不是解决业务逻辑。当你在应用中只使用Model-View时,到最后,你会发现“所有的事物都被连接到一起”。复杂的任务被分成细小的任务,并且很容易解决。越小的东西,bug越少,越容易debug,更好测试。在MVP模式下的View层将会变得简单,所以即便是他请求数据的时候也不需要回调函数。View逻辑变成十分直接。 2. 后台任务 当你编写一个Actviity、Fragment、自定义View的时候,你会把所有的和后台任务相关的方法写在一个静态类或者外部类中。这样,你的Task不再和Activity联系在一起,这既不会导致内存泄露,也不依赖于Activity的重建。 -###优缺点 +### 优缺点 优点: diff --git "a/Part1/Android/Recyclerview\345\222\214Listview\347\232\204\345\274\202\345\220\214.md" "b/Part1/Android/Recyclerview\345\222\214Listview\347\232\204\345\274\202\345\220\214.md" index 973a76c..09c6569 100644 --- "a/Part1/Android/Recyclerview\345\222\214Listview\347\232\204\345\274\202\345\220\214.md" +++ "b/Part1/Android/Recyclerview\345\222\214Listview\347\232\204\345\274\202\345\220\214.md" @@ -1,4 +1,4 @@ -#RecyclerView和ListView的异同 +# RecyclerView和ListView的异同 --- * ViewHolder是用来保存视图引用的类,无论是ListView亦或是RecyclerView。只不过在ListView中,ViewHolder需要自己来定义,且这只是一种推荐的使用方式,不使用当然也可以,这不是必须的。只不过不使用ViewHolder的话,ListView每次getView的时候都会调用findViewById(int),这将导致ListView性能展示迟缓。而在RecyclerView中使用RecyclerView.ViewHolder则变成了必须,尽管实现起来稍显复杂,但它却解决了ListView面临的上述不使用自定义ViewHolder时所面临的问题。 diff --git a/Part1/Android/SurfaceView.md b/Part1/Android/SurfaceView.md index 5ebcaed..252abf5 100755 --- a/Part1/Android/SurfaceView.md +++ b/Part1/Android/SurfaceView.md @@ -1,16 +1,16 @@ -##为什么要使用SurfaceView来实现动画? -###因为View的绘图存在以下缺陷: +## 为什么要使用SurfaceView来实现动画? +### 因为View的绘图存在以下缺陷: 1. View缺乏双缓冲机制 2. 当程序需要更新View上的图像时,程序必须重绘View上显示的整张图片 3. 新线程无法直接更新View组件 -##SurfaceView的绘图机制 +## SurfaceView的绘图机制 * 一般会与SurfaceView结合使用 * 调用SurfaceView的getHolder()方法即可获得SurfaceView关联的SurfaceHolder -##SurfaceHolder提供了如下方法来获取Canvas对象 +## SurfaceHolder提供了如下方法来获取Canvas对象 1. Canvas lockCanvas():锁定整个SurfaceView对象,获取该Surface上的Canvas 2. Canvas lockCanvas(Rect dirty):锁定SurfaceView上Rect划分的区域,获取该Surface上的Canvas 3. unlockCanvasAndPost(canvas):释放绘图、提交所绘制的图形,需要注意,当调用SurfaceHolder上的unlockCanvasAndPost方法之后,该方法之前所绘制的图形还处于缓冲之中,下一次lockCanvas()方法锁定的区域可能会“遮挡”它 diff --git "a/Part1/Android/Zygote\345\222\214System\350\277\233\347\250\213\347\232\204\345\220\257\345\212\250\350\277\207\347\250\213.md" "b/Part1/Android/Zygote\345\222\214System\350\277\233\347\250\213\347\232\204\345\220\257\345\212\250\350\277\207\347\250\213.md" index 1ae66ad..d97b559 100644 --- "a/Part1/Android/Zygote\345\222\214System\350\277\233\347\250\213\347\232\204\345\220\257\345\212\250\350\277\207\347\250\213.md" +++ "b/Part1/Android/Zygote\345\222\214System\350\277\233\347\250\213\347\232\204\345\220\257\345\212\250\350\277\207\347\250\213.md" @@ -1,7 +1,7 @@ -#Zygote和System进程的启动过程 +# Zygote和System进程的启动过程 --- -##init脚本的启动 +## init脚本的启动 --- ``` @@ -22,7 +22,7 @@ service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-sys * --start-system-server 表明Zygote启动完成之后,要启动System进程。 * socket zygote stream 666 在Zygote启动时,创建一个权限为666的socket。此socket用来请求Zygote创建新进程。socket的fd保存在名称为“ANDROID_SOCKET_zygote”的环境变量中。 -##Zygote进程的启动过程 +## Zygote进程的启动过程 --- ``` @@ -59,7 +59,7 @@ ZygoteInit类的main方法运行时,会通过registerZygoteSocket方法创建 selectReadable方法会返回一个整数值index。如果index为0,则说明这个是AMS发过来的连接请求。这时会与AMS建立一个新的socket连接,并包装成ZygoteConnection对象保存起来。如果index大于0,则说明这是AMS发过来的一个创建新进程的请求。此时会取出之前保存的ZygoteConnection对象,调用其中的runOnce方法创建新进程。调用完成后将connection删除。 这就是Zygote处理一次AMS请求的过程。 -##System进程的启动 +## System进程的启动 --- ``` @@ -97,7 +97,7 @@ System进程是在ZygoteInit的handleSystemServerProcess中开始启动的。 6. 执行到这里,System就将系统的关键服务启动起来了,这时候其他进程便可利用这些Service提供的基础服务了。 7. 最后会调用ActivityManagerService的systemReady方法,在该方法里会启动系统界面以及Home程序。 -##Android进程启动 +## Android进程启动 --- diff --git "a/Part1/Android/\345\274\200\346\272\220\346\241\206\346\236\266\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/Part1/Android/\345\274\200\346\272\220\346\241\206\346\236\266\346\272\220\347\240\201\345\210\206\346\236\220.md" index 80e7b96..6f9d16c 100644 --- "a/Part1/Android/\345\274\200\346\272\220\346\241\206\346\236\266\346\272\220\347\240\201\345\210\206\346\236\220.md" +++ "b/Part1/Android/\345\274\200\346\272\220\346\241\206\346\236\266\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -1,13 +1,13 @@ -#框架源码分析 +# 框架源码分析 --- -###Retrofit +### Retrofit --- -###EventBus +### EventBus --- -###Glide +### Glide --- diff --git "a/Part1/Android/\346\217\222\344\273\266\345\214\226\346\212\200\346\234\257\345\255\246\344\271\240.md" "b/Part1/Android/\346\217\222\344\273\266\345\214\226\346\212\200\346\234\257\345\255\246\344\271\240.md" index 01250bf..e8a9643 100644 --- "a/Part1/Android/\346\217\222\344\273\266\345\214\226\346\212\200\346\234\257\345\255\246\344\271\240.md" +++ "b/Part1/Android/\346\217\222\344\273\266\345\214\226\346\212\200\346\234\257\345\255\246\344\271\240.md" @@ -1,4 +1,4 @@ -###Android动态加载dex技术初探 +### Android动态加载dex技术初探 [http://blog.csdn.net/u013478336/article/details/50734108](http://blog.csdn.net/u013478336/article/details/50734108) @@ -6,7 +6,7 @@ Android使用Dalvik虚拟机加载可执行程序,所以不能直接加载基 Android支持动态加载的两种方式是:DexClassLoader和PathClassLoader,DexClassLoader可加载jar/apk/dex,且支持从SD卡加载;PathClassLoader据说只能加载已经安装在Android系统内APK文件。 -###Android插件化基础 +### Android插件化基础 Android简单来说就是如下操作: @@ -14,7 +14,7 @@ Android简单来说就是如下操作: * 宿主下载或者从本地加载Jar或者APK到宿主中 * 将宿主调用插件中的算法或者Android特定的Class(如Activity) -###插件化开发—动态加载技术加载已安装和未安装的apk +### 插件化开发—动态加载技术加载已安装和未安装的apk [http://blog.csdn.net/u010687392/article/details/47121729?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io](http://blog.csdn.net/u010687392/article/details/47121729?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io) 为什么引入动态加载技术? @@ -39,7 +39,7 @@ Android简单来说就是如下操作: -#插件化技术学习 +# 插件化技术学习 --- 原因: @@ -53,13 +53,13 @@ Android简单来说就是如下操作: 1. 代码加载 2. 资源加载 -###代码加载 +### 代码加载 类的加载可以使用Java的ClassLoader机制,还需要组件生命周期管理。 -###资源加载 +### 资源加载 用AssetManager的隐藏方法addAssetPath。 -##Android插件化原理解析——Hook机制之动态代理 +## Android插件化原理解析——Hook机制之动态代理 使用代理机制进行API Hook进而达到方法增强。 @@ -67,7 +67,7 @@ Android简单来说就是如下操作: 动态代理:可以简单理解为JVM可以在运行时帮我们动态生成一系列的代理类。 -###代理Hook +### 代理Hook 如果我们自己创建代理对象,然后把原始对象替换为我们的代理对象,就可以在这个代理对象中为所欲为了;修改参数,替换返回值,称之为Hook。 @@ -77,7 +77,7 @@ Android简单来说就是如下操作: 2. 选择合适的代理方式,如果是接口可以用动态代理;如果是类可以手动写代理也可以使用cglib。 3. 偷梁换柱-用代理对象替换原始对象 -##Android插件化原理解析——Hook机制之Binder Hook +## Android插件化原理解析——Hook机制之Binder Hook diff --git "a/Part1/Android/\346\237\245\346\274\217\350\241\245\347\274\272.md" "b/Part1/Android/\346\237\245\346\274\217\350\241\245\347\274\272.md" index 2811dd2..68e353d 100644 --- "a/Part1/Android/\346\237\245\346\274\217\350\241\245\347\274\272.md" +++ "b/Part1/Android/\346\237\245\346\274\217\350\241\245\347\274\272.md" @@ -1,4 +1,4 @@ -#查漏补缺 +# 查漏补缺 --- 请分析一张400*500尺寸的PNG图片加载到程序中占用内存中的大小 diff --git "a/Part1/Android/\347\203\255\344\277\256\345\244\215\346\212\200\346\234\257.md" "b/Part1/Android/\347\203\255\344\277\256\345\244\215\346\212\200\346\234\257.md" index e513857..af5013c 100644 --- "a/Part1/Android/\347\203\255\344\277\256\345\244\215\346\212\200\346\234\257.md" +++ "b/Part1/Android/\347\203\255\344\277\256\345\244\215\346\212\200\346\234\257.md" @@ -1,19 +1,19 @@ -#热修复技术 +# 热修复技术 --- APP提早发出去的包,如果出现客户端的问题,实在是干着急,覆水难收。因此线上修复方案迫在眉睫。 -###概述 +### 概述 基于Xposed中的思想,通过修改c层的Method实例描述,来实现更改与之对应的java方法的行为,从而达到修复的目的。 -###Xposed +### Xposed 诞生于XDA论坛,类似一个应用平台,不同的是其提供诸多系统级的应用。可实现许多神奇的功能。Xposed需要以越狱为前提,像是iOS中的cydia。 Xposed可以修改任何程序的任何java方法(需root),github上提供了XposedInstaller,是一个android app。提供很多framework层,应用层级的程序。开发者可以为其开发一些系统或应用方面的插件,自定义android系统,它甚至可以做动态权限管理(XposedMods)。 -###Android系统启动与应用启动 +### Android系统启动与应用启动 Zygote进程是Android手机系统启动后,常驻的一个名为‘受精卵’的进程。 @@ -28,7 +28,7 @@ Zygote进程是Android手机系统启动后,常驻的一个名为‘受精卵 等应用启动中必要的类,触发必要的方法,比如:handleBindApplication,将此进程与对应的应用绑定的初始化方法;同时,会将zygote进程中的dalvik虚拟机实例复制一份,因此每个应用程序进程都有自己的dalvik虚拟机实例;会将已有Java运行时加载到进程中;会注册一些android核心类的jni方法到虚拟机中,支撑从c到java的启动过程。 -###Xposed做了手脚 +### Xposed做了手脚 Xposed在这个过程改写了app_process(源码在Xposed : a modified app_process binary),替换/system/bin/app_process这个二进制文件。然后做了两个事: @@ -39,7 +39,7 @@ Xposed在这个过程改写了app_process(源码在Xposed : a modified app_proce 为获得/system/bin/目录的读写权限,因而需要以root为前提。 -###Xposed的hook思想 +### Xposed的hook思想 那么Xposed是怎么hook java方法的呢?要从XposedBridge看起,重点在 XposedBridge.hookmethod(原方法的Member对象,含有新方法的XC_MethodHook对象);,这里会调到 @@ -89,7 +89,7 @@ method->insns = (const u2*) hookInfo; 现在所有被hook的方法,都指向了hookedMethodCallbackc方法中,然后在此方法中实现调用替换成为的java方法。 -###从Xposed提炼精髓 +### 从Xposed提炼精髓 回顾Xposed,以root为必要条件,在app_process加载XposedBidge.jar,从而实现有hook所有应用的所有方法的能力;而后续动态hook应用内的方法,其实只是load了从zypote进程复制出来的运行时的这个XposedBidge.jar,然后hook而已。因此,若在一个应用范围内的hook,root不是必须的,只是单纯的加载hook的实现方法,即可修改本应用的方法。 diff --git "a/Part1/Android/\347\272\277\347\250\213\351\200\232\344\277\241\345\237\272\347\241\200\346\265\201\347\250\213\345\210\206\346\236\220.md" "b/Part1/Android/\347\272\277\347\250\213\351\200\232\344\277\241\345\237\272\347\241\200\346\265\201\347\250\213\345\210\206\346\236\220.md" index defe0ca..1260dd5 100644 --- "a/Part1/Android/\347\272\277\347\250\213\351\200\232\344\277\241\345\237\272\347\241\200\346\265\201\347\250\213\345\210\206\346\236\220.md" +++ "b/Part1/Android/\347\272\277\347\250\213\351\200\232\344\277\241\345\237\272\347\241\200\346\265\201\347\250\213\345\210\206\346\236\220.md" @@ -1,6 +1,6 @@ > 老司机们都知道,Android的线程间通信就靠Handler、Looper、Message、MessageQueue这四个麻瓜兄弟了,那么,他们是怎么运作的呢?下面做一个基于主要源代码的大学生水平的分析。 [原文链接](http://anangryant.leanote.com/post/Handler%E3%80%81Looper%E3%80%81Message%E3%80%81MessageQueue%E5%88%86%E6%9E%90) -##Looper(先分析这个是因为能够引出四者的关系) +## Looper(先分析这个是因为能够引出四者的关系) 在Looper中,维持一个`Thread`对象以及`MessageQueue`,通过Looper的构造函数我们可以知道: ``` private Looper(boolean quitAllowed) { @@ -16,7 +16,7 @@ 1. `looper.loop()` 2. `looper.prepare()` -###looper.loop()(在当前线程启动一个Message loop机制,此段代码将直接分析出Looper、Handler、Message、MessageQueue的关系) +### looper.loop()(在当前线程启动一个Message loop机制,此段代码将直接分析出Looper、Handler、Message、MessageQueue的关系) ``` public static void loop() { final Looper me = myLooper();//获得当前线程绑定的Looper @@ -82,7 +82,7 @@ 4. `Looper`:负责分发食物的人 -###looper.prepare()(在当前线程关联一个Looper对象) +### looper.prepare()(在当前线程关联一个Looper对象) ``` private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { @@ -97,7 +97,7 @@ 2. 如果没有的话,那么就设置一个新的`Looper`到当前线程。 -------------- -##Handler +## Handler 由于我们使用Handler的通常性的第一步是: ``` Handler handler = new Handler(){ @@ -134,7 +134,7 @@ public Handler(Callback callback, boolean async) { 1. `Looper.loop()`死循环中的`msg.target`是什么时候被赋值的? 2. `handler.handleMessage(msg)`在什么时候被回调的? -###A1:`Looper.loop()`死循环中的`msg.target`是什么时候被赋值的? +### A1:`Looper.loop()`死循环中的`msg.target`是什么时候被赋值的? 要分析这个问题,很自然的我们想到从发送消息开始,无论是`handler.sendMessage(msg)`还是`handler.sendEmptyMessage(what)`,我们最终都可以追溯到以下方法 ``` public boolean sendMessageAtTime(Message msg, long uptimeMillis) { @@ -166,7 +166,7 @@ private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMilli ``` -###A2:`handler.handleMessage(msg)`在什么时候被回调的? +### A2:`handler.handleMessage(msg)`在什么时候被回调的? 通过以上的分析,我们很明确的知道`Message`中的`target`是在什么时候被赋值的了,我们先来分析在`Looper.loop()`中出现过的过的`dispatchMessage(msg)`方法 ``` @@ -191,7 +191,7 @@ public void dispatchMessage(Message msg) { ------------------ 通过以上的分析,我们可以很清晰的知道Handler、Looper、Message、MessageQueue这四者的关系以及如何合作的了。 -#总结: +# 总结: 当我们调用`handler.sendMessage(msg)`方法发送一个`Message`时,实际上这个`Message`是发送到**与当前线程绑定**的一个`MessageQueue`中,然后**与当前线程绑定**的`Looper`将会不断的从`MessageQueue`中取出新的`Message`,调用`msg.target.dispathMessage(msg)`方法将消息分发到与`Message`绑定的`handler.handleMessage()`方法中。 一个`Thread`对应多个`Handler` diff --git "a/Part1/Android/\350\207\252\345\256\232\344\271\211\346\216\247\344\273\266.md" "b/Part1/Android/\350\207\252\345\256\232\344\271\211\346\216\247\344\273\266.md" index cf77edf..6a02098 100644 --- "a/Part1/Android/\350\207\252\345\256\232\344\271\211\346\216\247\344\273\266.md" +++ "b/Part1/Android/\350\207\252\345\256\232\344\271\211\346\216\247\344\273\266.md" @@ -1,4 +1,4 @@ -#自定义控件 +# 自定义控件 --- 自定义View的步骤: diff --git "a/Part1/DesignPattern/Builder\346\250\241\345\274\217.md" "b/Part1/DesignPattern/Builder\346\250\241\345\274\217.md" index dfc6d1d..0e59805 100644 --- "a/Part1/DesignPattern/Builder\346\250\241\345\274\217.md" +++ "b/Part1/DesignPattern/Builder\346\250\241\345\274\217.md" @@ -1,21 +1,21 @@ -#Builder模式 +# Builder模式 --- -##模式介绍 +## 模式介绍 --- -###模式的定义 +### 模式的定义 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 -###模式的使用场景 +### 模式的使用场景 1. 相同的方法,不同的执行顺序,产生不同的事件结果时; 2. 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时; 3. 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适; -###Android源码中的模式实现 +### Android源码中的模式实现 在Android源码中,我们最常用到的Builder模式就是AlertDialog.Builder, 使用该Builder来构建复杂的AlertDialog对象。简单示例如下 : @@ -48,16 +48,16 @@ } ``` -##优点与缺点 +## 优点与缺点 --- -###优点 +### 优点 * 良好的封装性, 使用建造者模式可以使客户端不必知道产品内部组成的细节; * 建造者独立,容易扩展; * 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。 -###缺点 +### 缺点 * 会产生多余的Builder对象以及Director对象,消耗内存; * 对象的构建过程暴露。 \ No newline at end of file diff --git "a/Part1/DesignPattern/\344\273\243\347\220\206\346\250\241\345\274\217.md" "b/Part1/DesignPattern/\344\273\243\347\220\206\346\250\241\345\274\217.md" index 82d91fc..ed727fa 100644 --- "a/Part1/DesignPattern/\344\273\243\347\220\206\346\250\241\345\274\217.md" +++ "b/Part1/DesignPattern/\344\273\243\347\220\206\346\250\241\345\274\217.md" @@ -1,21 +1,21 @@ -#代理模式 +# 代理模式 --- -##模式介绍 +## 模式介绍 代理模式是对象的结构模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。 -##模式的使用场景 +## 模式的使用场景 就是一个人或者机构代表另一个人或者机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 -##角色介绍 +## 角色介绍 * 抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。 * 目标对象角色:定义了代理对象所代表的目标对象。 * 代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。 -##优点与缺点 +## 优点与缺点 --- 优点 diff --git "a/Part1/DesignPattern/\345\215\225\344\276\213\346\250\241\345\274\217.md" "b/Part1/DesignPattern/\345\215\225\344\276\213\346\250\241\345\274\217.md" index 23f759d..9103a92 100644 --- "a/Part1/DesignPattern/\345\215\225\344\276\213\346\250\241\345\274\217.md" +++ "b/Part1/DesignPattern/\345\215\225\344\276\213\346\250\241\345\274\217.md" @@ -1,7 +1,7 @@ -#单例模式 +# 单例模式 --- -###定义 +### 定义 >保证一个类仅有一个实例,并提供一个访问它的全局访问点。 >Singleton:负责创建Singleton类自己的唯一实例,并提供一个getInstance的方法,让外部来访问这个类的唯一实例。 @@ -16,15 +16,15 @@ private static Singleton uniqueInstance = null; ``` -###功能 +### 功能 单例模式是用来保证这个类在运行期间只会被创建一个类实例,另外,单例模式还提供了一个全局唯一访问这个类实例的访问点,就是getInstance方法。 -###范围 +### 范围 Java里面实现的单例是一个虚拟机的范围。因为装载类的功能是虚拟机的,所以一个虚拟机在通过自己的ClassLoader装载饿汉式实现单例类的时候就会创建一个类的实例。 懒汉式单例有延迟加载和缓存的思想 -###优缺点 +### 优缺点 * 懒汉式是典型的时间换空间 * 饿汉式是典型的空间换时间 @@ -82,7 +82,7 @@ public class Singleton { ``` -###一种更好的单例实现方式 +### 一种更好的单例实现方式 ``` public class Singleton { @@ -142,9 +142,9 @@ public class Singleton { ``` --- -###本质 +### 本质 控制实例数量 -###何时选用单例模式 +### 何时选用单例模式 当需要控制一个类的实例只能有一个,而且客户只能从一个全局访问点访问它时,可以选用单例模式,这些功能恰好是单例模式要解决的问题。 diff --git "a/Part1/DesignPattern/\345\216\237\345\236\213\346\250\241\345\274\217.md" "b/Part1/DesignPattern/\345\216\237\345\236\213\346\250\241\345\274\217.md" index 3c60825..1500ef3 100644 --- "a/Part1/DesignPattern/\345\216\237\345\236\213\346\250\241\345\274\217.md" +++ "b/Part1/DesignPattern/\345\216\237\345\236\213\346\250\241\345\274\217.md" @@ -1,9 +1,9 @@ -#原型模式 +# 原型模式 --- -##模式介绍 +## 模式介绍 -###模式的定义 +### 模式的定义 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。 @@ -13,7 +13,7 @@ 2. 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式; 3. 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。 -##Android源码中的模式实现 +## Android源码中的模式实现 Intent中使用了原型模式 @@ -26,11 +26,11 @@ Uri uri = Uri.parse("smsto:0800000123"); startActivity(intent); ``` -##优点与缺点 +## 优点与缺点 -###优点 +### 优点 原型模式是在内存二进制流的拷贝,要比直接 new 一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。 -###缺点 +### 缺点 这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的,在实际开发当中应该注意这个潜在的问题。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。 \ No newline at end of file diff --git "a/Part1/DesignPattern/\345\244\226\350\247\202\346\250\241\345\274\217.md" "b/Part1/DesignPattern/\345\244\226\350\247\202\346\250\241\345\274\217.md" index 609bb31..c77ee12 100644 --- "a/Part1/DesignPattern/\345\244\226\350\247\202\346\250\241\345\274\217.md" +++ "b/Part1/DesignPattern/\345\244\226\350\247\202\346\250\241\345\274\217.md" @@ -1,14 +1,14 @@ -#外观模式 +# 外观模式 --- -###定义 +### 定义 为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 -###外观模式的目的 +### 外观模式的目的 不是给子系统添加新的功能接口,而是为了让外部减少与子系统内多个模块的交互,松散耦合,从而让外部能够更简单的使用子系统。 -###优缺点 +### 优缺点 1. 优点 * 松散耦合 * 简单易用 @@ -16,10 +16,10 @@ 2. 缺点 * 过多的或者是不太合理的Facade也容易让人迷惑。到底是调用Facade好还是直接调用模块好。 -###本质 +### 本质 封装交互,简化调用 -###何时选用外观模式 +### 何时选用外观模式 * 如果你希望为复杂的子系统提供一个简单接口的时候,可以考虑使用外观模式。使用外观对象对实现大部分客户需要的功能,从而简化客户的使用。 * 如果想要让客户程序和抽象类的实现部分松散耦合,可以考虑使用外观模式,使用外观对象来将这个子系统与它的客户分离开来,从而提高子系统的独立性和可移植性。 * 如果构建多层结构的系统,可以考虑使用外观模式,使用外观对象作为每层的入口,这样就可以简化层间调用,也可以松散层次之间的依赖关系。 diff --git "a/Part1/DesignPattern/\345\270\270\350\247\201\347\232\204\351\235\242\345\220\221\345\257\271\350\261\241\350\256\276\350\256\241\345\216\237\345\210\231.md" "b/Part1/DesignPattern/\345\270\270\350\247\201\347\232\204\351\235\242\345\220\221\345\257\271\350\261\241\350\256\276\350\256\241\345\216\237\345\210\231.md" index 07652ce..661d018 100644 --- "a/Part1/DesignPattern/\345\270\270\350\247\201\347\232\204\351\235\242\345\220\221\345\257\271\350\261\241\350\256\276\350\256\241\345\216\237\345\210\231.md" +++ "b/Part1/DesignPattern/\345\270\270\350\247\201\347\232\204\351\235\242\345\220\221\345\257\271\350\261\241\350\256\276\350\256\241\345\216\237\345\210\231.md" @@ -1,4 +1,4 @@ -#常见的面向对象设计原则 +# 常见的面向对象设计原则 1. 单一职责原则 SRP 一个类应该仅有一个引起它变化的原因。 diff --git "a/Part1/DesignPattern/\347\255\226\347\225\245\346\250\241\345\274\217.md" "b/Part1/DesignPattern/\347\255\226\347\225\245\346\250\241\345\274\217.md" index 0b90e15..23d0d46 100644 --- "a/Part1/DesignPattern/\347\255\226\347\225\245\346\250\241\345\274\217.md" +++ "b/Part1/DesignPattern/\347\255\226\347\225\245\346\250\241\345\274\217.md" @@ -1,33 +1,33 @@ -#策略模式 +# 策略模式 --- -##模式的定义 +## 模式的定义 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。 注:针对同一类型操作,将复杂多样的处理方式分别开来,有选择的实现各自特有的操作。 -##模式的使用场景 +## 模式的使用场景 * 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时。 * 需要安全的封装多种同一类型的操作时。 * 出现同一抽象多个子类,而又需要使用if-else 或者 switch-case来选择时。 -##Android源码中的模式实现 +## Android源码中的模式实现 策略模式主要用来分离算法,根据相同的行为抽象来做不同的具体策略实现。 -##优缺点 +## 优缺点 -###优点: +### 优点: * 结构清晰明了、使用简单直观。 * 耦合度相对而言较低,扩展方便。 * 操作封装也更为彻底,数据更为安全。 -###缺点: +### 缺点: * 随着策略的增加,子类也会变得繁多。 \ No newline at end of file diff --git "a/Part1/DesignPattern/\347\256\200\345\215\225\345\267\245\345\216\202.md" "b/Part1/DesignPattern/\347\256\200\345\215\225\345\267\245\345\216\202.md" index f3c1e95..1cb9309 100644 --- "a/Part1/DesignPattern/\347\256\200\345\215\225\345\267\245\345\216\202.md" +++ "b/Part1/DesignPattern/\347\256\200\345\215\225\345\267\245\345\216\202.md" @@ -1,26 +1,26 @@ -#简单工厂 +# 简单工厂 --- -###接口 +### 接口 接口是一种特殊的抽象类,跟一般的抽象类相比,接口里的所有方法都是抽象方法,接口里的所有属性都是常量。也就是说接口里面只有方法定义没有任何方法实现。 接口的思想是"封装隔离" -###简单工厂 +### 简单工厂 示例代码: -[https://github.com/GeniusVJR/DesignMode_Java/tree/master/SimpleFactory](https://github.com/GeniusVJR/DesignMode_Java/tree/master/SimpleFactory) +[https://github.com/HuYingBao/DesignMode_Java/tree/master/SimpleFactory](https://github.com/HuYingBao/DesignMode_Java/tree/master/SimpleFactory) 客户端在调用的时候,不但知道了接口,同时还知道了具体的实现。接口的思想是"封装隔离",而实现类Impl应该是被接口Api封装并同客户端隔离开来的,客户端不应该知道具体的实现类是Impl。 -###简单工厂的功能 +### 简单工厂的功能 不仅可以利用简单工厂来创建接口,也可以用简单工厂来创造抽象类,甚至是一个具体的实例。 -###静态工厂 +### 静态工厂 没有创建工厂实例的必要,把简单工厂实现成一个工具类,直接使用静态方法。 -###万能工厂 +### 万能工厂 一个简单哪工厂可以包含很多用来构造东西的方法,这些方法可以创建不同的接口、抽象类或者是类实例。 -###简单工厂的优缺点 +### 简单工厂的优缺点 1. 优点 * 帮助封装 * 解耦 @@ -28,7 +28,7 @@ * 可能增加客户端的复杂度 * 不方便扩展子工厂 -##思考 +## 思考 简单工厂的本质是选择实现。 diff --git "a/Part1/DesignPattern/\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217.md" "b/Part1/DesignPattern/\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217.md" index d341c56..e7aa615 100644 --- "a/Part1/DesignPattern/\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217.md" +++ "b/Part1/DesignPattern/\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217.md" @@ -1,4 +1,4 @@ -#观察者模式 +# 观察者模式 --- 首先在Android中,我们往ListView添加数据后,都会调用Adapter的notifyDataChanged()方法,其中使用了观察者模式。 diff --git "a/Part1/DesignPattern/\350\264\243\344\273\273\351\223\276\346\250\241\345\274\217.md" "b/Part1/DesignPattern/\350\264\243\344\273\273\351\223\276\346\250\241\345\274\217.md" index ee4a0b9..5a9e0b5 100644 --- "a/Part1/DesignPattern/\350\264\243\344\273\273\351\223\276\346\250\241\345\274\217.md" +++ "b/Part1/DesignPattern/\350\264\243\344\273\273\351\223\276\346\250\241\345\274\217.md" @@ -1,12 +1,12 @@ -#责任链模式 +# 责任链模式 --- -##模式介绍 +## 模式介绍 -###模式的定义 +### 模式的定义 一个请求沿着一条“链”传递,直到该“链”上的某个处理者处理它为止。 -###模式的使用场景 +### 模式的使用场景 一个请求可以被多个处理者处理或处理者未明确指定时。 \ No newline at end of file diff --git "a/Part1/DesignPattern/\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217.md" "b/Part1/DesignPattern/\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217.md" index c0250be..0c39c56 100644 --- "a/Part1/DesignPattern/\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217.md" +++ "b/Part1/DesignPattern/\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217.md" @@ -1,4 +1,4 @@ -#适配器模式 +# 适配器模式 --- 定义: >将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 diff --git a/Part2/JVM/JVM.md b/Part2/JVM/JVM.md index 430cb5b..23aac93 100644 --- a/Part2/JVM/JVM.md +++ b/Part2/JVM/JVM.md @@ -1,4 +1,4 @@ -#JVM +# JVM --- **内存模型以及分区,需要详细到每个区放什么。** diff --git "a/Part2/JVM/JVM\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" "b/Part2/JVM/JVM\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" index fe2dab4..30cd377 100644 --- "a/Part2/JVM/JVM\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" +++ "b/Part2/JVM/JVM\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" @@ -1,22 +1,22 @@ -#虚拟机类加载机制 +# 虚拟机类加载机制 --- **虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被Java虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。** 类从被加载到虚拟内存中开始,到卸载内存为止,它的整个生命周期包括了:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)七个阶段。其中,验证,准备和解析三个部分统称为连接(Linking)。 -###类加载的过程 +### 类加载的过程 类加载的全过程,加载,验证,准备,解析和初始化这五个阶段。 --- -####加载 +#### 加载 在加载阶段,虚拟机需要完成以下三件事情: * 通过一个类的全限定名来获取定义此类的二进制字节流 * 将这个字节流所代表的静态存储结构转换为方法区的运行时数据结构 * 在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口 -####验证 +#### 验证 这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。不同的虚拟机对类验证的实现可能有所不同,但大致上都会完成下面四个阶段的检验过程:文件格式验证、元数据验证、字节码验证和符号引用验证。 **文件格式验证** @@ -35,10 +35,10 @@ 最后一个阶段的校验发生在虚拟机将符号引用直接转化为直接引用的时候,这个转化动作将在连接的第三个阶段-解析阶段产生。符号引用验证可以看作是对类自身以外(常量池中的各种符号引用)的信息进行匹配性的校验。 -####准备 +#### 准备 准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区进行分配。 -####解析 +#### 解析 解析阶段是虚拟机将常量池的符号引用转换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、接口方法四类符号引用进行。 * 类或接口的解析 @@ -46,15 +46,15 @@ * 类方法解析 * 接口方法解析 -####初始化 +#### 初始化 前面的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由Java虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码(或者说是字节码)。在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则是根据程序员通过程序制定的主观计划去初始化类变量和其他资源,或者说初始化阶段是执行类构造器()方法的过程。 -###类加载器 +### 类加载器 --- -####类与类加载器 +#### 类与类加载器 虚拟机设计团队把类加载阶段中的"通过一个类的全限定名来获取描述此类的二进制字节流"这个动作放到Java虚拟机外部去实现,以便让程序自己决定如何去获取所需的类。实现这个动作的代码模块被称为"类加载器"。 -####双亲委派模型 +#### 双亲委派模型 站在Java虚拟机的角度讲,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类加载器使用C++语言实现,是虚拟机自身的一部分;另外一种就是所有其他的类加载器,这些类加载器都由Java语言实现,独立于虚拟机外部,并且全部继承自抽象类java.lang.ClassLoader。从Java开发人员的角度来看,类加载器还可以分得更细致一些,绝大部分Java程序都会使用到以下三种系统提供的类加载器: * 启动类加载器 diff --git "a/Part2/JVM/Java\345\206\205\345\255\230\345\214\272\345\237\237\344\270\216\345\206\205\345\255\230\346\272\242\345\207\272.md" "b/Part2/JVM/Java\345\206\205\345\255\230\345\214\272\345\237\237\344\270\216\345\206\205\345\255\230\346\272\242\345\207\272.md" index f69e747..247f154 100644 --- "a/Part2/JVM/Java\345\206\205\345\255\230\345\214\272\345\237\237\344\270\216\345\206\205\345\255\230\346\272\242\345\207\272.md" +++ "b/Part2/JVM/Java\345\206\205\345\255\230\345\214\272\345\237\237\344\270\216\345\206\205\345\255\230\346\272\242\345\207\272.md" @@ -1,4 +1,4 @@ -##内存区域 +## 内存区域 Java虚拟机在执行Java程序的过程中会把他所管理的内存划分为若干个不同的数据区域。Java虚拟机规范将JVM所管理的内存分为以下几个运行时数据区:程序计数器,Java虚拟机栈,本地方法栈,Java堆,方法区。下面详细阐述各数据区所存储的数据类型。 diff --git "a/Part2/JVM/\345\236\203\345\234\276\345\233\236\346\224\266\347\256\227\346\263\225.md" "b/Part2/JVM/\345\236\203\345\234\276\345\233\236\346\224\266\347\256\227\346\263\225.md" index 4488977..e9114cb 100644 --- "a/Part2/JVM/\345\236\203\345\234\276\345\233\236\346\224\266\347\256\227\346\263\225.md" +++ "b/Part2/JVM/\345\236\203\345\234\276\345\233\236\346\224\266\347\256\227\346\263\225.md" @@ -1,4 +1,4 @@ -#垃圾回收算法 +# 垃圾回收算法 --- 1. 引用计数法:缺点是无法处理循环引用问题 diff --git "a/Part2/JavaConcurrent/Java\345\271\266\345\217\221\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/Part2/JavaConcurrent/Java\345\271\266\345\217\221\345\237\272\347\241\200\347\237\245\350\257\206.md" index 038c898..047a62a 100644 --- "a/Part2/JavaConcurrent/Java\345\271\266\345\217\221\345\237\272\347\241\200\347\237\245\350\257\206.md" +++ "b/Part2/JavaConcurrent/Java\345\271\266\345\217\221\345\237\272\347\241\200\347\237\245\350\257\206.md" @@ -1,4 +1,5 @@ -#Java并发 +# Java并发 + --- (Executor框架和多线程基础) @@ -80,7 +81,7 @@ sleep()方法是线程类(Thread)的静态方法,导致此线程暂停执 -###3、IO(IO,NIO,目前okio已经被集成Android包) +### 3、IO(IO,NIO,目前okio已经被集成Android包) **IO框架主要用到什么设计模式** diff --git a/Part2/JavaConcurrent/NIO.md b/Part2/JavaConcurrent/NIO.md index 15fd500..67197d6 100644 --- a/Part2/JavaConcurrent/NIO.md +++ b/Part2/JavaConcurrent/NIO.md @@ -1,18 +1,18 @@ -#NIO +# NIO --- Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java1.4开始),Java NIO提供了与标准IO不同的IO工作方式。 -###Java NIO: Channels and Buffers(通道和缓冲区) +### Java NIO: Channels and Buffers(通道和缓冲区) 标准的俄IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入通道也类似。 -###Java NIO: Non-blocking IO(非阻塞IO) +### Java NIO: Non-blocking IO(非阻塞IO) Java NIO可以让你非阻塞的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。 -###Java NIO: Selectors(选择器) +### Java NIO: Selectors(选择器) Java NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。 @@ -64,7 +64,7 @@ Selector允许单线程处理多个Channel。如果你的应用打开了多个 要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接送等。 -##Channel +## Channel --- Java NIO的通道类似流,但又有些不同: @@ -107,7 +107,7 @@ aFile.close(); 注意 buf.flip() 的调用,首先读取数据到Buffer,然后反转Buffer,接着再从Buffer中读取数据。 -##Buffer +## Buffer Java NIO中的Buffer用于和NIO通道进行交互。如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的。 diff --git a/Part2/JavaConcurrent/Synchronized.md b/Part2/JavaConcurrent/Synchronized.md index d8ba637..f472ff8 100644 --- a/Part2/JavaConcurrent/Synchronized.md +++ b/Part2/JavaConcurrent/Synchronized.md @@ -1,4 +1,4 @@ -#synchronized +# synchronized --- 在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访问对象并要求操作相同资源时,分割了原子操作就有可能出现数据的不一致或数据不完整的情况,为避免这种情况的发生,我们会采取同步机制,以确保在某一时刻,方法内只允许有一个线程。 @@ -16,7 +16,7 @@ 7. 类级别锁被特定类的所有示例共享,它用于控制对static成员变量以及static方法的并发访问。具体用法与对象级别锁相似。 8. 互斥是实现同步的一种手段,临界区、互斥量和信号量都是主要的互斥实现方式。synchronized关键字经过编译后,会在同步块的前后分别形成monitorenter和monitorexit这两个字节码指令。根据虚拟机规范的要求,在执行monitorenter指令时,首先要尝试获取对象的锁,如果获得了锁,把锁的计数器加1,相应地,在执行monitorexit指令时会将锁计数器减1,当计数器为0时,锁便被释放了。由于synchronized同步块对同一个线程是可重入的,因此一个线程可以多次获得同一个对象的互斥锁,同样,要释放相应次数的该互斥锁,才能最终释放掉该锁。 -##内存可见性 +## 内存可见性 加锁(synchronized同步)的功能不仅仅局限于互斥行为,同时还存在另外一个重要的方面:内存可见性。我们不仅希望防止某个线程正在使用对象状态而另一个线程在同时修改该状态,而且还希望确保当一个线程修改了对象状态后,其他线程能够看到该变化。而线程的同步恰恰也能够实现这一点。 diff --git "a/Part2/JavaConcurrent/Thread\345\222\214Runnable\345\256\236\347\216\260\345\244\232\347\272\277\347\250\213\347\232\204\345\214\272\345\210\253.md" "b/Part2/JavaConcurrent/Thread\345\222\214Runnable\345\256\236\347\216\260\345\244\232\347\272\277\347\250\213\347\232\204\345\214\272\345\210\253.md" index 64992ef..5ed6954 100644 --- "a/Part2/JavaConcurrent/Thread\345\222\214Runnable\345\256\236\347\216\260\345\244\232\347\272\277\347\250\213\347\232\204\345\214\272\345\210\253.md" +++ "b/Part2/JavaConcurrent/Thread\345\222\214Runnable\345\256\236\347\216\260\345\244\232\347\272\277\347\250\213\347\232\204\345\214\272\345\210\253.md" @@ -1,4 +1,4 @@ -#Thread和Runnable实现多线程的区别 +# Thread和Runnable实现多线程的区别 --- Java中实现多线程有两种方法:继承Thread、实现Runnable接口,在程序开发中只要是多线程,肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下优势: diff --git "a/Part2/JavaConcurrent/thread\344\270\216runable\345\246\202\344\275\225\345\256\236\347\216\260\345\244\232\347\272\277\347\250\213.md" "b/Part2/JavaConcurrent/thread\344\270\216runable\345\246\202\344\275\225\345\256\236\347\216\260\345\244\232\347\272\277\347\250\213.md" index 64a37bd..35e3794 100755 --- "a/Part2/JavaConcurrent/thread\344\270\216runable\345\246\202\344\275\225\345\256\236\347\216\260\345\244\232\347\272\277\347\250\213.md" +++ "b/Part2/JavaConcurrent/thread\344\270\216runable\345\246\202\344\275\225\345\256\236\347\216\260\345\244\232\347\272\277\347\250\213.md" @@ -1,4 +1,4 @@ -##Thread与Runable如何实现多线程? +## Thread与Runable如何实现多线程? Java实现多线程有两种途径:继承Thread类或者实现Runnable接口。Runnable是接口 diff --git "a/Part2/JavaConcurrent/volatile\345\217\230\351\207\217\344\277\256\351\245\260\347\254\246.md" "b/Part2/JavaConcurrent/volatile\345\217\230\351\207\217\344\277\256\351\245\260\347\254\246.md" index 6ce4f45..b9c4602 100644 --- "a/Part2/JavaConcurrent/volatile\345\217\230\351\207\217\344\277\256\351\245\260\347\254\246.md" +++ "b/Part2/JavaConcurrent/volatile\345\217\230\351\207\217\344\277\256\351\245\260\347\254\246.md" @@ -1,7 +1,7 @@ -#volatile变量修饰符 +# volatile变量修饰符 --- -##volatile用处说明 +## volatile用处说明 在JDK1.2之前,Java的类型模型实现总是从主存(即共享内存)读取变量,是不需要进行特别的注意的。而随着JVM的成熟和优化,现在在多线程环境下volatile关键字的使用变的非常重要。 diff --git "a/Part2/JavaConcurrent/\344\275\277\347\224\250wait notify notifyall\345\256\236\347\216\260\347\272\277\347\250\213\351\227\264\351\200\232\344\277\241.md" "b/Part2/JavaConcurrent/\344\275\277\347\224\250wait notify notifyall\345\256\236\347\216\260\347\272\277\347\250\213\351\227\264\351\200\232\344\277\241.md" index bd8f92a..380cb30 100644 --- "a/Part2/JavaConcurrent/\344\275\277\347\224\250wait notify notifyall\345\256\236\347\216\260\347\272\277\347\250\213\351\227\264\351\200\232\344\277\241.md" +++ "b/Part2/JavaConcurrent/\344\275\277\347\224\250wait notify notifyall\345\256\236\347\216\260\347\272\277\347\250\213\351\227\264\351\200\232\344\277\241.md" @@ -1,4 +1,4 @@ -#使用wait/notify/notifyAll实现线程间通信 +# 使用wait/notify/notifyAll实现线程间通信 --- 在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用wait()方法,将阻塞等待其他线程的通知(其他线程调用notify()方法或notifyAll()方法),在线程中调用notify()方法或notifyAll()方法,将通知其他线程从wait()方法处返回。 diff --git "a/Part2/JavaConcurrent/\345\217\257\351\207\215\345\205\245\345\206\205\347\275\256\351\224\201.md" "b/Part2/JavaConcurrent/\345\217\257\351\207\215\345\205\245\345\206\205\347\275\256\351\224\201.md" index 14f1997..723185d 100644 --- "a/Part2/JavaConcurrent/\345\217\257\351\207\215\345\205\245\345\206\205\347\275\256\351\224\201.md" +++ "b/Part2/JavaConcurrent/\345\217\257\351\207\215\345\205\245\345\206\205\347\275\256\351\224\201.md" @@ -1,4 +1,4 @@ -#可重入内置锁 +# 可重入内置锁 --- 每个Java对象都可以用做一个实现同步的锁,这些锁被称为内置锁或监视器锁。线程在进入同步代码块之前会自动获取锁,并且在退出同步代码块时会自动释放锁。获得内置锁的唯一途径就是进入由这个锁保护的同步代码块或方法。 diff --git "a/Part2/JavaConcurrent/\345\244\232\347\272\277\347\250\213\347\216\257\345\242\203\344\270\255\345\256\211\345\205\250\344\275\277\347\224\250\351\233\206\345\220\210API.md" "b/Part2/JavaConcurrent/\345\244\232\347\272\277\347\250\213\347\216\257\345\242\203\344\270\255\345\256\211\345\205\250\344\275\277\347\224\250\351\233\206\345\220\210API.md" index 3b0a6f8..26097b6 100644 --- "a/Part2/JavaConcurrent/\345\244\232\347\272\277\347\250\213\347\216\257\345\242\203\344\270\255\345\256\211\345\205\250\344\275\277\347\224\250\351\233\206\345\220\210API.md" +++ "b/Part2/JavaConcurrent/\345\244\232\347\272\277\347\250\213\347\216\257\345\242\203\344\270\255\345\256\211\345\205\250\344\275\277\347\224\250\351\233\206\345\220\210API.md" @@ -1,4 +1,4 @@ -#多线程环境中安全使用集合API +# 多线程环境中安全使用集合API --- 在集合API中,最初设计的Vector和Hashtable是多线程安全的。例如:对于Vector来说,用来添加和删除元素的方法是同步的。如果只有一个线程与Vector的实例交互,那么,要求获取和释放对象锁便是一种浪费,另外在不必要的时候如果滥用同步化,也有可能会带来死锁。因此,对于更改集合内容的方法,没有一个是同步化的。集合本质上是非多线程安全的,当多个线程与集合交互时,为了使它多线程安全,必须采取额外的措施。 diff --git "a/Part2/JavaConcurrent/\345\256\210\346\212\244\347\272\277\347\250\213\344\270\216\351\230\273\345\241\236\347\272\277\347\250\213.md" "b/Part2/JavaConcurrent/\345\256\210\346\212\244\347\272\277\347\250\213\344\270\216\351\230\273\345\241\236\347\272\277\347\250\213.md" index 445ae60..dc0b832 100644 --- "a/Part2/JavaConcurrent/\345\256\210\346\212\244\347\272\277\347\250\213\344\270\216\351\230\273\345\241\236\347\272\277\347\250\213.md" +++ "b/Part2/JavaConcurrent/\345\256\210\346\212\244\347\272\277\347\250\213\344\270\216\351\230\273\345\241\236\347\272\277\347\250\213.md" @@ -1,4 +1,4 @@ -#守护线程与阻塞线程的四种情况 +# 守护线程与阻塞线程的四种情况 --- Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程) @@ -16,7 +16,7 @@ Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程) 3. 不要认为所有的应用都可以分配给守护线程来进行服务,比如读写操作或者计算逻辑。 -##线程阻塞 +## 线程阻塞 线程可以阻塞于四种状态: diff --git "a/Part2/JavaConcurrent/\345\256\236\347\216\260\345\206\205\345\255\230\345\217\257\350\247\201\347\232\204\344\270\244\347\247\215\346\226\271\346\263\225\346\257\224\350\276\203\357\274\232\345\212\240\351\224\201\345\222\214volatile\345\217\230\351\207\217.md" "b/Part2/JavaConcurrent/\345\256\236\347\216\260\345\206\205\345\255\230\345\217\257\350\247\201\347\232\204\344\270\244\347\247\215\346\226\271\346\263\225\346\257\224\350\276\203\357\274\232\345\212\240\351\224\201\345\222\214volatile\345\217\230\351\207\217.md" index a5e284c..11f9ea2 100644 --- "a/Part2/JavaConcurrent/\345\256\236\347\216\260\345\206\205\345\255\230\345\217\257\350\247\201\347\232\204\344\270\244\347\247\215\346\226\271\346\263\225\346\257\224\350\276\203\357\274\232\345\212\240\351\224\201\345\222\214volatile\345\217\230\351\207\217.md" +++ "b/Part2/JavaConcurrent/\345\256\236\347\216\260\345\206\205\345\255\230\345\217\257\350\247\201\347\232\204\344\270\244\347\247\215\346\226\271\346\263\225\346\257\224\350\276\203\357\274\232\345\212\240\351\224\201\345\222\214volatile\345\217\230\351\207\217.md" @@ -1,4 +1,4 @@ -#并发编程中实现内存可见的两种方法比较:加锁和volatile变量 +# 并发编程中实现内存可见的两种方法比较:加锁和volatile变量 --- 1. volatile变量是一种稍弱的同步机制在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比synchronized关键字更轻量级的同步机制。 diff --git "a/Part2/JavaConcurrent/\346\255\273\351\224\201.md" "b/Part2/JavaConcurrent/\346\255\273\351\224\201.md" index e50fe74..41fc833 100644 --- "a/Part2/JavaConcurrent/\346\255\273\351\224\201.md" +++ "b/Part2/JavaConcurrent/\346\255\273\351\224\201.md" @@ -1,4 +1,4 @@ -#死锁 +# 死锁 --- 当线程需要同时持有多个锁时,有可能产生死锁。考虑如下情形: diff --git "a/Part2/JavaConcurrent/\347\224\237\344\272\247\350\200\205\345\222\214\346\266\210\350\264\271\350\200\205\351\227\256\351\242\230.md" "b/Part2/JavaConcurrent/\347\224\237\344\272\247\350\200\205\345\222\214\346\266\210\350\264\271\350\200\205\351\227\256\351\242\230.md" index d3e0b1d..512cdb5 100755 --- "a/Part2/JavaConcurrent/\347\224\237\344\272\247\350\200\205\345\222\214\346\266\210\350\264\271\350\200\205\351\227\256\351\242\230.md" +++ "b/Part2/JavaConcurrent/\347\224\237\344\272\247\350\200\205\345\222\214\346\266\210\350\264\271\350\200\205\351\227\256\351\242\230.md" @@ -1,4 +1,4 @@ -#生产者和消费者问题 +# 生产者和消费者问题 ``` diff --git "a/Part2/JavaConcurrent/\347\272\277\347\250\213\344\270\255\346\226\255.md" "b/Part2/JavaConcurrent/\347\272\277\347\250\213\344\270\255\346\226\255.md" index bc4dc4f..f2904f6 100644 --- "a/Part2/JavaConcurrent/\347\272\277\347\250\213\344\270\255\346\226\255.md" +++ "b/Part2/JavaConcurrent/\347\272\277\347\250\213\344\270\255\346\226\255.md" @@ -1,7 +1,7 @@ -#线程中断 +# 线程中断 --- -##使用interrupt()中断线程 +## 使用interrupt()中断线程 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即返回。这里需要注意的是,如果只是单纯的调用interrupt()方法,线程并没有实际被中断,会继续往下执行。 @@ -62,7 +62,7 @@ in run() - interrupted while sleeping 另外,如果将catch块中的return语句注释掉,则线程在抛出异常后,会继续往下执行,而不会被中断,从而会打印出”leaving normally“信息。 -##待决中断 +## 待决中断 --- 在上面的例子中,sleep()方法的实现检查到休眠线程被中断,它会相当友好地终止线程,并抛出InterruptedException异常。另外一种情况,如果线程在调用sleep()方法前被中断,那么该中断称为待决中断,它会在刚调用sleep()方法时,立即抛出InterruptedException异常。 @@ -100,7 +100,7 @@ elapsedTime=2001 这种模式下,main线程中断它自身。除了将中断标志(它是Thread的内部标志)设置为true外,没有其他任何影响。线程被中断了,但main线程仍然运行,main线程继续监视实时时钟,并进入try块,一旦调用sleep()方法,它就会注意到待决中断的存在,并抛出InterruptException。于是执行跳转到catch块,并打印出线程被中断的信息。最后,计算并打印出时间差。 -##使用isInterrupted()方法判断中断状态 +## 使用isInterrupted()方法判断中断状态 --- 可以在Thread对象上调用isInterrupted()方法来检查任何线程的中断状态。这里需要注意:线程一旦被中断,isInterrupted()方法便会返回true,而一旦sleep()方法抛出异常,它将清空中断标志,此时isInterrupted()方法将返回false。 @@ -144,7 +144,7 @@ Point D: t.isInterrupted()=false ``` -##使用Thread.interrupted()方法判断中断状态 +## 使用Thread.interrupted()方法判断中断状态 --- 可以使用Thread.interrupted()方法来检查当前线程的中断状态(并隐式重置为false)。又由于它是静态方法,因此不能在特定的线程上使用,而只能报告调用它的线程的中断状态,如果线程被中断,而且中断状态尚不清楚,那么,这个方法返回true。与isInterrupted()不同,它将自动重置中断状态为false,第二次调用Thread.interrupted()方法,总是返回false,除非中断了线程。 @@ -181,7 +181,7 @@ Point Z: Thread.interrupted()=false 从结果中可以看出,当前线程中断自身后,在Y点,中断状态为true,并由Thread.interrupted()自动重置为false,那么下次调用该方法得到的结果便是false。 -##补充 +## 补充 --- yield和join方法的使用 diff --git "a/Part2/JavaConcurrent/\347\272\277\347\250\213\346\214\202\350\265\267\343\200\201\346\201\242\345\244\215\344\270\216\347\273\210\346\255\242\347\232\204\346\255\243\347\241\256\346\226\271\346\263\225.md" "b/Part2/JavaConcurrent/\347\272\277\347\250\213\346\214\202\350\265\267\343\200\201\346\201\242\345\244\215\344\270\216\347\273\210\346\255\242\347\232\204\346\255\243\347\241\256\346\226\271\346\263\225.md" index dba6442..0516722 100644 --- "a/Part2/JavaConcurrent/\347\272\277\347\250\213\346\214\202\350\265\267\343\200\201\346\201\242\345\244\215\344\270\216\347\273\210\346\255\242\347\232\204\346\255\243\347\241\256\346\226\271\346\263\225.md" +++ "b/Part2/JavaConcurrent/\347\272\277\347\250\213\346\214\202\350\265\267\343\200\201\346\201\242\345\244\215\344\270\216\347\273\210\346\255\242\347\232\204\346\255\243\347\241\256\346\226\271\346\263\225.md" @@ -1,7 +1,7 @@ -#线程挂起、恢复与终止的正确方法(含代码) +# 线程挂起、恢复与终止的正确方法(含代码) --- -##挂起和恢复线程 +## 挂起和恢复线程 Thread 的API中包含两个被淘汰的方法,它们用于临时挂起和重启某个线程,这些方法已经被淘汰,因为它们是不安全的,不稳定的。如果在不合适的时候挂起线程(比如,锁定共享资源时),此时便可能会发生死锁条件——其他线程在等待该线程释放锁,但该线程却被挂起了,便会发生死锁。另外,在长时间计算期间挂起线程也可能导致问题。 diff --git "a/Part2/JavaSE/ArrayList \343\200\201 LinkedList \343\200\201 Vector \347\232\204\345\272\225\345\261\202\345\256\236\347\216\260\345\222\214\345\214\272\345\210\253.md" "b/Part2/JavaSE/ArrayList \343\200\201 LinkedList \343\200\201 Vector \347\232\204\345\272\225\345\261\202\345\256\236\347\216\260\345\222\214\345\214\272\345\210\253.md" index eaf1bc7..f2a8bab 100755 --- "a/Part2/JavaSE/ArrayList \343\200\201 LinkedList \343\200\201 Vector \347\232\204\345\272\225\345\261\202\345\256\236\347\216\260\345\222\214\345\214\272\345\210\253.md" +++ "b/Part2/JavaSE/ArrayList \343\200\201 LinkedList \343\200\201 Vector \347\232\204\345\272\225\345\261\202\345\256\236\347\216\260\345\222\214\345\214\272\345\210\253.md" @@ -1,4 +1,4 @@ -#Java基础之集合List-ArrayList、LinkedList、Vector的底层实现和区别 +# Java基础之集合List-ArrayList、LinkedList、Vector的底层实现和区别 diff --git "a/Part2/JavaSE/ArrayList\346\272\220\347\240\201\345\211\226\346\236\220.md" "b/Part2/JavaSE/ArrayList\346\272\220\347\240\201\345\211\226\346\236\220.md" index 3689eab..466a1c3 100644 --- "a/Part2/JavaSE/ArrayList\346\272\220\347\240\201\345\211\226\346\236\220.md" +++ "b/Part2/JavaSE/ArrayList\346\272\220\347\240\201\345\211\226\346\236\220.md" @@ -1,4 +1,4 @@ -##ArrayList简介 +## ArrayList简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。 @@ -380,7 +380,7 @@ public class ArrayList extends AbstractList } ``` -##几点总结 +## 几点总结 关于ArrayList的源码,给出几点比较重要的总结: diff --git a/Part2/JavaSE/Arraylist.md b/Part2/JavaSE/Arraylist.md index d16d2a6..3627dc2 100755 --- a/Part2/JavaSE/Arraylist.md +++ b/Part2/JavaSE/Arraylist.md @@ -4,7 +4,7 @@ * 实现的接口:List、Collectin、Iterable、Serializable、Cloneable、RandomAccess * 子类:AttributeList、RoleList、RoleUnresolvedList -##简介 +## 简介 --- * 它是顺序表 * 大小可变 @@ -12,7 +12,7 @@ * 可LinkedList一样,不具备线程同步的安全性、但速度较快 * 第一次定义的时候没有指定数组的长度则长度是0,在第一次添加的时候判断如果是空则追加10。 -##容量是如何变化的 +## 容量是如何变化的 --- 在源码中: @@ -30,17 +30,17 @@ private transient Object[] elementData; * 之后每次添加时,会先确保容量是否够用 * 如果不够用,每次增加的容量为 newCapacity = oldCapacity + (oldCapacity >> 1);即,每次增加为原来的1.5倍。 -##和Vector的区别 +## 和Vector的区别 --- * Vector线程安全 * ArrayList线程不安全,速度快 -##和LinkedList的区别 +## 和LinkedList的区别 --- * ArrayList是顺序表,LinkedList是链表 * ArrayList查找,修改方便,LinkedList添加、删除方便 -##方法 +## 方法 --- **void ensureCapacity(int minCapacity)** 设置容量能容纳下minCapacity个元素 diff --git "a/Part2/JavaSE/Arraylist\345\222\214Hashmap\345\246\202\344\275\225\346\211\251\345\256\271\347\255\211.md" "b/Part2/JavaSE/Arraylist\345\222\214Hashmap\345\246\202\344\275\225\346\211\251\345\256\271\347\255\211.md" index 6f26b8c..7edfc7f 100755 --- "a/Part2/JavaSE/Arraylist\345\222\214Hashmap\345\246\202\344\275\225\346\211\251\345\256\271\347\255\211.md" +++ "b/Part2/JavaSE/Arraylist\345\222\214Hashmap\345\246\202\344\275\225\346\211\251\345\256\271\347\255\211.md" @@ -1,10 +1,10 @@ -#Arraylist和HashMap如何扩容? +# Arraylist和HashMap如何扩容? -#负载因子有什么作用? +# 负载因子有什么作用? -#如何保证读写进程安全? +# 如何保证读写进程安全? diff --git a/Part2/JavaSE/Collection.md b/Part2/JavaSE/Collection.md index 15c6e3d..ce7e40e 100755 --- a/Part2/JavaSE/Collection.md +++ b/Part2/JavaSE/Collection.md @@ -1,5 +1,5 @@ -####线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构。这些类均在java.util包中。本文试图通过简单的描述,向读者阐述各个类的作用以及如何正确使用这些类。 +#### 线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构。这些类均在java.util包中。本文试图通过简单的描述,向读者阐述各个类的作用以及如何正确使用这些类。 # Collection *** @@ -7,11 +7,11 @@ * 继承的接口:Iterable * 子接口:List、Set、Queue等 -##简介 +## 简介 * 一个Collection代表一组Object,即Collection的元素(Elements),一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。 * Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。 -##如何遍历Collection中的每一个元素? +## 如何遍历Collection中的每一个元素? * 不论Collection的实际类型如何,它都支持一个iterator()的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection中每一个元素,代码如下: @@ -26,9 +26,9 @@ ``` ## 方法 - -**retainAll(Collection c)**:保留,交运算 -**addAll(Collection c)**:添加,并运算 + +**retainAll(Collection c)**:保留,交运算 +**addAll(Collection c)**:添加,并运算 **removeAll(Collection c)**:移除,减运算 diff --git "a/Part2/JavaSE/HashMap\346\272\220\347\240\201\345\211\226\346\236\220.md" "b/Part2/JavaSE/HashMap\346\272\220\347\240\201\345\211\226\346\236\220.md" index b516b5e..3aac885 100644 --- "a/Part2/JavaSE/HashMap\346\272\220\347\240\201\345\211\226\346\236\220.md" +++ "b/Part2/JavaSE/HashMap\346\272\220\347\240\201\345\211\226\346\236\220.md" @@ -1,11 +1,11 @@ -###HashMap简介 +### HashMap简介 HashMap是基于哈希表实现的,每一个元素都是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阈值)时,同样会自动增长。 HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap。 HashMap实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆。 -###HashMap源码剖析 +### HashMap源码剖析 HashMap的源码如下(加入了比较详细的注释): @@ -766,7 +766,7 @@ public class HashMap } ``` -###几点总结 +### 几点总结 1、首先要清楚HashMap的存储结构,如下图所示: ![](http://img.blog.csdn.net/20140701191403764?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbnNfY29kZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) diff --git "a/Part2/JavaSE/HashTable\346\272\220\347\240\201\345\211\226\346\236\220.md" "b/Part2/JavaSE/HashTable\346\272\220\347\240\201\345\211\226\346\236\220.md" index 99adfce..809d9a0 100644 --- "a/Part2/JavaSE/HashTable\346\272\220\347\240\201\345\211\226\346\236\220.md" +++ "b/Part2/JavaSE/HashTable\346\272\220\347\240\201\345\211\226\346\236\220.md" @@ -1,4 +1,4 @@ -##Hashtable简介 +## Hashtable简介 HashTable同样是基于哈希表实现的,同样每个元素都是key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阈值)时,同样会自动增长。 @@ -6,7 +6,7 @@ Hashtable也是JDK1.0引入的类,是线程安全的,能用于多线程环 Hashtable同样实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆。 -##Hashtable源码剖析 +## Hashtable源码剖析 Hashtable的源码的很多实现都和HashMap差不多,源码如下(加入了比较详细的注释): ``` @@ -818,7 +818,7 @@ public class Hashtable } ``` -##几点总结 +## 几点总结 针对Hashtable,我们同样给出几点比较重要的总结,但要结合与HashMap的比较来总结。 1. 二者的存储结构和解决冲突的方法都是相同的。 diff --git "a/Part2/JavaSE/Hashmap\347\232\204hashcode\347\232\204\344\275\234\347\224\250\347\255\211.md" "b/Part2/JavaSE/Hashmap\347\232\204hashcode\347\232\204\344\275\234\347\224\250\347\255\211.md" index 7d753da..818a41f 100755 --- "a/Part2/JavaSE/Hashmap\347\232\204hashcode\347\232\204\344\275\234\347\224\250\347\255\211.md" +++ "b/Part2/JavaSE/Hashmap\347\232\204hashcode\347\232\204\344\275\234\347\224\250\347\255\211.md" @@ -1,16 +1,16 @@ -#HashMap的hashcode的作用? +# HashMap的hashcode的作用? 1. hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的; 2. 如果两个对象相同,就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode一定要相同; 3. 如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点; 4. 两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。 -#什么时候需要重写? +# 什么时候需要重写? 一般的地方不需要重载hashCode,只有当类需要放在HashTable、HashMap、HashSet等等hash结构的集合时才会重载hashCode,那么为什么要重载hashCode呢?就HashMap来说,好比HashMap就是一个大内存块,里面有很多小内存块,小内存块里面是一系列的对象,可以利用hashCode来查找小内存块hashCode%size(小内存块数量),所以当equal相等时,hashCode必须相等,而且如果是object对象,必须重载hashCode和equal方法。 [对于equal和hashcode的理解,何时需要重写](http://blog.csdn.net/qq352773277/article/details/41675407) -#如何解决哈希冲突? +# 如何解决哈希冲突? 1. 线性探查法(Linear Probing) 2. 线性补偿探测法 @@ -20,7 +20,7 @@ -#查找的时候流程是如何? +# 查找的时候流程是如何? 1.hashcode是用来查找的,如果你学过数据结构就应该知道,在查找和排序这一章有 例如内存中有这样的位置 diff --git "a/Part2/JavaSE/Java\344\270\255\347\232\204\345\206\205\345\255\230\346\263\204\346\274\217.md" "b/Part2/JavaSE/Java\344\270\255\347\232\204\345\206\205\345\255\230\346\263\204\346\274\217.md" index efec035..b061a80 100644 --- "a/Part2/JavaSE/Java\344\270\255\347\232\204\345\206\205\345\255\230\346\263\204\346\274\217.md" +++ "b/Part2/JavaSE/Java\344\270\255\347\232\204\345\206\205\345\255\230\346\263\204\346\274\217.md" @@ -1,4 +1,4 @@ -#Java中的内存泄漏 +# Java中的内存泄漏 --- 1.Java内存回收机制 diff --git "a/Part2/JavaSE/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/Part2/JavaSE/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" index 782ade9..2901643 100644 --- "a/Part2/JavaSE/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" +++ "b/Part2/JavaSE/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" @@ -1,7 +1,7 @@ -#J2SE +# J2SE --- -##基础 +## 基础 --- **八种基本数据类型的大小,以及他们的封装类。** @@ -195,7 +195,7 @@ Java 平台提供了两种类型的字符串:String和StringBuffer / StringBui **try catch finally,try里有return,finally还执行么?** -会执行,在方法 返回调用者前执行。Java允许在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是纪录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,这会对程序造成很大的困扰,C#中就从语法规定不能做这样的事。 +会执行,在方法 返回调用者前执行。Java允许在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是纪录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,这会对程序造成很大的困扰,C# 中就从语法规定不能做这样的事。 --- @@ -400,7 +400,7 @@ JAVA反射机制是在运行状态中, 对于任意一个类, 都能够知道这 **String类内部实现,能否改变String对象内容** -[String源码分析](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaSE/String源码分析.md) +[String源码分析](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaSE/String源码分析.md) [http://blog.csdn.net/zhangjg_blog/article/details/18319521](http://blog.csdn.net/zhangjg_blog/article/details/18319521) @@ -456,7 +456,7 @@ JAVA反射机制是在运行状态中, 对于任意一个类, 都能够知道这 --- -###集合 +### 集合 **ArrayList、LinkedList、Vector的底层实现和区别** diff --git "a/Part2/JavaSE/LinkedHashMap\346\272\220\347\240\201\345\211\226\346\236\220.md" "b/Part2/JavaSE/LinkedHashMap\346\272\220\347\240\201\345\211\226\346\236\220.md" index 94206db..be712b0 100644 --- "a/Part2/JavaSE/LinkedHashMap\346\272\220\347\240\201\345\211\226\346\236\220.md" +++ "b/Part2/JavaSE/LinkedHashMap\346\272\220\347\240\201\345\211\226\346\236\220.md" @@ -1,4 +1,4 @@ -##LinkedHashMap简介 +## LinkedHashMap简介 LinkedHashMap是HashMap的子类,与HashMap有着同样的存储结构,但它加入了一个双向链表的头结点,将所有put到LinkedHashmap的节点一一串成了一个双向循环链表,因此它保留了节点插入的顺序,可以使节点的输出顺序与输入顺序相同。 @@ -6,7 +6,7 @@ LinkedHashMap可以用来实现LRU算法(这会在下面的源码中进行分 LinkedHashMap同样是非线程安全的,只在单线程环境下使用。 -##LinkedHashMap源码剖析 +## LinkedHashMap源码剖析 LinkedHashMap源码如下(加入了详细的注释): @@ -272,7 +272,7 @@ public class LinkedHashMap } } ``` -##几点总结 +## 几点总结 关于LinkedHashMap的源码,给出以下几点比较重要的总结: diff --git "a/Part2/JavaSE/LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.md" "b/Part2/JavaSE/LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.md" index 527e1e0..b1c7973 100644 --- "a/Part2/JavaSE/LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.md" +++ "b/Part2/JavaSE/LinkedList\346\272\220\347\240\201\345\211\226\346\236\220.md" @@ -1,11 +1,11 @@ -##LinkedList简介 +## LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当作链表来操作外,它还可以当作栈,队列和双端队列来使用。 LinkedList同样是非线程安全的,只在单线程下适合使用。 LinkedList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了Cloneable接口,能被克隆。 -##LinkedList源码剖析 +## LinkedList源码剖析 LinkedList的源码如下(加入了比较详细的注释) ``` @@ -649,7 +649,7 @@ public class LinkedList } ``` -##几点总结 +## 几点总结 关于LinkedList的源码,给出几点比较重要的总结: diff --git a/Part2/JavaSE/Linkedlist.md b/Part2/JavaSE/Linkedlist.md index 5bdcdca..9069a9c 100755 --- a/Part2/JavaSE/Linkedlist.md +++ b/Part2/JavaSE/Linkedlist.md @@ -1,17 +1,17 @@ -#LinkedList +# LinkedList --- * 是一个类 * 实现的接口:List、Collection、Iterable、Serializable、Cloneable、Deque,Queue * 子类:没有子类 -##简介 +## 简介 --- * 它是链表 * 它还是队列、双端队列 * 它还可以用作堆栈 * 和ArrayList一样,不具有线程安全性 -##关于添加元素 +## 关于添加元素 --- **boolean add(E e)** 添加到链表末尾 diff --git a/Part2/JavaSE/List.md b/Part2/JavaSE/List.md index 21a88c7..9be4459 100755 --- a/Part2/JavaSE/List.md +++ b/Part2/JavaSE/List.md @@ -5,7 +5,7 @@ * 间接继承的接口:Iterable * 实现类:ArrayList、LinkedList、Vector等 -##简介 +## 简介 * List是有序的**Collection** - 可以对每个元素的插入位置进行精准控制 - 可以根据索引访问元素 @@ -13,23 +13,23 @@ * 有自己的迭代器 ListIterator * 如果元素包含自身,equals()和hashCode()不再是良定义的 -## 方法 -**boolean add(E e)**: 添加到末尾 -**void add(int index, E e)**: 添加到指定位置 - -**E set(int index, E e)**: 设置指定位置的元素,返回一个E -**get(int index)**: 获得指定位置的元素 - -**Iterator iterator()** -**ListIterator listIterator()** -**ListIterator listIterator(int index)** - -**int indexOf(E e)** -**int lastIndexOf(E e)** - +## 方法 +**boolean add(E e)**: 添加到末尾 +**void add(int index, E e)**: 添加到指定位置 + +**E set(int index, E e)**: 设置指定位置的元素,返回一个E +**get(int index)**: 获得指定位置的元素 + +**Iterator iterator()** +**ListIterator listIterator()** +**ListIterator listIterator(int index)** + +**int indexOf(E e)** +**int lastIndexOf(E e)** + **List subList(int fromIndex, int toIndex)** -##子类介绍 +## 子类介绍 1. ArrayList是一个可改变大小的数组,当更多的元素加入到ArrayList中时,其大小将会动态的增长。内部的元素可以直接通过get与set方法进行访问,因为ArrayList本质上就是一个数组 2. LinkedList 是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList.当然,这些对比都是指数据量很大或者操作很频繁的情况下的对比,如果数据和运算量很小,那么对比将失去意义。 LinkedList还实现了Queue接口,该接口比List提供了更多的方法,包括offer(),peek(),poll等 diff --git a/Part2/JavaSE/Queue.md b/Part2/JavaSE/Queue.md index ba16926..aceef9b 100755 --- a/Part2/JavaSE/Queue.md +++ b/Part2/JavaSE/Queue.md @@ -4,12 +4,12 @@ * 父接口:Collection * 子接口:Deque -##简介 +## 简介 --- * 是个队列 * 插入、提取、检查操作都存在两种形式,一种在操作失败后返回特殊值,一种抛出异常 -##方法 +## 方法 --- 1. boolean add(E e)和 boolean offer(E e)添加元素 失败时,add()抛出异常,offer()返回false @@ -18,8 +18,8 @@ 3. E remove()和E poll()获取并移除 失败时,remove()抛出异常,poll()返回null -##子类介绍 +## 子类介绍 --- -###Deque +### Deque * 双端队列 * 可以实现队列。也可以用作栈 diff --git a/Part2/JavaSE/Set.md b/Part2/JavaSE/Set.md index adfb1ad..74c7ba9 100755 --- a/Part2/JavaSE/Set.md +++ b/Part2/JavaSE/Set.md @@ -1,4 +1,4 @@ -#Set +# Set --- * 是一个泛型接口 * 继承了接口Collection diff --git "a/Part2/JavaSE/String\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/Part2/JavaSE/String\346\272\220\347\240\201\345\210\206\346\236\220.md" index 78c5a09..9572488 100644 --- "a/Part2/JavaSE/String\346\272\220\347\240\201\345\210\206\346\236\220.md" +++ "b/Part2/JavaSE/String\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -1,4 +1,4 @@ -#String源码分析 +# String源码分析 --- 从一段代码说起: diff --git "a/Part2/JavaSE/Vector\346\272\220\347\240\201\345\211\226\346\236\220.md" "b/Part2/JavaSE/Vector\346\272\220\347\240\201\345\211\226\346\236\220.md" index bbf57d1..0d4a252 100644 --- "a/Part2/JavaSE/Vector\346\272\220\347\240\201\345\211\226\346\236\220.md" +++ "b/Part2/JavaSE/Vector\346\272\220\347\240\201\345\211\226\346\236\220.md" @@ -1,11 +1,11 @@ -##Vector简介 +## Vector简介 Vector也是基于数组实现的,是一个动态数组,其容量能自动增长。 Vector是JDK1.0引入了,它的很多实现方法都加入了同步语句,因此是线程安全的(其实也只是相对安全,有些时候还是要加入同步语句来保证线程的安全),可以用于多线程环境。 Vector没有实现Serializable接口,因此它不支持序列化,实现了Cloneable接口,能被克隆,实现了RandomAccess接口,支持快速随机访问。 -##Vector源码剖析 +## Vector源码剖析 Vector的源码如下(加入了比较详细的注释): ``` @@ -482,7 +482,7 @@ public class Vector } ``` -##几点总结 +## 几点总结 Vector的源码实现总体与ArrayList类似,关于Vector的源码,给出如下几点总结: diff --git "a/Part2/JavaSE/hashmap\345\222\214hashtable\347\232\204\345\272\225\345\261\202\345\256\236\347\216\260\345\222\214\345\214\272\345\210\253\357\274\214\344\270\244\350\200\205\345\222\214concurrenthashmap\347\232\204\345\214\272\345\210\253\343\200\202.md" "b/Part2/JavaSE/hashmap\345\222\214hashtable\347\232\204\345\272\225\345\261\202\345\256\236\347\216\260\345\222\214\345\214\272\345\210\253\357\274\214\344\270\244\350\200\205\345\222\214concurrenthashmap\347\232\204\345\214\272\345\210\253\343\200\202.md" index 4d7880d..a060202 100755 --- "a/Part2/JavaSE/hashmap\345\222\214hashtable\347\232\204\345\272\225\345\261\202\345\256\236\347\216\260\345\222\214\345\214\272\345\210\253\357\274\214\344\270\244\350\200\205\345\222\214concurrenthashmap\347\232\204\345\214\272\345\210\253\343\200\202.md" +++ "b/Part2/JavaSE/hashmap\345\222\214hashtable\347\232\204\345\272\225\345\261\202\345\256\236\347\216\260\345\222\214\345\214\272\345\210\253\357\274\214\344\270\244\350\200\205\345\222\214concurrenthashmap\347\232\204\345\214\272\345\210\253\343\200\202.md" @@ -1,4 +1,4 @@ -#HashMap 和 HashTable 的底层实现和区别,两者和 ConcurrentHashMap 的区别。 +# HashMap 和 HashTable 的底层实现和区别,两者和 ConcurrentHashMap 的区别。 HashMap和HashTable源代码级别的区别 diff --git "a/Part2/JavaSE/\344\273\216\346\272\220\347\240\201\345\210\206\346\236\220HashMap.md" "b/Part2/JavaSE/\344\273\216\346\272\220\347\240\201\345\210\206\346\236\220HashMap.md" index ddd4565..c6d56c5 100644 --- "a/Part2/JavaSE/\344\273\216\346\272\220\347\240\201\345\210\206\346\236\220HashMap.md" +++ "b/Part2/JavaSE/\344\273\216\346\272\220\347\240\201\345\210\206\346\236\220HashMap.md" @@ -1,14 +1,14 @@ -#HashMap +# HashMap --- -###HashMap和Hashtable的区别: +### HashMap和Hashtable的区别: 1. Hashtable的大部分方法做了同步,HashMap没有,因此,HashMap不是线程安全的。 2. Hashtable不允许key或者value使用null值,而HashMap可以。 3. 在内部算法上,它们对key的hash算法和hash值到内存索引的映射算法不同。 -###HashMap的实现原理 +### HashMap的实现原理 简单说,HashMap就是将key做hash算法,然后将hash所对应的数据映射到内存地址,直接取得key所对应的数据。在HashMap中。底层数据结构使用的是数组,所谓的内存地址即数组的下标索引。HashMap的高性能需要保证以下几点: @@ -41,7 +41,7 @@ static int indexFor(int h, int length){ indexFor()函数通过将hash值和数组长度按位与直接得到数组索引。 最后由indexFor()函数返回的数组索引直接通过数组下标便可取得对应的值,直接的内存访问速度也是相当的快,因此,可认为HashMap是高性能的。 -###Hash冲突 +### Hash冲突 如图3.11所示,需要存放到HashMap中的两个元素1和2,通过hash计算后,发现对应在内存中的同一个地址,如何处理? 其实HashMap的底层实现使用的是数组,但是数组内的元素并不是简单的值。而是一个Entry类的对象。因此,对HashMap结构贴切描述如图3.12所示。 @@ -89,7 +89,7 @@ void addEntry(int hash, K key, V value, int bucketIndex){ 基于HashMap的这种实现机制,只要hashCode和hash()方法实现的足够好,能够尽可能的减少冲突的产生,那么对HashMap的操作几乎等价于对数组的随机访问操作,具有很好的性能。但是,如果hashCode()或者hash()方法实现较差,在大量冲突产生的情况下,HashMap事实上就退化为几个链表,对HashMap的操作等价于遍历链表,此时性能很差。 -###容量参数 +### 容量参数 除hashCode()的实现外,影响HashMap性能的还有它的容量参数。和ArrayList和Vector一样,这种基于数组的结构,不可避免的需要在数组空间不足时,进行扩展。而数组的重组相对而言较为耗时,因此对其作一定了解有助于优化HashMap的性能。 diff --git "a/Part2/JavaSE/\345\217\215\345\260\204\346\234\272\345\210\266.md" "b/Part2/JavaSE/\345\217\215\345\260\204\346\234\272\345\210\266.md" index 0c74ff4..39710d9 100755 --- "a/Part2/JavaSE/\345\217\215\345\260\204\346\234\272\345\210\266.md" +++ "b/Part2/JavaSE/\345\217\215\345\260\204\346\234\272\345\210\266.md" @@ -1,4 +1,4 @@ -#反射机制 +# 反射机制 反射技术:其实就是动态加载一个指定的类,并获取该类中所有的内容。并将字节码文件中的内容都封装成对象,这样便于操作这些成员。简单说:反射技术可以对一个类进行解剖。 diff --git "a/Part2/JavaSE/\345\246\202\344\275\225\350\241\250\350\276\276\345\207\272Collection\345\217\212\345\205\266\345\255\220\347\261\273.md" "b/Part2/JavaSE/\345\246\202\344\275\225\350\241\250\350\276\276\345\207\272Collection\345\217\212\345\205\266\345\255\220\347\261\273.md" index 797f406..2828a81 100755 --- "a/Part2/JavaSE/\345\246\202\344\275\225\350\241\250\350\276\276\345\207\272Collection\345\217\212\345\205\266\345\255\220\347\261\273.md" +++ "b/Part2/JavaSE/\345\246\202\344\275\225\350\241\250\350\276\276\345\207\272Collection\345\217\212\345\205\266\345\255\220\347\261\273.md" @@ -1,4 +1,4 @@ -#如何介绍数据结构 +# 如何介绍数据结构 1. 是泛型?接口?类? 2. 是个什么? @@ -8,7 +8,7 @@ 6. 子类? -#Collection +# Collection --- 1. 是一个泛型的接口 2. 继承了超级接口Iterable @@ -19,7 +19,7 @@ 7. 没有具体的直接实现,但提供了更具体的子接口,如Set、List等 -#List +# List --- 1. 是一个接口,继承了接口Collection 2. List是有序的Collection,能够精确控制插入、获取的位置 @@ -27,7 +27,7 @@ 4. 它的直接实现类有ArrayList,LinkedList,Vector等 5. List有自己的迭代器ListIterator,可以通过这个迭代器进行逆序的迭代,以及用迭代器设置元素的值 -#ArrayList +# ArrayList --- 1. ArrayList实现了Collection接口 2. ArrayList是一个顺序表。大小可变。 @@ -35,7 +35,7 @@ 4. ArrayList相比Vector是线程不安全的 -#LinkedList +# LinkedList --- 1. LinkedList泛型接口 2. 链表 diff --git a/Part3/Algorithm/LeetCode/two-sum.md b/Part3/Algorithm/LeetCode/two-sum.md index 7093c58..cfeb3de 100644 --- a/Part3/Algorithm/LeetCode/two-sum.md +++ b/Part3/Algorithm/LeetCode/two-sum.md @@ -1,4 +1,4 @@ -#two-sum +# two-sum --- Question diff --git a/Part3/Algorithm/LeetCode/zigzag-conversion.md b/Part3/Algorithm/LeetCode/zigzag-conversion.md index 2815e2d..c5f7afb 100644 --- a/Part3/Algorithm/LeetCode/zigzag-conversion.md +++ b/Part3/Algorithm/LeetCode/zigzag-conversion.md @@ -1,4 +1,4 @@ -#zigzag-conversion +# zigzag-conversion --- 题目描述 diff --git "a/Part3/Algorithm/Lookup/\346\212\230\345\215\212\346\237\245\346\211\276.md" "b/Part3/Algorithm/Lookup/\346\212\230\345\215\212\346\237\245\346\211\276.md" index a033b05..af794c7 100644 --- "a/Part3/Algorithm/Lookup/\346\212\230\345\215\212\346\237\245\346\211\276.md" +++ "b/Part3/Algorithm/Lookup/\346\212\230\345\215\212\346\237\245\346\211\276.md" @@ -1,4 +1,4 @@ -#折半查找 +# 折半查找 --- 基本原理:每次查找都对半分,但要求数组是有序的 diff --git "a/Part3/Algorithm/Lookup/\351\241\272\345\272\217\346\237\245\346\211\276.md" "b/Part3/Algorithm/Lookup/\351\241\272\345\272\217\346\237\245\346\211\276.md" index 134477a..d3eb0c5 100644 --- "a/Part3/Algorithm/Lookup/\351\241\272\345\272\217\346\237\245\346\211\276.md" +++ "b/Part3/Algorithm/Lookup/\351\241\272\345\272\217\346\237\245\346\211\276.md" @@ -1,4 +1,4 @@ -#顺序查找 +# 顺序查找 --- 基本原理:依次遍历 diff --git "a/Part3/Algorithm/Sort/\345\206\222\346\263\241\346\216\222\345\272\217.md" "b/Part3/Algorithm/Sort/\345\206\222\346\263\241\346\216\222\345\272\217.md" index ccf96ac..dd4d9e7 100644 --- "a/Part3/Algorithm/Sort/\345\206\222\346\263\241\346\216\222\345\272\217.md" +++ "b/Part3/Algorithm/Sort/\345\206\222\346\263\241\346\216\222\345\272\217.md" @@ -1,4 +1,4 @@ -#冒泡排序: +# 冒泡排序: --- * 背景介绍: 是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。----- 来自 [wikipedia](https://zh.wikipedia.org/wiki/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F) * 算法规则: 由于算法每次都将一个最大的元素往上冒,我们可以将待排序集合(0...n)看成两部分,一部分为(k..n)的待排序unsorted集合,另一部分为(0...k)的已排序sorted集合,每一次都在unsorted集合从前往后遍历,选出一个数,如果这个数比其后面的数大,则进行交换。完成一轮之后,就肯定能将这一轮unsorted集合中最大的数移动到集合的最后,并且将这个数从unsorted中删除,移入sorted中。 diff --git "a/Part3/Algorithm/Sort/\345\275\222\345\271\266\346\216\222\345\272\217.md" "b/Part3/Algorithm/Sort/\345\275\222\345\271\266\346\216\222\345\272\217.md" index 689469b..add5227 100644 --- "a/Part3/Algorithm/Sort/\345\275\222\345\271\266\346\216\222\345\272\217.md" +++ "b/Part3/Algorithm/Sort/\345\275\222\345\271\266\346\216\222\345\272\217.md" @@ -1,4 +1,4 @@ -#归并排序: +# 归并排序: --- * 背景介绍: 是创建在归并操作上的一种有效的排序算法,效率为O(n log n)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。 ----- 来自 [wikipedia](https://zh.wikipedia.org/wiki/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F) * **算法规则: 像快速排序一样,由于归并排序也是分治算法,因此可使用分治思想:**
1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2.设定两个指针,最初位置分别为两个已经排序序列的起始位置
3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4.重复步骤3直到某一指针到达序列尾
5.将另一序列剩下的所有元素直接复制到合并序列尾 diff --git "a/Part3/Algorithm/Sort/\345\277\253\351\200\237\346\216\222\345\272\217.md" "b/Part3/Algorithm/Sort/\345\277\253\351\200\237\346\216\222\345\272\217.md" index 20a6987..f02b50f 100644 --- "a/Part3/Algorithm/Sort/\345\277\253\351\200\237\346\216\222\345\272\217.md" +++ "b/Part3/Algorithm/Sort/\345\277\253\351\200\237\346\216\222\345\272\217.md" @@ -1,5 +1,5 @@ -#快速排序: +# 快速排序: --- * 背景介绍: 又称划分交换排序(partition-exchange sort),一种排序算法,最早由东尼·霍尔提出。在平均状况下,排序n个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n)算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来 ----- 来自 [wikipedia](https://zh.wikipedia.org/wiki/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F) ** * 算法规则: 本质来说,快速排序的过程就是不断地将无序元素集递归分割,一直到所有的分区只包含一个元素为止。
由于快速排序是一种分治算法,我们可以用分治思想将快排分为三个步骤:
1.分:设定一个分割值,并根据它将数据分为两部分
2.治:分别在两部分用递归的方式,继续使用快速排序法
3.合:对分割的部分排序直到完成 diff --git "a/Part3/Algorithm/Sort/\351\200\211\346\213\251\346\216\222\345\272\217.md" "b/Part3/Algorithm/Sort/\351\200\211\346\213\251\346\216\222\345\272\217.md" index 75465ab..e89ec9b 100644 --- "a/Part3/Algorithm/Sort/\351\200\211\346\213\251\346\216\222\345\272\217.md" +++ "b/Part3/Algorithm/Sort/\351\200\211\346\213\251\346\216\222\345\272\217.md" @@ -1,4 +1,4 @@ -#选择排序: +# 选择排序: --- * 背景介绍: 选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 ----- 来自 [wikipedia](https://zh.wikipedia.org/wiki/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F) * 算法规则: 将待排序集合(0...n)看成两部分,在起始状态中,一部分为(k..n)的待排序unsorted集合,另一部分为(0...k)的已排序sorted集合,在待排序集合中挑选出最小元素并且记录下标i,若该下标不等于k,那么 unsorted[i] 与 sorted[k]交换 ,一直重复这个过程,直到unsorted集合中元素为空为止。 diff --git "a/Part3/Algorithm/Sort/\351\235\242\350\257\225\344\270\255\347\232\204 10 \345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.md" "b/Part3/Algorithm/Sort/\351\235\242\350\257\225\344\270\255\347\232\204 10 \345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.md" index 626f256..d639894 100644 --- "a/Part3/Algorithm/Sort/\351\235\242\350\257\225\344\270\255\347\232\204 10 \345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.md" +++ "b/Part3/Algorithm/Sort/\351\235\242\350\257\225\344\270\255\347\232\204 10 \345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.md" @@ -1,4 +1,4 @@ -

本文转载自码农网:http://www.codeceo.com/article/10-sort-algorithm-interview.html#0-tsina-1-10490-397232819ff9a47a7b7e80a40613cfe1 +

本文转载自码农网:http://www.codeceo.com/article/10-sort-algorithm-interview.html# 0-tsina-1-10490-397232819ff9a47a7b7e80a40613cfe1

@@ -453,7 +453,7 @@ public class CountSort {

桶排序算是计数排序的一种改进和推广,但是网上有许多资料把计数排序和桶排序混为一谈。其实桶排序要比计数排序复杂许多。

对桶排序的分析和解释借鉴这位兄弟的文章(有改动):http://hxraid.iteye.com/blog/647759

桶排序的基本思想:

-

假设有一组长度为N的待排关键字序列K[1....n]。首先将这个序列划分成M个的子区间(桶) 。然后基于某种映射函数 ,将待排序列的关键字k映射到第i个桶中(即桶数组B的下标 i) ,那么该关键字k就作为B[i]中的元素(每个桶B[i]都是一组大小为N/M的序列)。接着对每个桶B[i]中的所有元素进行比较排序(可以使用快排)。然后依次枚举输出B[0]….B[M]中的全部内容即是一个有序序列。bindex=f(key) 其中,bindex 为桶数组B的下标(即第bindex个桶), k为待排序列的关键字。桶排序之所以能够高效,其关键在于这个映射函数,它必须做到:如果关键字k1<k2,那么f(k1)<=f(k2)。也就是说B(i)中的最小数据都要大于B(i-1)中最大数据。很显然,映射函数的确定与数据本身的特点有很大的关系。

+

假设有一组长度为N的待排关键字序列K[1....n]。首先将这个序列划分成M个的子区间(桶) 。然后基于某种映射函数 ,将待排序列的关键字k映射到第i个桶中(即桶数组B的下标 i) ,那么该关键字k就作为B[i]中的元素(每个桶B[i]都是一组大小为N/M的序列)。接着对每个桶B[i]中的所有元素进行比较排序(可以使用快排)。然后依次枚举输出B[0]&# 8230;.B[M]中的全部内容即是一个有序序列。bindex=f(key) 其中,bindex 为桶数组B的下标(即第bindex个桶), k为待排序列的关键字。桶排序之所以能够高效,其关键在于这个映射函数,它必须做到:如果关键字k1<k2,那么f(k1)<=f(k2)。也就是说B(i)中的最小数据都要大于B(i-1)中最大数据。很显然,映射函数的确定与数据本身的特点有很大的关系。

举个栗子:

假如待排序列K= {49、 38 、 35、 97 、 76、 73 、 27、 49 }。这些数据全部在1—100之间。因此我们定制10个桶,然后确定映射函数f(k)=k/10。则第一个关键字49将定位到第4个桶中(49/10=4)。依次将所有关键字全部堆入桶中,并在每个非空的桶中进行快速排序后得到如图所示。只要顺序输出每个B[i]中的数据就可以得到有序序列了。

@@ -625,7 +625,7 @@ public class RadixSort {

附:基于比较排序算法时间下限为O(nlogn)的证明:

基于比较排序下限的证明是通过决策树证明的,决策树的高度Ω(nlgn),这样就得出了比较排序的下限。

-

首先要引入决策树。 首先决策树是一颗二叉树,每个节点表示元素之间一组可能的排序,它予以京进行的比较相一致,比较的结果是树的边。 先来说明一些二叉树的性质,令T是深度为d的二叉树,则T最多有2^片树叶。 具有L片树叶的二叉树的深度至少是logL。 所以,对n个元素排序的决策树必然有n!片树叶(因为n个数有n!种不同的大小关系),所以决策树的深度至少是log(n!),即至少需要log(n!)次比较。 而 log(n!)=logn+log(n-1)+log(n-2)+…+log2+log1 >=logn+log(n-1)+log(n-2)+…+log(n/2) >=(n/2)log(n/2) >=(n/2)logn-n/2 =O(nlogn) 所以只用到比较的排序算法最低时间复杂度是O(nlogn)。

+

首先要引入决策树。 首先决策树是一颗二叉树,每个节点表示元素之间一组可能的排序,它予以京进行的比较相一致,比较的结果是树的边。 先来说明一些二叉树的性质,令T是深度为d的二叉树,则T最多有2^片树叶。 具有L片树叶的二叉树的深度至少是logL。 所以,对n个元素排序的决策树必然有n!片树叶(因为n个数有n!种不同的大小关系),所以决策树的深度至少是log(n!),即至少需要log(n!)次比较。 而 log(n!)=logn+log(n-1)+log(n-2)+&# 8230;+log2+log1 >=logn+log(n-1)+log(n-2)+&# 8230;+log(n/2) >=(n/2)log(n/2) >=(n/2)logn-n/2 =O(nlogn) 所以只用到比较的排序算法最低时间复杂度是O(nlogn)。

参考资料:

  • 《数据结构》 严蔚敏 吴伟民 编著
  • diff --git "a/Part3/Algorithm/\345\211\221\346\214\207Offer/1.\344\270\203\347\247\215\346\226\271\345\274\217\345\256\236\347\216\260singleton\346\250\241\345\274\217.md" "b/Part3/Algorithm/\345\211\221\346\214\207Offer/1.\344\270\203\347\247\215\346\226\271\345\274\217\345\256\236\347\216\260singleton\346\250\241\345\274\217.md" index 6a8ae00..c872c43 100644 --- "a/Part3/Algorithm/\345\211\221\346\214\207Offer/1.\344\270\203\347\247\215\346\226\271\345\274\217\345\256\236\347\216\260singleton\346\250\241\345\274\217.md" +++ "b/Part3/Algorithm/\345\211\221\346\214\207Offer/1.\344\270\203\347\247\215\346\226\271\345\274\217\345\256\236\347\216\260singleton\346\250\241\345\274\217.md" @@ -1,4 +1,4 @@ -#面试题2.七种方式实现Singleton模式 +# 面试题2.七种方式实现Singleton模式 --- ``` diff --git "a/Part3/Algorithm/\345\211\221\346\214\207Offer/2.\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.md" "b/Part3/Algorithm/\345\211\221\346\214\207Offer/2.\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.md" index dc09629..b6dfbc6 100644 --- "a/Part3/Algorithm/\345\211\221\346\214\207Offer/2.\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.md" +++ "b/Part3/Algorithm/\345\211\221\346\214\207Offer/2.\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.md" @@ -1,9 +1,9 @@ -#面试题3:二维数组中的查找 +# 面试题3:二维数组中的查找 --- 这个题我在面试今日头条的时候面试官让我写过这个题目的代码,所以比较重要。 -###题目描述 +### 题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 输入描述: diff --git "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.md" "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.md" index 27bd7d5..9f4aa26 100644 --- "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.md" +++ "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.md" @@ -1,4 +1,4 @@ -#合并两个排序的链表 +# 合并两个排序的链表 --- 题目: diff --git "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.md" "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.md" index 11d9449..68ebe15 100644 --- "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.md" +++ "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.md" @@ -1,4 +1,4 @@ -#旋转数组的最小数字 +# 旋转数组的最小数字 --- 题目 diff --git "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23011\357\274\232\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.md" "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23011\357\274\232\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.md" index f42e645..12117d6 100644 --- "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23011\357\274\232\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.md" +++ "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23011\357\274\232\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.md" @@ -1,4 +1,4 @@ -#面试题11 数值的整数次方 +# 面试题11 数值的整数次方 --- 题目: diff --git "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23012\357\274\232\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260.md" "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23012\357\274\232\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260.md" index 9ec778a..50df35b 100644 --- "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23012\357\274\232\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260.md" +++ "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23012\357\274\232\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260.md" @@ -1,4 +1,4 @@ -# 面试题12 打印1到最大的n位数 +# 面试题12 打印1到最大的n位数 --- 题目: diff --git "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23044\357\274\232\346\211\221\345\205\213\347\211\214\347\232\204\351\241\272\345\255\220.md" "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23044\357\274\232\346\211\221\345\205\213\347\211\214\347\232\204\351\241\272\345\255\220.md" index 1152229..0d9d6ff 100644 --- "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23044\357\274\232\346\211\221\345\205\213\347\211\214\347\232\204\351\241\272\345\255\220.md" +++ "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23044\357\274\232\346\211\221\345\205\213\347\211\214\347\232\204\351\241\272\345\255\220.md" @@ -1,4 +1,4 @@ -#面试题44:扑克牌的顺子 +# 面试题44:扑克牌的顺子 --- 题目: diff --git "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23045\357\274\232\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260\345\255\227.md" "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23045\357\274\232\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260\345\255\227.md" index 475f830..b279c9a 100644 --- "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23045\357\274\232\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260\345\255\227.md" +++ "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\23045\357\274\232\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260\345\255\227.md" @@ -1,4 +1,4 @@ -#面试题45 圆圈中最后剩下的数字 +# 面试题45 圆圈中最后剩下的数字 --- 题目 diff --git "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\2306\357\274\232\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.md" "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\2306\357\274\232\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.md" index f3aec3b..1850fed 100644 --- "a/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\2306\357\274\232\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.md" +++ "b/Part3/Algorithm/\345\211\221\346\214\207Offer/\351\235\242\350\257\225\351\242\2306\357\274\232\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.md" @@ -1,4 +1,4 @@ -#面试题6:重建二叉树 +# 面试题6:重建二叉树 --- 题目: diff --git "a/Part3/Algorithm/\347\250\213\345\272\217\345\221\230\344\273\243\347\240\201\351\235\242\350\257\225\346\214\207\345\215\227(\345\267\246\347\250\213\344\272\221)/1.\350\256\276\350\256\241\344\270\200\344\270\252\346\234\211getMin\345\212\237\350\203\275\347\232\204\346\240\210.md" "b/Part3/Algorithm/\347\250\213\345\272\217\345\221\230\344\273\243\347\240\201\351\235\242\350\257\225\346\214\207\345\215\227(\345\267\246\347\250\213\344\272\221)/1.\350\256\276\350\256\241\344\270\200\344\270\252\346\234\211getMin\345\212\237\350\203\275\347\232\204\346\240\210.md" index 11f2d56..02340dc 100644 --- "a/Part3/Algorithm/\347\250\213\345\272\217\345\221\230\344\273\243\347\240\201\351\235\242\350\257\225\346\214\207\345\215\227(\345\267\246\347\250\213\344\272\221)/1.\350\256\276\350\256\241\344\270\200\344\270\252\346\234\211getMin\345\212\237\350\203\275\347\232\204\346\240\210.md" +++ "b/Part3/Algorithm/\347\250\213\345\272\217\345\221\230\344\273\243\347\240\201\351\235\242\350\257\225\346\214\207\345\215\227(\345\267\246\347\250\213\344\272\221)/1.\350\256\276\350\256\241\344\270\200\344\270\252\346\234\211getMin\345\212\237\350\203\275\347\232\204\346\240\210.md" @@ -1,4 +1,4 @@ -#设计一个有getMin功能的栈 +# 设计一个有getMin功能的栈 --- 实现一个特殊的栈,在实现栈的基本功能的基础上,在实现返回栈中最小元素的操作。 diff --git "a/Part3/Algorithm/\347\250\213\345\272\217\345\221\230\344\273\243\347\240\201\351\235\242\350\257\225\346\214\207\345\215\227(\345\267\246\347\250\213\344\272\221)/2.\347\224\261\344\270\244\344\270\252\346\240\210\347\273\204\346\210\220\347\232\204\351\230\237\345\210\227.md" "b/Part3/Algorithm/\347\250\213\345\272\217\345\221\230\344\273\243\347\240\201\351\235\242\350\257\225\346\214\207\345\215\227(\345\267\246\347\250\213\344\272\221)/2.\347\224\261\344\270\244\344\270\252\346\240\210\347\273\204\346\210\220\347\232\204\351\230\237\345\210\227.md" index 586cbe6..28af6d7 100644 --- "a/Part3/Algorithm/\347\250\213\345\272\217\345\221\230\344\273\243\347\240\201\351\235\242\350\257\225\346\214\207\345\215\227(\345\267\246\347\250\213\344\272\221)/2.\347\224\261\344\270\244\344\270\252\346\240\210\347\273\204\346\210\220\347\232\204\351\230\237\345\210\227.md" +++ "b/Part3/Algorithm/\347\250\213\345\272\217\345\221\230\344\273\243\347\240\201\351\235\242\350\257\225\346\214\207\345\215\227(\345\267\246\347\250\213\344\272\221)/2.\347\224\261\344\270\244\344\270\252\346\240\210\347\273\204\346\210\220\347\232\204\351\230\237\345\210\227.md" @@ -1,4 +1,4 @@ -#2.由两个栈组成的队列 +# 2.由两个栈组成的队列 --- 题目: diff --git "a/Part3/Algorithm/\347\250\213\345\272\217\345\221\230\344\273\243\347\240\201\351\235\242\350\257\225\346\214\207\345\215\227(\345\267\246\347\250\213\344\272\221)/3.\345\246\202\344\275\225\344\273\205\347\224\250\351\200\222\345\275\222\345\207\275\346\225\260\345\222\214\346\240\210\346\223\215\344\275\234\351\200\206\345\272\217\344\270\200\344\270\252\346\240\210.md" "b/Part3/Algorithm/\347\250\213\345\272\217\345\221\230\344\273\243\347\240\201\351\235\242\350\257\225\346\214\207\345\215\227(\345\267\246\347\250\213\344\272\221)/3.\345\246\202\344\275\225\344\273\205\347\224\250\351\200\222\345\275\222\345\207\275\346\225\260\345\222\214\346\240\210\346\223\215\344\275\234\351\200\206\345\272\217\344\270\200\344\270\252\346\240\210.md" index 893c9aa..9ee9e6a 100644 --- "a/Part3/Algorithm/\347\250\213\345\272\217\345\221\230\344\273\243\347\240\201\351\235\242\350\257\225\346\214\207\345\215\227(\345\267\246\347\250\213\344\272\221)/3.\345\246\202\344\275\225\344\273\205\347\224\250\351\200\222\345\275\222\345\207\275\346\225\260\345\222\214\346\240\210\346\223\215\344\275\234\351\200\206\345\272\217\344\270\200\344\270\252\346\240\210.md" +++ "b/Part3/Algorithm/\347\250\213\345\272\217\345\221\230\344\273\243\347\240\201\351\235\242\350\257\225\346\214\207\345\215\227(\345\267\246\347\250\213\344\272\221)/3.\345\246\202\344\275\225\344\273\205\347\224\250\351\200\222\345\275\222\345\207\275\346\225\260\345\222\214\346\240\210\346\223\215\344\275\234\351\200\206\345\272\217\344\270\200\344\270\252\346\240\210.md" @@ -1,4 +1,4 @@ -#3.如何仅用递归函数和栈操作逆序一个栈 +# 3.如何仅用递归函数和栈操作逆序一个栈 --- 题目: diff --git "a/Part3/DataStructure/\346\225\260\346\215\256\347\273\223\346\236\204(Java).md" "b/Part3/DataStructure/\346\225\260\346\215\256\347\273\223\346\236\204(Java).md" index a9736ad..8dbf649 100644 --- "a/Part3/DataStructure/\346\225\260\346\215\256\347\273\223\346\236\204(Java).md" +++ "b/Part3/DataStructure/\346\225\260\346\215\256\347\273\223\346\236\204(Java).md" @@ -1,10 +1,10 @@ -#数据结构和算法: +# 数据结构和算法: --- (推荐书籍:剑指offer、编程之美、Cracking、程序员代码面试指南,特别是这四本书上的重复题) **数组与链表** -####数组: +#### 数组: 创建 @@ -81,7 +81,7 @@ Tips:数组中删除和增加元素的原理:增加元素,需要将index后 数组表示相同类型的一类数据的集合,下标从0开始。 -####单链表: +#### 单链表: ![](http://img.my.csdn.net/uploads/201304/13/1365855052_1221.jpg) diff --git "a/Part3/DataStructure/\346\225\260\347\273\204.md" "b/Part3/DataStructure/\346\225\260\347\273\204.md" index b83f81a..23e186a 100644 --- "a/Part3/DataStructure/\346\225\260\347\273\204.md" +++ "b/Part3/DataStructure/\346\225\260\347\273\204.md" @@ -1,4 +1,4 @@ -#数组 +# 数组 --- ``` diff --git "a/Part3/DataStructure/\346\240\210\345\222\214\351\230\237\345\210\227.md" "b/Part3/DataStructure/\346\240\210\345\222\214\351\230\237\345\210\227.md" index 2847248..aac5de4 100644 --- "a/Part3/DataStructure/\346\240\210\345\222\214\351\230\237\345\210\227.md" +++ "b/Part3/DataStructure/\346\240\210\345\222\214\351\230\237\345\210\227.md" @@ -1,6 +1,6 @@ -#栈和队列 +# 栈和队列 --- -##栈 +## 栈 --- 栈只允许访问一个数据项:即最后插入的数据。溢出这个数据才能访问倒数第二个插入的数据项。它是一种"后进先出"的数据结构。 @@ -90,7 +90,7 @@ public class ArrayStack { ``` -##队列 +## 队列 --- 依然使用数组作为底层容器来实现一个队列的封装 diff --git "a/Part3/DataStructure/\351\200\222\345\275\222\345\222\214\351\235\236\351\200\222\345\275\222\346\226\271\345\274\217\345\256\236\347\216\260\344\272\214\345\217\211\346\240\221\345\205\210\343\200\201\344\270\255\343\200\201\345\220\216\345\272\217\351\201\215\345\216\206.md" "b/Part3/DataStructure/\351\200\222\345\275\222\345\222\214\351\235\236\351\200\222\345\275\222\346\226\271\345\274\217\345\256\236\347\216\260\344\272\214\345\217\211\346\240\221\345\205\210\343\200\201\344\270\255\343\200\201\345\220\216\345\272\217\351\201\215\345\216\206.md" index 20ea885..aa741bf 100644 --- "a/Part3/DataStructure/\351\200\222\345\275\222\345\222\214\351\235\236\351\200\222\345\275\222\346\226\271\345\274\217\345\256\236\347\216\260\344\272\214\345\217\211\346\240\221\345\205\210\343\200\201\344\270\255\343\200\201\345\220\216\345\272\217\351\201\215\345\216\206.md" +++ "b/Part3/DataStructure/\351\200\222\345\275\222\345\222\214\351\235\236\351\200\222\345\275\222\346\226\271\345\274\217\345\256\236\347\216\260\344\272\214\345\217\211\346\240\221\345\205\210\343\200\201\344\270\255\343\200\201\345\220\216\345\272\217\351\201\215\345\216\206.md" @@ -1,4 +1,4 @@ -###递归和非递归方式实现二叉树先、中、后序遍历 +### 递归和非递归方式实现二叉树先、中、后序遍历 先序遍历顺序为根、左、右,中序遍历顺序为左、根、右,后序遍历是左、右、根。 diff --git "a/Part4/Network/Http\345\215\217\350\256\256.md" "b/Part4/Network/Http\345\215\217\350\256\256.md" index 03f7cf5..269c1dc 100755 --- "a/Part4/Network/Http\345\215\217\350\256\256.md" +++ "b/Part4/Network/Http\345\215\217\350\256\256.md" @@ -1,8 +1,8 @@ -#Http协议 +# Http协议 --- * 默认端口:80 -##Http协议的主要特点 +## Http协议的主要特点 --- 1. 支持客户/服务器模式 2. 简单快速:客户向服务端请求服务时,只需传送请求方式和路径。 @@ -10,23 +10,23 @@ 4. 无连接:每次响应一个请求,响应完成以后就断开连接。 5. 无状态:服务器不保存浏览器的任何信息。每次提交的请求之间没有关联。 -###非持续性和持续性 +### 非持续性和持续性 --- * HTTP1.0默认非持续性;HTTP1.1默认持续性 -####持续性 +#### 持续性 浏览器和服务器建立TCP连接后,可以请求多个对象 -####非持续性 +#### 非持续性 浏览器和服务器建立TCP连接后,只能请求一个对象 -###非流水线和流水线 +### 非流水线和流水线 --- 类似于组成里面的流水操作 * 流水线:不必等到收到服务器的回应就发送下一个报文。 * 非流水线:发出一个报文,等到响应,再发下一个报文。类似TCP。 -####POST和GET的区别 +#### POST和GET的区别 | Post一般用于更新或者添加资源信息 | Get一般用于查询操作,而且应该是安全和幂等的 | | ------------- |:-------------:| @@ -35,14 +35,14 @@ | Post执行效率低 | Get执行效率略高 | -####为什么POST效率低,Get效率高 +#### 为什么POST效率低,Get效率高 --- * Get将参数拼成URL,放到header消息头里传递 * Post直接以键值对的形式放到消息体中传递。 * 但两者的效率差距很小很小 -##Https +## Https --- * 端口号是443 * 是由SSL+Http协议构建的可进行加密传输、身份认证的网络协议。 diff --git a/Part4/Network/Socket.md b/Part4/Network/Socket.md index 11d6d5e..a0bf4c4 100755 --- a/Part4/Network/Socket.md +++ b/Part4/Network/Socket.md @@ -1,6 +1,6 @@ -#Socket +# Socket --- -###使用TCP +### 使用TCP --- 客户端 diff --git "a/Part4/Network/TCP\344\270\216UDP.md" "b/Part4/Network/TCP\344\270\216UDP.md" index b454430..8b9cea6 100644 --- "a/Part4/Network/TCP\344\270\216UDP.md" +++ "b/Part4/Network/TCP\344\270\216UDP.md" @@ -1,4 +1,4 @@ -#TCP与UDP +# TCP与UDP --- **面向报文的传输方式**是应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文。因此,应用程序必须选择合适大小的报文。若报文太长,则IP层需要分片,降低效率。若太短,会是IP太小。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。这也就是说,应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文。 diff --git "a/Part4/Network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\345\237\272\347\241\200\346\261\207\346\200\273.md" "b/Part4/Network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\345\237\272\347\241\200\346\261\207\346\200\273.md" index e4797a3..5cdaec5 100644 --- "a/Part4/Network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\345\237\272\347\241\200\346\261\207\346\200\273.md" +++ "b/Part4/Network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\345\237\272\347\241\200\346\261\207\346\200\273.md" @@ -1,4 +1,4 @@ -#计算机网络体系分类: +# 计算机网络体系分类: 计算机网络整个体系有两个大的分类:一个是国际组织制定的OSI七层模型,一种是实际使用中的TCP/IP四层模型。 |OSI七层模型 |TCP/IP四层模型| @@ -11,29 +11,29 @@ |数据链路层|物理接入层| |物理层|| -#物理层: +# 物理层: 物理层主要是实现主机和网络之间的物理连接,规定一些与传输媒体接口有关的一些特性。 -##通信方式: +## 通信方式: - **单工通信:**只能由A主机向B主机发送消息,通信是单向的。 - **半双工通信:**同一时间只能是由A主机向B主机或者是B主机向A主机发送信息,不能同时发送消息。 - **全双工通信:** A主机和B主机可以实现在同一时间内既接收消息,又发送消息,极大的提升了通信效率。 -##常见引导型传输媒体: -###双绞线: +## 常见引导型传输媒体: +### 双绞线: 分为屏蔽双绞线(STP)和非屏蔽双绞线(UTP),屏蔽双绞线就是在非屏蔽双绞线外边又加了一层屏蔽层 tips:为什么双绞线要两根线绞起来,两个线绞起来可以有效的减少相互之间的电磁干扰。 -###同轴电缆: +### 同轴电缆: 由内导体铜制芯线,绝缘层,网状编织的外导体屏蔽层,以及塑料保护外层组成。有良好的抗干扰性,被广泛用于较高速率的传输。 -###光缆: +### 光缆: 由非常透明的石英玻璃拉成细丝,主要由纤芯和包层构成双层通讯柱。可以分为单模光纤和多模光纤。 -##信道复用技术: +## 信道复用技术: - **频分复用:**根据传输的波的频率的不同,将不同频段的波用于不同的通信。 @@ -43,15 +43,15 @@ tips:为什么双绞线要两根线绞起来,两个线绞起来可以有效 - 光分复用:就是光的频分复用,根据光谱中频率的不同,用不同频率的光来携带不同的信息。 -#数据链路层: +# 数据链路层: 数据链路层主要是将上层的数据转化为数据帧发送到链路上,以及把接受到的帧中的数据取出并交给网络层。 -##通信方式: +## 通信方式: - **点对点通信:**通信方式是点到点的,也就是只能是两个点之间的通信。常见的就是PPP协议 - **广播通信:**广播通讯,也就是可以同时实现一对多的通信。常见的就是CSMA/CD(载波监听多点访问/冲突检测) -##核心要解决的问题: +## 核心要解决的问题: - **封装成帧:**在一段数据的前后分别添加首部和尾部,这样就构成了一个帧。接收端在接受到后就可以方便准确的确定帧的首尾,也称为帧定界符。同时定义出了最大传输单元(MTU)--表示一次可以传输的最大长度上限。 @@ -59,11 +59,11 @@ tips:为什么双绞线要两根线绞起来,两个线绞起来可以有效 - **差错检测:** 比特在传输过程中可能产生差错,差错检测就是用于检测出现的差错,以便及时的重传,最常用的差错检测算法就是[CRC(循环冗余检验)](http://baike.sogou.com/v7730112.htm?fromTitle=CRC%E6%A0%A1%E9%AA%8C) -#网络层 +# 网络层 网络层主要是向上只提供简单灵活的,无连接的,尽最大努力交付的数据报服务。 -##IP协议(网际协议): +## IP协议(网际协议): IP协议是TCP/IP体系中最主要的协议之一,一切在IP之下,一切又在IP之上。我们常说的应该是IP协议族,还包含配套的协议: - ARP(地址解析协议):将网络的IP地址转化为实际的物理地址(MAC地址),并存储在MAC地址表中。 @@ -84,11 +84,11 @@ IP协议是TCP/IP体系中最主要的协议之一,一切在IP之下,一切 - E类:前四位为1111,保留为以后使用 -##路由选择协议: +## 路由选择协议: 路由选择协议分为**内部网关协议(IGP)**和**外部网关协议(EGP)** -###内部网关协议: +### 内部网关协议: 主要是有RIP协议和OSPF协议 @@ -96,7 +96,7 @@ IP协议是TCP/IP体系中最主要的协议之一,一切在IP之下,一切 - **OSPF(开放最短路径优先协议):**基于链路状态的协议 -###外部网关协议: +### 外部网关协议: 主要是**边界网关协议(BGP)**,将一个大的网络分为多个小的自治域,每个自治域内有一个网关路由负责和其他的自治域的网关进行通讯。 @@ -104,11 +104,11 @@ IP协议是TCP/IP体系中最主要的协议之一,一切在IP之下,一切 网络层主要是为主机之间提供逻辑通讯,而传输层为应用程序之间提供端到端的逻辑通讯。主要是两种类型的通讯方式,面向连接的TCP协议和面向无连接的UDP。 -##端口号: +## 端口号: 端口号按照使用地方的不同分为两大类:服务端端口号,客户端端口号。 按照占用时长又可以分为熟知端口号(0~1023),登记端口号(1024~49151),短暂端口号(49152~65535) -###常见端口: +### 常见端口: - FTP(文件传输协议):20,21------其中20端口用于传输数据,21端口用于命令控制 @@ -120,7 +120,7 @@ IP协议是TCP/IP体系中最主要的协议之一,一切在IP之下,一切 - HTTP(超文本传输协议):80 -##两种协议: +## 两种协议: - **UDP(用户数据报协议):** @@ -139,7 +139,7 @@ IP协议是TCP/IP体系中最主要的协议之一,一切在IP之下,一切 - TCP提供全双工通信 - 面向字节流 -###可靠传输的实现机制: +### 可靠传输的实现机制: - **停止等待协议:** 每发完一个分组就停止发送,直到收到上一个分组的确认信息。若超过规定时间没有接收到确认信息,边认为是分组丢失,开始重传。 @@ -166,9 +166,9 @@ IP协议是TCP/IP体系中最主要的协议之一,一切在IP之下,一切 - **快回复:**与快重传配合使用,当发送方连续收到三个重复确认的时候,就执行“乘法减小”算法,将慢开始门限减半。将拥塞窗口设置为慢开始门限减半之后的值,并开始指向拥塞避免算法。 -###TCP的连接管理: +### TCP的连接管理: -####连接三次握手: +#### 连接三次握手: 1. 客户端请求建立连接:SYN=1,seq=x; 2. 服务器对客户端的请求进行响应:SYN=1,ACK=1,seq=y,ack=x+1 @@ -176,7 +176,7 @@ IP协议是TCP/IP体系中最主要的协议之一,一切在IP之下,一切 **注:** SYN为同步信息,在建立连接过程中始终为1 -####断开连接四次握手: +#### 断开连接四次握手: 1. 客户端请求断开连接: FIN=1,seq = u; 2. 服务端对客户端的请求应答:ACK=1,seq=v,ack=u+1; diff --git "a/Part4/OperatingSystem/\346\223\215\344\275\234\347\263\273\347\273\237.md" "b/Part4/OperatingSystem/\346\223\215\344\275\234\347\263\273\347\273\237.md" index f63b456..e78833d 100644 --- "a/Part4/OperatingSystem/\346\223\215\344\275\234\347\263\273\347\273\237.md" +++ "b/Part4/OperatingSystem/\346\223\215\344\275\234\347\263\273\347\273\237.md" @@ -1,4 +1,4 @@ -#OS +# OS **进程和线程** diff --git "a/Part5/ReadingNotes/\343\200\212APP\347\240\224\345\217\221\345\275\225\343\200\213\347\254\2541\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" "b/Part5/ReadingNotes/\343\200\212APP\347\240\224\345\217\221\345\275\225\343\200\213\347\254\2541\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" index f8c335e..75d7efc 100755 --- "a/Part5/ReadingNotes/\343\200\212APP\347\240\224\345\217\221\345\275\225\343\200\213\347\254\2541\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" +++ "b/Part5/ReadingNotes/\343\200\212APP\347\240\224\345\217\221\345\275\225\343\200\213\347\254\2541\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" @@ -1,7 +1,7 @@ -#《APP研发录》读书笔记 +# 《APP研发录》读书笔记 --- -##第一章 -###1.1重新规划Android项目结构 +## 第一章 +### 1.1重新规划Android项目结构 重新规划Android项目的目录结构,分两步走: @@ -26,7 +26,7 @@ * interfaces:真正意义上的接口,命名以I作为开头 * listener:基于Listener的接口,命名以On作为开头 -###1.2为Activity定义新的生命周期 +### 1.2为Activity定义新的生命周期 可以把onCreate方法拆成三个子方法 @@ -34,13 +34,13 @@ * initViews:加载layout布局文件,初始化控件,为控件挂上事件方法 * loadData:调用MobileAPI获取数据 -###1.3统一事件编程模型 +### 1.3统一事件编程模型 只要在一个团队内部达成了协议,决定使用某种事件编程方式,所有开发人员就要按照同样的方式编写代码。 -###1.4实体化编程 +### 1.4实体化编程 -####1.4.1在网络请求中使用实体 +#### 1.4.1在网络请求中使用实体 一些开发人员不使用实体化编程,在获取MobileAPI网络请求返回的JSON数据时,使用JSONObject或者JSONArray来承载数据,然后把返回的数据当作一个字典,根据键取出响应的值。介绍fastJSON和GSON这种实体化编程的方式. @@ -70,7 +70,7 @@ Gson gson = new Gson(); } ``` -####1.4.3在页面跳转中实现实体 +#### 1.4.3在页面跳转中实现实体 在一个页面中,数据的来源有两种: 1. 调用MobileAPI获取JSON数据 @@ -170,7 +170,7 @@ public class CinemaBean implements Serializable { ``` -###1.5Adapter模版 +### 1.5Adapter模版 不对Adapter的写法进行规范,就会写出以下的Adapter * 很多开发人员都喜欢将Adapter内嵌在Activity中,一般会使用SimpleAdapter @@ -268,7 +268,7 @@ public View getView(final int position, View convertView, } ``` -###1.6类型安全转换函数 +### 1.6类型安全转换函数 在每天统计线上崩溃的时候,我们发现因为类型转换不正确导致的崩溃占了很大的比例。于是去检查程序中的所有类型转换,发现主要集中在两个地方:Object类型的对象,substring函数。 diff --git "a/Part5/ReadingNotes/\343\200\212APP\347\240\224\345\217\221\345\275\225\343\200\213\347\254\2542\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" "b/Part5/ReadingNotes/\343\200\212APP\347\240\224\345\217\221\345\275\225\343\200\213\347\254\2542\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" index ac8a7aa..9d4400c 100644 --- "a/Part5/ReadingNotes/\343\200\212APP\347\240\224\345\217\221\345\275\225\343\200\213\347\254\2542\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" +++ "b/Part5/ReadingNotes/\343\200\212APP\347\240\224\345\217\221\345\275\225\343\200\213\347\254\2542\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" @@ -1,4 +1,4 @@ -#APP研发录第二章笔记 +# APP研发录第二章笔记 --- * 抛弃AsyncTask,自定义一套网络底层的封装框架。 @@ -6,20 +6,20 @@ * 设计一套MockService的机制,在没有MobileAPI的时候,也能假装获取到了网络返回的数据。 * 封装了用户Cookie的逻辑。 -##2.1 网络底层封装 +## 2.1 网络底层封装 很多公司和团队都是用AsyncTask来封装网络底层,因为这个类非常好用,内部封装了很多好用的方法,但缺点是可扩展性不高。 对于网络请求,我们一般定义为GET和POST即可,GET为请求数据,POST为修改数据(增删改)。 -###1.Request格式 +### 1.Request格式 所有的MobileAPI都可以写作http://www.xxx.com/aaaa.api的形式。 * 对于GET,我们可以写作:http://www.xxx.com/aaaa.api?k1=va&k2=v2的形式,也就是说,把key-value这样的键值对存放在URL上。之所以这样设计,是为了更方便地定义数据缓存。我们尽量使GET的参数都是string、int这样的简单类型。 * 对于POST,我们将key-value这样的键值对存放在Form表单中,进行提交。POST经常会提交大量数据,所以有些键值对要定义成集合或者复杂的自定义实体,这时我们就需要将这样的值转换为JSON字符串进行提交,由App传递到MobileAPI后,再将JSON字符串转换为对应的实体。 -###2.Response格式 +### 2.Response格式 我们一般使用JSON作为MobileAPI返回的结果。最规范的JSON数据返回格式如下。 JSON数据格式1: @@ -101,7 +101,7 @@ public class Response } ``` -####2.1.2 AsyncTask的使用和缺点 +#### 2.1.2 AsyncTask的使用和缺点 对AsyncTask的封装属于网络底层的技术,所以AsyncTask应该封装在AndroidLib类库中,而不是具体的项目里。 对网络异常的分类,也就是Response类中的errorType字段,分析如下: @@ -209,7 +209,7 @@ protected void loadData() { 如果你不信,我们可以做个试验。记录每次MobileAPI请求发起和接收数据的时间点,你会看到,在迅速进入二级页面后,首页的十几个MobileAPI请求只有发起时间并没有返回时间,说明它们还在处理过程中,都被堵塞了。 -####2.1.3 使用原生的ThreadPoolExcutor+Runnable+Handler +#### 2.1.3 使用原生的ThreadPoolExcutor+Runnable+Handler 既然AsyncTask有诸多问题,那么退而求其次,使用ThreadPoolExecutor+Runnable+Handler的原生方式,对网络底层进行封装。 @@ -217,7 +217,7 @@ protected void loadData() { [《App研发录》 源码](http://www.cnblogs.com/Jax/p/4656789.html) -####2.1.4 网络底层的一些优化工作 +#### 2.1.4 网络底层的一些优化工作 接下来将完善这个框架,修复其中的一些瑕疵,如onFail的统一处理机制、UrlConfigManager的优化、ProgressBar的处理等。 @@ -423,11 +423,11 @@ void loadAPIData1() { 不要把Dialog的show方法和dismiss方法封装到网络底层。网络底层的调用经常是在子线程执行的,子线程是不能操作Dialog、Toast和控件的。 -###2.2 App数据缓存设计 +### 2.2 App数据缓存设计 如果以为上一节内容就是网络底层框架的全部,那就错了。那只是网络底层框架的最核心的功能,我们还有很多高级功能没有介绍。在接下来的几节中,我将陆续介绍到这些高级功能。本节先介绍App本地的缓存策略。 -####2.2.1 数据缓存策略 +#### 2.2.1 数据缓存策略 对于任何一款应用类App,如果访问MobileAPI的速度和牛车一样慢,那么就是失败之作。不要在WiFi下测试速度,那是自欺欺人,要把App放在2G或3G网络环境下进行测试,才能得到大部分用户的真实数据。 @@ -521,7 +521,7 @@ public class YoungHeartApplication extends Application { } ``` -####2.2.2 强制更新 +#### 2.2.2 强制更新 不光是App端需要记录缓存数据,在MobileAPI的很多接口,其实也需要一样的设计。 @@ -564,7 +564,7 @@ RemoteService.getInstance().invoke( weatherCallback); ``` -###2.3 MockService +### 2.3 MockService 设计App端MockService包括如下几个关键点: @@ -649,9 +649,9 @@ public void invoke(final BaseActivity activity, } ``` -###2.4 用户登录 +### 2.4 用户登录 -####2.4.1 登录成功后的各种场景 +#### 2.4.1 登录成功后的各种场景 首先,贯穿App的,应该有一个User全局变量,在每次登录成功后,会将其isLogin属性设置为true,在退出登录后,则将该属性设置为false。这个User全局变量要支持序列化到本地的功能,这样数据才不会因内存回收而丢失。 @@ -757,7 +757,7 @@ RequestCallback loginCallback = new AbstractRequestCallback() { 我们看到,对于情形2,当用户在LoginMainActivity点击按钮想跳转到NewsActivity,如果已经登录,就直接跳转过去;否则,先到LoginActivity登录,然后回调LoginMain-Activity的onActivityResult,仍然跳转到NewsActivity。 -####2.4.2 自动登录 +#### 2.4.2 自动登录 所谓自动登录,就是登录成功后,重启App后用户仍然是登录状态。 @@ -862,7 +862,7 @@ public synchronized void saveCookie() { * 用户注册功能,一般在注册成功后,都会拿着用户名和密码再调用一次登录接口,这就又和验证码功能冲突了,解决方案是注册成功后直接跳转到登录页面,让用户手动再输入一次。这是从产品层面来解决问题。另一种解决方案是,注册成功后进入个人中心页面,不需要再登录一次,而是把注册和登录接口绑在一起。 * 对于Cookie过期,App应该跳转到登录页面,让用户手动进行登录。这里有一个比较有挑战性的工作,就是登录成功后,应该返回手动登录之前的那个页面。我们在下一节再细说这个技术。 -####2.4.3 Cookie过期的统一处理 +#### 2.4.3 Cookie过期的统一处理 Cookie不是一直有效的,到了一定时间就会失效。 @@ -936,16 +936,16 @@ public void onCookieExpired() { } ``` -####2.4.4 防止黑客刷库 +#### 2.4.4 防止黑客刷库 * MobileAPI在发现有同一IP短时间内频繁访问某一个MobileAPI接口时,就直接返回一段HTML5,要求用户输入验证码。 * App在接收到这段代码时,就在页面上显示一个浮层,里面一个WebView,显示这个要求用户输入验证码的HTML5。 -###2.5 HTTP头中的奥妙 +### 2.5 HTTP头中的奥妙 -####2.5.1 HTTP请求 +#### 2.5.1 HTTP请求 HTTP请求分为HTTPRequest和HTTPResponse两种。但无论哪种请求,都由header和body两部分组成。 @@ -1045,7 +1045,7 @@ response = httpClient.execute(request); 前面我们介绍过Cookie,其实也是HTTP头的一部分。它的作用我们已经见识过了。下面将讨论HTTP头中的另几个重要字段。 -####2.5.2 时间校准 +#### 2.5.2 时间校准 接下来要介绍的是HTTP Response头中另一重要属性:Date,这个属性中记录了MobileAPI当时的服务器时间。 @@ -1129,7 +1129,7 @@ btnShowTime.setOnClickListener(new View.OnClickListener() { }); ``` -####2.5.3 开启gzip压缩 +#### 2.5.3 开启gzip压缩 HTTP协议上的gzip编码是一种用来改进Web应用程序性能的技术。大流量的Web站点常常使用gzip压缩技术来减少传输量的大小,减少传输量大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输时,可以减少传输的时间。 diff --git "a/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\344\270\200\347\253\240\347\254\224\350\256\260.md" "b/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\344\270\200\347\253\240\347\254\224\350\256\260.md" index c440343..7bddcd6 100644 --- "a/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\344\270\200\347\253\240\347\254\224\350\256\260.md" +++ "b/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\344\270\200\347\253\240\347\254\224\350\256\260.md" @@ -1,4 +1,4 @@ -#《Android开发艺术探索》第一章笔记 +# 《Android开发艺术探索》第一章笔记 --- 注:此篇笔记只记录重难点,对于基础和详细内容请自行学习《Android开发艺术探索》。 diff --git "a/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\344\270\211\347\253\240\347\254\224\350\256\260.md" "b/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\344\270\211\347\253\240\347\254\224\350\256\260.md" index c19a533..669e006 100644 --- "a/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\344\270\211\347\253\240\347\254\224\350\256\260.md" +++ "b/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\344\270\211\347\253\240\347\254\224\350\256\260.md" @@ -1,6 +1,6 @@ -#《Android开发艺术探索》第三章笔记 +# 《Android开发艺术探索》第三章笔记 --- -##View的基础知识 +## View的基础知识 * 什么是View @@ -112,7 +112,7 @@ VelocityTracker的使用方式: 弹性滑动对象,用于实现View的弹性滑动。Scroller本身无法让View弹性滑动,它需要和View的computeScroll方法配合使用才能共同完成这个功能。 -##View的滑动 +## View的滑动 通过三种方式可以实现View的滑动 @@ -137,7 +137,7 @@ scrollTo和scrollBy方法只能改变view内容的位置而不能改变view在 动画兼容库nineoldandroids中的ViewHelper类提供了很多的get/set方法来为属性动画服务,例如setTranslationX和setTranslationY方法,这些方法是没有版本要求的。 -##弹性滑动 +## 弹性滑动 1、使用Scroller Scroller的工作原理:Scroller本身并不能实现view的滑动,它需要配合view的computeScroll方法才能完成弹性滑动的效果,它不断地让view重绘,而每一次重绘距滑动起始时间会有一个时间间隔,通过这个时间间隔Scroller就可以得出view的当前的滑动位置,知道了滑动位置就可以通过scrollTo方法来完成view的滑动。就这样,view的每一次重绘都会导致view进行小幅度的滑动,而多次的小幅度滑动就组成了弹性滑动,这就是Scroller的工作原理。 @@ -148,7 +148,7 @@ Scroller的工作原理:Scroller本身并不能实现view的滑动,它需要 3、使用延时策略 使用延时策略来实现弹性滑动,它的核心思想是通过发送一系列延时消息从而达到一种渐进式的效果,具体来说可以使用Handler的sendEmptyMessageDelayed(xxx)或view的postDelayed方法,也可以使用线程的sleep方法。 -##View的事件分发机制 +## View的事件分发机制 1、事件分发机制的三个重要方法 @@ -185,7 +185,7 @@ Scroller的工作原理:Scroller本身并不能实现view的滑动,它需要 我们可以大致了解点击事件的传递规则:对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,这时它的dispatchTouchEvent会被调用,如果这个ViewGroup的onInterceptTouchEvent方法返回true就表示它要拦截当前事件,接着事件就会交给这个ViewGroup处理,即它的onTouchEvent方法就会被调用;如果这个ViewGroup的onInterceptTouchEvent方法返回false就表示它不拦截当前事件,这时当前事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvent方法就会被调用,如此反复直到事件被最终处理。 -####OnTouchListener的优先级比onTouchEvent要高 +#### OnTouchListener的优先级比onTouchEvent要高 如果给一个view设置了OnTouchListener,那么OnTouchListener中的onTouch方法会被回调。这时事件如何处理还要看onTouch的返回值,如果返回false,那么当前view的onTouchEvent方法会被调用;如果返回true,那么onTouchEvent方法将不会被调用。 在onTouchEvent方法中,如果当前view设置了OnClickListener,那么它的onClick方法会被调用,所以OnClickListener的优先级最低。 @@ -204,7 +204,7 @@ Scroller的工作原理:Scroller本身并不能实现view的滑动,它需要 * View的enable属性不影响onTouchEvent的默认返回值,哪怕一个View是disable状态的,只要它的clickable或者longClickable有一个为true,那么它的onTouchEvent就返回true * 事件传递过程总是先传递给父元素,然后再由父元素分发给子view,通过requestDisallowInterceptTouchEvent方法可以在子元素中干预父元素的事件分发过程,但是ACTION_DOWN事件除外,即当面对ACTION_DOWN事件时,ViewGroup总是会调用自己的onInterceptTouchEvent方法来询问自己是否要拦截事件。 -##View的滑动冲突 +## View的滑动冲突 1、常见的滑动冲突场景 diff --git "a/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\344\272\214\347\253\240\347\254\224\350\256\260.md" "b/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\344\272\214\347\253\240\347\254\224\350\256\260.md" index 1118951..a110887 100644 --- "a/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\344\272\214\347\253\240\347\254\224\350\256\260.md" +++ "b/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\344\272\214\347\253\240\347\254\224\350\256\260.md" @@ -1,24 +1,24 @@ -##《Android开发艺术探索》第二章笔记 +## 《Android开发艺术探索》第二章笔记 --- -##IPC +## IPC * Inter-Process Communication的缩写。含义为进程间通信或跨进程通信,是指两个进程之间进行数据交换的过程。 -##进程和线程的区别 +## 进程和线程的区别 * 按照操作系统的描述,线程是CPU调度的最小单元,同时线程是一种有限的系统资源。 * 进程一般指一个执行单元,在PC和移动设备上指一个程序或者一个应用。一个进程可以包含多个线程,因此进程和线程是包含与被包含的关系。 -##多进程分为两种 +## 多进程分为两种 * 第一种情况是一个应用因为某些原因自身需要采用多线程模式来实现。 * 另一种情况是当前应用需要向其他应用获取数据 -##Android中的多进程模式 +## Android中的多进程模式 通过给四大组件指定android:process属性,我们可以开启多线程模式 * 进程名以":"开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一进程,而进程名不以":"开头的进程属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中。 * Android系统会为每个应用分配一个唯一的UID,具有相同UID的应用才能共享数据,两个应用通过ShareUID跑在同一个进程中是有要求的,需要这两个应用有相同的ShareUID并且签名相同才可以。在这种情况下,它们可以互相访问对方的私有数据,比如data目录、组件信息等,不管它们是否跑在同一个进程中。当然如果它们跑在同一个进程中,那么除了能共享data目录、组件信息,还可以共享内存数据,或者说它们看起来就像是一个应用的两个部分。 -##多进程模式的运行机制 +## 多进程模式的运行机制 * Android为每一个应用分配了一个独立的虚拟机,或者说为每个进程都分配了一个独立的虚拟机,不同的虚拟机在不同的内存分配上有不同的地址空间,这就导致在不同的虚拟机中访问同一个类的对象会产生多份副本。 * 所有运行在不同进程中的四大组件,只要它们之间需要通过内存来共享数据,都会共享失败。 @@ -38,7 +38,7 @@ SharedPreferences不支持两个进程同时去执行写操作,否则会导致 运行在同一个进程中的组件是属于同一个虚拟机和同一个Application的。同理,运行在不同进程中的组件是属于两个不同的虚拟机和Application的。 -##IPC基础概念介绍 +## IPC基础概念介绍 * Serializable 是Java所提供的一个序列化接口,它是一个空接口,为对象提供标准的序列化和反序列化操作。使用Serializable来实现序列化相当简单,只需要在类的声明中指定一个类似下面的标识即可自动实现默认的序列化过程。 @@ -72,7 +72,7 @@ in.close(); * 其次用transient关键字标记的成员变量不参与序列化过程 -##Parcelable接口 +## Parcelable接口 Parcelable也是一个接口,只要实现这个接口,一个类的对象就可以实现序列化并可以通过Intent的Binder传递 Parcelable的方法说明: @@ -87,11 +87,11 @@ Parcelable的方法说明: * 系统已经为我们提供了许多实现了Parcelable接口的类,它们都是可以直接序列化的,比如Intent、Bundle、Bitmap等,同时List和Map也可以序列化,前提是它们里面的每个元素都是可序列化的。 -##如何选取 +## 如何选取 Serializable是Java中的序列化接口,其使用起来简单但是开销很大,序列化和反序列化需要大量I/O操作。而Parceleble是Android中的序列化方式,因此更适合在Android平台上,缺点是麻烦,但是效率高,这是Android推荐的序列化方式,所以我们要首选Parcelable。Parcelable主要用在内存序列化上,通过Parcelable将对象序列化到存储设备中或者将对象序列化之后通过网络传输,但是过程稍显复杂,因此在这两种情况下建议大家使用Serializable。 -##Binder +## Binder * 继承了IBinder接口 * Binder是一种跨进程通信方式 * 是ServiceManager连接各种Manager(ActivityManager,WindowManager等)和相应ManagerService的桥梁 @@ -105,15 +105,15 @@ aidl工具根据aidl文件自动生成的java接口的解析:首先,它声 * onTransact:这个方法运行在服务端中的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。 这个方法的原型是public Boolean onTransact(int code, Parcelable data, Parcelable reply, int flags) 服务端通过code可以知道客户端请求的目标方法,接着从data中取出所需的参数,然后执行目标方法,执行完毕之后,将结果写入到reply中。如果此方法返回false,说明客户端的请求失败,利用这个特性可以做权限验证(即验证是否有权限调用该服务)。 -* Proxy#[Method]:代理类中的接口方法,这些方法运行在客户端,当客户端远程调用此方法时,它的内部实现是:首先创建该方法所需要的参数,然后把方法的参数信息写入到_data中,接着调用transact方法来发起RPC请求,同时当前线程挂起;然后服务端的onTransact方法会被调用,直到RPC过程返回后,当前线程继续执行,并从_reply中取出RPC过程的返回结果,最后返回_reply中的数据。 +* Proxy# [Method]:代理类中的接口方法,这些方法运行在客户端,当客户端远程调用此方法时,它的内部实现是:首先创建该方法所需要的参数,然后把方法的参数信息写入到_data中,接着调用transact方法来发起RPC请求,同时当前线程挂起;然后服务端的onTransact方法会被调用,直到RPC过程返回后,当前线程继续执行,并从_reply中取出RPC过程的返回结果,最后返回_reply中的数据。 -######首先,当客户端发起远程请求时,由于当前线程会被挂起直至服务端进程返回数据,所以如果一个远程方法是很耗时的,那么不能在UI线程发起此远程请求;其次,由于服务端的Binder方法运行在Binder的线程池中,所以不管Binder是否耗时都应该采用同步的方式去实现,因为它已经运行在一个线程中了。 +###### 首先,当客户端发起远程请求时,由于当前线程会被挂起直至服务端进程返回数据,所以如果一个远程方法是很耗时的,那么不能在UI线程发起此远程请求;其次,由于服务端的Binder方法运行在Binder的线程池中,所以不管Binder是否耗时都应该采用同步的方式去实现,因为它已经运行在一个线程中了。 -###Binder两种重要的方法 +### Binder两种重要的方法 1. linkToDeath 2. unlinkToDeath Binder运行在服务端,如果由于某种服务端异常终止了的话会导致客户端的远程调用失败、所以Binder提供了两个配对的方法linkToDeath和unlinkToDeath,通过linkToDeath方法可以给Binder设置一个死亡代理,当Binder死亡的时候客户端就会收到通知,然后就可以重新发起连接从而恢复连接了。 -###如何给Binder设置死亡代理 +### 如何给Binder设置死亡代理 1、声明一个DeathRecipient对象、DeathRecipient是一个接口,其内部只有一个方法bindDied,实现这个方法就可以在Binder死亡的时候收到通知了。 ``` @@ -138,7 +138,7 @@ mRemoteBookManager.asBinder().linkToDeath(mDeathRecipient, 0); ``` -##Android的IPC方式 +## Android的IPC方式 1、 使用Bundle @@ -176,12 +176,12 @@ Messenger是一种轻量级的IPC方案,它的底层实现就是AIDL。Messeng * TCP协议是面向连接的协议,提供稳定的双向通信功能,TCP连接的建立需要经过"三次握手"才能完成,为了提供稳定的数据传输功能,其本身提供了超时重传功能,因此具有很高的稳定性 * UDP是无连接的,提供不稳定的单向通信功能,当然UDP也可以实现双向通信功能,在性能上,UDP具有更好的效率,其缺点是不保证数据能够正确传输,尤其是在网络拥塞的情况下。 -##Binder连接池 +## Binder连接池 * 当项目规模很大的时候,创建很多个Service是不对的做法,因为service是系统资源,太多的service会使得应用看起来很重,所以最好是将所有的AIDL放在同一个Service中去管理。整个工作机制是:每个业务模块创建自己的AIDL接口并实现此接口,这个时候不同业务模块之间是不能有耦合的,所有实现细节我们要单独开来,然后向服务端提供自己的唯一标识和其对应的Binder对象;对于服务端来说,只需要一个Service,服务端提供一个queryBinder接口,这个接口能够根据业务模块的特征来返回相应的Binder对象给它们,不同的业务模块拿到所需的Binder对象后就可以进行远程方法调用了。 Binder连接池的主要作用就是将每个业务模块的Binder请求统一转发到远程Service去执行,从而避免了重复创建Service的过程。 * 建议在AIDL开发工作中引入BinderPool机制。 -##选用合适的IPC方式 +## 选用合适的IPC方式 ![Mou icon](http://hujiaweibujidao.github.io/images/androidart_ipc.png) diff --git "a/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\345\205\253\347\253\240\347\254\224\350\256\260.md" "b/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\345\205\253\347\253\240\347\254\224\350\256\260.md" index 965b77d..6349dfc 100644 --- "a/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\345\205\253\347\253\240\347\254\224\350\256\260.md" +++ "b/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\345\205\253\347\253\240\347\254\224\350\256\260.md" @@ -1,8 +1,8 @@ -##理解Window和WindowManager +## 理解Window和WindowManager Window是一个抽象类,它的具体实现是PhoneWindow。WindowManager是外界访问Window的入口,Window的具体实现位于WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC过程。Android中所有的视图都是通过Window来呈现的,不管是Activity、Dialog还是Toast,它们的视图实际上都是附加在Window上的,因此Window实际是View的直接管理者。 -###8.1 Window和WindowManager +### 8.1 Window和WindowManager 为了分析Window的工作机制,先通过代码了解如何使用WindowManager添加一个Window,下面一段代码将一个Button添加到屏幕坐标为(100, 300)的位置上 @@ -45,11 +45,11 @@ mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR WindowManager所提供的功能很简单,常用的只有三个方法,即添加View、更新View和删除View,这三个方法定义在ViewManager中,而WindowManager继承了ViewManager。 -###8.2 Window的内部机制 +### 8.2 Window的内部机制 Window是一个抽象的概念,并不是实际存在的,它是以View的形式存在,每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系。在实际使用中无法直接访问Window,对Window的访问必须通过WindowManager。 -####8.2.1 Window的添加过程 +#### 8.2.1 Window的添加过程 Window的添加过程需要通过WindowManager的addView来实现,WindowManager是一个接口,它的真正实现是WindowManagerImpl类。WindowManager的实现类对于addView、updateView和removeView方法都是委托给WindowManagerGlobal类。 @@ -59,7 +59,7 @@ WindowManagerGlobal的addView方法分为如下几步: 2. 创建ViewRootImpl并将View添加到列表中 3. 通过ViewRootImpl来更新界面并完成Window的添加过程 -####8.2.2 Window的删除过程 +#### 8.2.2 Window的删除过程 和添加过程一样,都是先通过WindowManagerImpl后,再进一步通过WindowManagerGlobal来实现的。 真正删除View的逻辑在dispatchDetachedFromWindow方法的内部实现。dispatchDetachedFromWindow方法主要做四件事: @@ -69,13 +69,13 @@ WindowManagerGlobal的addView方法分为如下几步: 3. 调用View的dispatchDetachedFromWindow方法,在内部调用View的onDetachedFromWindow()以及onDetachedFromWindowInternal()。 4. 调用WindowManagerGlobal的doRemoveView方法刷新数据,包括mRoots、mParams以及mDyingViews,需要将当前Window所关联的这三类对象从列表中删除。 -####8.2.3 Window的更新过程 +#### 8.2.3 Window的更新过程 首先需要更新View的LayoutParams并替换掉老的LayoutParams,接着再更新ViewRootImpl中的LayoutParams,这一步是通过ViewRootImpl的setLayoutParams方法来实现的。在ViewRootImpl中会通过scheduleTrversals方法来对View重新布局,包括测量、布局、重绘三个过程。除了View本身的重绘以外,ViewRootImpl还会通过WindowSession来更新Window的视图,这个过程最终是由WindowManagerService的relayoutWindow()来具体实现的,同样是一个IPC过程。 -##Window的创建过程 +## Window的创建过程 -###8.3.1 Activity的Window创建过程 +### 8.3.1 Activity的Window创建过程 1、Activity的启动过程很复杂,最终会由ActivityThread中的performLaunchActivity()来完成整个启动过程,在这个方法内部会通过类加载器创建Activity的实例对象,并调用其attach方法为其关联运行过程中所依赖的一系列上下文环境变量。 @@ -88,7 +88,7 @@ PhoneWindow方法大致遵循如下几个步骤: 2. 将View添加到DecorView的mContentParent中 3. 回调Activity的onCreateChanged方法通知Activity视图已经发生改变 -###8.3.2 Dialog的Window创建过程 +### 8.3.2 Dialog的Window创建过程 Dialog的Window的创建过程和Activity类似,有如下步骤: @@ -96,7 +96,7 @@ Dialog的Window的创建过程和Activity类似,有如下步骤: 2. 初始化DecorView并将Dialog的视图添加到DecorView中 3. 将DecorView添加到Window中并显示:普通的Dialog有一个特殊之处,就是必须采用Activity的Context,如果采用Application的Context,那么就会报错。应用token只有Activity拥有,所以这里只需要Activity作为Context来显示对话框即可。 -###8.3.3 Toast的Window创建过程 +### 8.3.3 Toast的Window创建过程 在Toast的内部有两类IPC过程,第一类是Toast访问NotificationManagerService,第二类是NotificationManagerService回调Toast里的TN接口。 diff --git "a/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\345\215\201\344\272\224\347\253\240\347\254\224\350\256\260.md" "b/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\345\215\201\344\272\224\347\253\240\347\254\224\350\256\260.md" index fa1b41a..85128e8 100644 --- "a/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\345\215\201\344\272\224\347\253\240\347\254\224\350\256\260.md" +++ "b/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\345\215\201\344\272\224\347\253\240\347\254\224\350\256\260.md" @@ -1,8 +1,8 @@ -#Android性能优化 +# Android性能优化 --- Android不可能无限制的使用内存和CPU资源,过多的使用内存会导致内存溢出,即OOM。而过多的使用CPU资源,一般是指做大量的耗时任务,会导致手机变的卡顿甚至出现程序无法响应的情况,即ANR。 -###15.1.1布局优化 +### 15.1.1布局优化 1、如何进行布局优化? @@ -36,7 +36,7 @@ Android不可能无限制的使用内存和CPU资源,过多的使用内存会 View importPanel = ((ViewStub)findViewById(R.id.stub_import)).inflate(); ``` -###15.1.1绘制优化 +### 15.1.1绘制优化 绘制优化是指View的onDraw方法要避免执行大量的操作: @@ -44,26 +44,26 @@ View importPanel = ((ViewStub)findViewById(R.id.stub_import)).inflate(); * onDraw方法中不要指定耗时任务,也不能执行成千上万次的循环操作,View的绘制帧率保证60fps是最佳的,这就要求每帧的绘制时间不超过16ms,虽然程序很难保证16ms这个时间,但是尽量降低onDraw方法的复杂度总是切实有效的。 -###15.1.3内存泄漏优化 +### 15.1.3内存泄漏优化 可能导致内存泄漏的场景很多,例如静态变量、单例模式、属性动画、AsyncTask、Handler等等 -###15.1.4响应速度优化和ANR日志分析 +### 15.1.4响应速度优化和ANR日志分析 1. ANR出现的情况:Activity如果5秒内没有响应屏幕触摸事件或者键盘输入事件就会ANR。而BroadcastReceiver如果10s没有执行完操作也会出现ANR。 2. 当一个进程发生了ANR之后,系统会在/data/anr目录下创建一个文件traces.txt,通过分析这个文件就能定位ANR的原因。 -###15.1.5ListView和Bitmap优化 +### 15.1.5ListView和Bitmap优化 1. ListView优化:采用ViewHolder并避免在getView方法中执行耗时操作;根据列表的滑动状态来绘制任务的执行效率;可以尝试开启硬件加速期来使ListView的滑动更加流畅。 2. Bitmap优化:根据需要对图片进行采样,主要是通过BitmapFactory.Options来根据需要对图片进行采样,采样主要用到了BitmapFactory.Options的inSampleSize参数。 -###15.1.6线程优化 +### 15.1.6线程优化 1. 采用线程池,避免程序中存在大量的Thread。线程池可以重用内部的线程,从而避免了线程的创建和销毁所带来的性能开销,同时线程池还能有效的控制线程池的最大并发数,避免大量的线程因互相抢占系统资源从而导致阻塞现象的发生。 -###15.1.7一些性能优化建议 +### 15.1.7一些性能优化建议 * 避免 创建过多的对象 * 不要过多的使用枚举,枚举占用的内存空间要比整形大 @@ -74,12 +74,12 @@ View importPanel = ((ViewStub)findViewById(R.id.stub_import)).inflate(); * 尽量采用静态内部类,这样可以避免潜在的由于内部类而导致的内存泄漏 -###15.2内存泄漏分析之MAT工具 +### 15.2内存泄漏分析之MAT工具 MAT是功能强大的内存分析工具,主要有Histograms和Dominator Tree等功能 -###15.3提高程序的可维护性 +### 15.3提高程序的可维护性 1. 命名要规范,要能正确地传达出变量或者方法的含义,少用缩写,关于变量的前缀可以参考Android源码的命名方式,比如私有成员以m开头,静态成员以s开头,常量则全部用大写字母表示,等等。 2. 代码的排版上需要留出合理的空白来区分不同的代码块,其中同类变量的声明要放在一起,两类变量之间要留出一行空白作为区分。 diff --git "a/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\345\233\233\347\253\240\347\254\224\350\256\260.md" "b/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\345\233\233\347\253\240\347\254\224\350\256\260.md" index 8eea44a..81b0b29 100644 --- "a/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\345\233\233\347\253\240\347\254\224\350\256\260.md" +++ "b/Part5/ReadingNotes/\343\200\212Android\345\274\200\345\217\221\350\211\272\346\234\257\346\216\242\347\264\242\343\200\213\347\254\254\345\233\233\347\253\240\347\254\224\350\256\260.md" @@ -1,7 +1,7 @@ -##View的工作原理 +## View的工作原理 --- -###4.1 初识ViewRoot和DecorView +### 4.1 初识ViewRoot和DecorView 1、ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRoot来完成的。在ActivityThread中,当Activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立连接。 @@ -13,7 +13,7 @@ 5、DecorView其实是一个FrameLayout,其中包含了一个竖直方向的LinearLayout,上面是标题栏,下面是内容栏(id为android.R.id.content)。View层的事件都先经过DecorView,然后才传给我们的View。 -###理解MeasureSpec +### 理解MeasureSpec 1、MeasureSpec通过将SpecMode和SpecSize打包成一个int值来避免过多的内存分配,为了方便操作,其提供了打包和解包方法。SpecMode和SpecSize也是一个int值,一组SpecMode和SpecSize可以打包为一个MeasureSpec,而一个MeasureSpec可以通过解包的形式来得出其原始的SpecMode和SpecSize。 @@ -33,11 +33,11 @@ MeasureSpec不是唯一由LayoutParams决定的,LayoutParams需要和父容器 当view的宽高是match_parent时,如果父容器的模式是精确模式,那么view也是精确模式,并且大小是父容器的剩余空间;如果父容器是最大模式,那么view也是最大模式,并且大小是不会超过父容器的剩余空间。 当view的宽高是wrap_content时,不管父容器的模式是精确模式还是最大模式,view的模式总是最大模式,并且大小不超过父容器的剩余空间。 -###4.3 View的工作流程 +### 4.3 View的工作流程 1、View的measure过程和Activity的生命周期方法不是同步执行的,因此无法保证Activity执行了onCreate、onStart、onResume时某个View已经测量完毕了。如果View还没有测量完毕,那么获得的宽和高都是0。下面是四种解决该问题的方法: -* Activity/View#onWindowsChanged方法 +* Activity/View# onWindowsChanged方法 onWindowFocusChanged方法表示View已经初始化完毕了,宽高已经准备好了,这个时候去获取是没问题的。这个方法会被调用多次,当Activity继续执行或者暂停执行的时候,这个方法都会被调用。 @@ -88,7 +88,7 @@ view.measure(widthMeasureSpec, heightMeasureSpec); 3. 绘制children:dispatchDraw; 4. 绘制装饰:onDrawScrollBars -###4.4自定义View +### 4.4自定义View 作者将自定义View分为以下4类: @@ -102,7 +102,7 @@ view.measure(widthMeasureSpec, heightMeasureSpec); 1. 让View支持wrap_content 2. 如果有必要,让你的View支持padding 3. 尽量不要在View中使用Handler,没必要 -4. View中如果有线程或者动画,需要及时停止,参考View#onDetachedFromWindow +4. View中如果有线程或者动画,需要及时停止,参考View# onDetachedFromWindow 5. View带有滑动嵌套情形时,需要处理好滑动冲突 diff --git "a/Part5/ReadingNotes/\343\200\212Java\347\274\226\347\250\213\346\200\235\346\203\263\343\200\213\347\254\254\344\270\200\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" "b/Part5/ReadingNotes/\343\200\212Java\347\274\226\347\250\213\346\200\235\346\203\263\343\200\213\347\254\254\344\270\200\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" index 5ca464a..54441f7 100644 --- "a/Part5/ReadingNotes/\343\200\212Java\347\274\226\347\250\213\346\200\235\346\203\263\343\200\213\347\254\254\344\270\200\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" +++ "b/Part5/ReadingNotes/\343\200\212Java\347\274\226\347\250\213\346\200\235\346\203\263\343\200\213\347\254\254\344\270\200\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" @@ -1,6 +1,6 @@ -#《Java编程思想》第一章 +# 《Java编程思想》第一章 --- -##对象导论 +## 对象导论 封装 diff --git "a/Part5/ReadingNotes/\343\200\212Java\347\274\226\347\250\213\346\200\235\346\203\263\343\200\213\347\254\254\344\272\214\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" "b/Part5/ReadingNotes/\343\200\212Java\347\274\226\347\250\213\346\200\235\346\203\263\343\200\213\347\254\254\344\272\214\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" index b1b2838..7dc53c7 100644 --- "a/Part5/ReadingNotes/\343\200\212Java\347\274\226\347\250\213\346\200\235\346\203\263\343\200\213\347\254\254\344\272\214\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" +++ "b/Part5/ReadingNotes/\343\200\212Java\347\274\226\347\250\213\346\200\235\346\203\263\343\200\213\347\254\254\344\272\214\347\253\240\350\257\273\344\271\246\347\254\224\350\256\260.md" @@ -1,15 +1,15 @@ -#《Java编程思想第二章》 +# 《Java编程思想第二章》 --- -##一切都是对象 +## 一切都是对象 -###对象存放位置与生命周期 +### 对象存放位置与生命周期 C++创建的对象可以存放在栈、静态存储区与堆(heap)中,放在栈中的对象用完后不需手动释放,会自动销毁,但放在堆中的对象需手动释放,栈中的对象所需空间与生命周期都是确定的,堆中的对象内存分配是动态的,在运行时才知道需要多少内存以及生命周期,如果说在堆上创建对象,编译器就会对它的生命周期一无所知,C++就需要以编程的方式来确定何时销毁对象,这可能因不正确处理而导致内存泄漏,而Java则提供了自动垃圾回收机制。 Java对象的创建采用了动态内存分配策略,即创建的堆都是放在堆中的。 -###数据内存分配 +### 数据内存分配 寄存器——位于处理器内部,这是最快的存储区,大小极其有限,一般不能直接控制,但C和C++允许你向编译器建议寄存器分配方式。 @@ -30,7 +30,7 @@ Java字节码的执行有两种方式: 通常采用的是第二种方法。由于JVM规格描述具有足够的灵活性,这使得将字节码翻译为机器代码的工作具有较高的效率。对于那些对运行速度要求较高的应用程序,解释器可将Java字节码即时编译为机器码,从而很好地保证了Java代码的可移植性和高性能。 -###基本类型 +### 基本类型 void属于基本类型,但只能用来修饰方法,不能用来修饰变量。 @@ -48,7 +48,7 @@ BigInteger支持任意精度的整数,可表示任何大小的整数值。 BigDecimal支持任意精度的定点数,例如,可以用它进行精确的货币计算。 -###引用与对象生存周期 +### 引用与对象生存周期 ``` { @@ -60,11 +60,11 @@ BigDecimal支持任意精度的定点数,例如,可以用它进行精确的 引用s在作用域终点就消失了,然而,s指向的String对象继续占据内存,最后由垃圾回收器回收。 -###方法签名 +### 方法签名 方法名和参数列表(合起来被称为“方法签名”)唯一地标识出某个方法。 -###static修饰字段与方法的区别 +### static修饰字段与方法的区别 一个static字段对每个对象来说都只有一份空间,而非static字段则是对每个对象都有一个存储空间,但是如果static作用于某个方法时,差别却没有那么大,static方法的一个重要的用法就是在不创建任何对象的前提下就可以调用它,这一点对定义main()方法很重要,该方法是运行时程序的一个入口。 diff --git "a/Part5/ReadingNotes/\343\200\212\346\267\261\345\205\245\347\220\206\350\247\243java\350\231\232\346\213\237\346\234\272\343\200\213\347\254\25412\347\253\240.md" "b/Part5/ReadingNotes/\343\200\212\346\267\261\345\205\245\347\220\206\350\247\243java\350\231\232\346\213\237\346\234\272\343\200\213\347\254\25412\347\253\240.md" index 3ebcbf2..c8ebe15 100644 --- "a/Part5/ReadingNotes/\343\200\212\346\267\261\345\205\245\347\220\206\350\247\243java\350\231\232\346\213\237\346\234\272\343\200\213\347\254\25412\347\253\240.md" +++ "b/Part5/ReadingNotes/\343\200\212\346\267\261\345\205\245\347\220\206\350\247\243java\350\231\232\346\213\237\346\234\272\343\200\213\347\254\25412\347\253\240.md" @@ -1,15 +1,15 @@ -#深入理解Java虚拟机读书笔记 +# 深入理解Java虚拟机读书笔记 --- -###第12章 +### 第12章 -####主内存和工作内存 +#### 主内存和工作内存 java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。为了获得较好的执行效能,Java内存模型咩有并没有限制执行引擎使用处理器的特定寄存器或缓存来和主内存进行交互,也没有限制即时编译器调整代码执行顺序这类权利。 Java内存模型规定了所有的变量都存储在主内存中(Main Memory)中(此处的主内存和介绍物理硬件时的主内存名字一样,两者也可以互相类比,但此处仅是虚拟机内存的一部分)。每条线程还有自己的工作内存(Working Memory,可与前面所讲的处理器高速缓存类比),线程的工作内存中保存了该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取,赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同的线程也无法直接访问对方工作内存中的变量,线程间变量的传递需要通过主内存来完成,线程、主内存、工作内存的交互关系如图: ![这里写图片描述](http://img.blog.csdn.net/20160321091659271) -####内存间交互操作 +#### 内存间交互操作 关于主内存和工作内存之间具体的交互协议,即一个遍历那个如何从主内存拷贝到工作内存、如何从工作内存同步回主内存之类的实现细节,Java内存模型中定义了一下八种操作来完成: @@ -33,7 +33,7 @@ Java内存模型规定了所有的变量都存储在主内存中(Main Memory)中 * 如果一个变量事先没有被lock锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定住的变量。 * 对一个变量执行unlock操作之前,必须先把此变量同步回主内存中(执行store和write) -####对于volatile型变量的特殊规则 +#### 对于volatile型变量的特殊规则 当一个变量被定义成volatile之后,它将具备两种特性,第一是保证此变量对所有线程的可见性,这里的可见性是指当一条线程修改了这个变量的值,新值对于其他的线程是可以立即得知的。 由于volatile变量只能保证可见性,在不符合以下两条规则的运算场景中,我们仍然要通过加锁(使用synchronized或java.util.concurrent中的原子类)来保证原子性 @@ -43,13 +43,13 @@ Java内存模型规定了所有的变量都存储在主内存中(Main Memory)中 volatile变量读操作的性能消耗与普通变量几乎没有什么差别,但是写操作则可能会慢上一些,因为它需要在本地代码中插入许多内存屏障(Memory Barrier或Memory Fence)指令来保证处理器不发生乱序执行。不过即便如此,大多数场景volatile的总开销仍然要比锁来的低。 -####对于long和double型变量的特殊规则 +#### 对于long和double型变量的特殊规则 Java内存模型要求对于lock、unlock、read、load、assign、use、store和write这八个操作都具有原子性,但是对于64位的数据类型(long和double),允许虚拟机将没有被volatile修饰的64位数据的读写操作划分为两次32位的操作来进行,即允许虚拟机实现选择可以不保证64位数据类型的load、store、read和write这四个操作的原子性。 -####原子性、可见性与有序性 +#### 原子性、可见性与有序性 Java语言提供了volatile和synchronized两个关键字来保证线程之间操作的有序性,volatile关键字本生就包含了禁止指令重排序的语义,而synchronized则是由“一个变量在同一时刻只允许一条线程对其进行lock操作”这条规则获得的,这个规则决定了持有同一个锁的两个同步代码块只能串行的进入。 -####先行发生原则 +#### 先行发生原则 先行发生是Java内存模型中定义的两项操作之间的偏序关系,如果说操作A先行发生于操作B,其实就是说在发生操作B之前,操作A产生的影响能被操作B观察到,“影响”包括修改了内存中共享变量的值、发送了消息、调用了方法等。 以下是Java内存模型下一些天然的先行发生关系,这些关系无需任何同步器协助就已经存在。 @@ -63,7 +63,7 @@ Java语言提供了volatile和synchronized两个关键字来保证线程之间 * 对象终结规则(Finalizer Rule):一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始。 * 传递性(Transitivity):如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论。 -####线程的实现 +#### 线程的实现 线程是比进程更轻量级的调度执行单位,线程的引入,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件I/O等),又可以独立调度(线程是CPU调度的最基本单位)。 实现线程主要有三种方式: @@ -73,7 +73,7 @@ Java语言提供了volatile和synchronized两个关键字来保证线程之间 3. 混合实现 4. Java线程的实现 -####Java线程调度 +#### Java线程调度 线程调度是指系统为线程分配处理器使用权的过程,主要调度方式有两种,分别是协同式(Cooperative Threads-Scheduling)线程调度和抢占式(Preemptive Threads-Scheduling)线程调度。 使用协同式调度的多线程系统,线程的执行时间由线程本身来控制,线程把自己的工作执行完了之后,要主动通知系统切换到另外一个线程上去。协同式多线程的最大好处是实现简单,而且由于线程要把自己的事情干完后才会进行线程切换,切换操作对自己是可知的,所以没有什么线程同步的问题。坏处是线程执行时间不可控制,甚至如果一个线程编写有问题,一直不告知系统进行线程切换,那么程序就会一直阻塞在那里。 @@ -81,7 +81,7 @@ Java语言提供了volatile和synchronized两个关键字来保证线程之间 抢占式调度的多线程系统,那么每个线程将由系统来分配执行时间,线程的切换不由线程本身来决定(在Java中,Thread.yield()可以让出执行时间,但是要获取执行时间的话,线程本身是没有什么办法的)。在这种实现线程调度的方式下,线程的执行时间是系统可控的,也不会有一个线程导致整个进程阻塞的问题,Java使用的线程调度方式就是抢占式调度。 -####状态转换 +#### 状态转换 Java定义了5种进程状态 * 新建(New):创建后尚未启动的线程处于这种状态。 diff --git a/Part6/InterviewExperience/Alibaba.md b/Part6/InterviewExperience/Alibaba.md index 1f2b2b2..cdeb173 100644 --- a/Part6/InterviewExperience/Alibaba.md +++ b/Part6/InterviewExperience/Alibaba.md @@ -1,4 +1,4 @@ -#Alibaba +# Alibaba --- 一面 diff --git "a/Part6/InterviewExperience/\346\226\260\346\265\252\345\276\256\345\215\232.md" "b/Part6/InterviewExperience/\346\226\260\346\265\252\345\276\256\345\215\232.md" index 14e3358..fff5852 100644 --- "a/Part6/InterviewExperience/\346\226\260\346\265\252\345\276\256\345\215\232.md" +++ "b/Part6/InterviewExperience/\346\226\260\346\265\252\345\276\256\345\215\232.md" @@ -1,4 +1,4 @@ -#新浪微博 +# 新浪微博 --- 一面 --- @@ -84,7 +84,7 @@ View在UI线程中更新界面 tips:静态类持有Activity引用会导致内存泄露 -##二面 +## 二面 * service生命周期,可以执行耗时操作吗? * JNI开发流程 diff --git "a/Part6/InterviewExperience/\347\275\221\346\230\223\346\235\255\347\240\224.md" "b/Part6/InterviewExperience/\347\275\221\346\230\223\346\235\255\347\240\224.md" index 0038f5b..4d006f1 100644 --- "a/Part6/InterviewExperience/\347\275\221\346\230\223\346\235\255\347\240\224.md" +++ "b/Part6/InterviewExperience/\347\275\221\346\230\223\346\235\255\347\240\224.md" @@ -1,7 +1,7 @@ -#网易杭研 +# 网易杭研 --- -###一面: +### 一面: * 自我介绍 * Android中ClassLoader和java中有什么关系和区别? @@ -14,7 +14,7 @@ -###二面: +### 二面: * 用过什么开源,举一个例子?(volley) * Activity生命周期?情景:现在在一张act1点了新的act2,周期如何? @@ -28,7 +28,7 @@ * **评价一下我?往技术栈加什么?** -###三面HR: +### 三面HR: * 为什么想来网易? * 有投其他公司吗? diff --git "a/Part6/InterviewExperience/\347\276\216\345\233\242.md" "b/Part6/InterviewExperience/\347\276\216\345\233\242.md" index 3ad45ec..d0991e5 100644 --- "a/Part6/InterviewExperience/\347\276\216\345\233\242.md" +++ "b/Part6/InterviewExperience/\347\276\216\345\233\242.md" @@ -1,4 +1,4 @@ -#美团 +# 美团 --- 一面 diff --git "a/Part6/InterviewExperience/\350\234\273\350\234\223FM.md" "b/Part6/InterviewExperience/\350\234\273\350\234\223FM.md" index 89ff507..2c32a07 100644 --- "a/Part6/InterviewExperience/\350\234\273\350\234\223FM.md" +++ "b/Part6/InterviewExperience/\350\234\273\350\234\223FM.md" @@ -1,4 +1,4 @@ -#蜻蜓FM +# 蜻蜓FM --- 一面 diff --git "a/Part6/InterviewExperience/\350\261\214\350\261\206\350\215\232.md" "b/Part6/InterviewExperience/\350\261\214\350\261\206\350\215\232.md" index 55c96e5..c3b35cf 100644 --- "a/Part6/InterviewExperience/\350\261\214\350\261\206\350\215\232.md" +++ "b/Part6/InterviewExperience/\350\261\214\350\261\206\350\215\232.md" @@ -1,4 +1,4 @@ -#豌豆荚三面 +# 豌豆荚三面 --- 豌豆荚一面 diff --git a/README.md b/README.md index c3d5864..ba44604 100644 --- a/README.md +++ b/README.md @@ -3,40 +3,40 @@ ## 第一部分: -* [Android(安卓)](https://github.com/GeniusVJR/LearningNotes/tree/master/Part1/Android) - - * [Android基础知识](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Android基础知识.md) - * [Android内存泄漏总结](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Android内存泄漏总结.md) - * [Handler内存泄漏分析及解决](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Handler内存泄漏分析及解决.md) - * [Handler、Looper、Message、MessageQueue基础流程分析](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/线程通信基础流程分析.md) - * [Android性能优化](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Android性能优化.md) - * [ListView详解](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Listview详解.md) - * [RecyclerView和ListView的异同](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Recyclerview和Listview的异同.md) - * [AsyncTask源码分析](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Asynctask源码分析.md) - * [插件化技术](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/插件化技术学习.md) - * [自定义控件](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/自定义控件.md) +* [Android(安卓)](https://github.com/HuYingBao/LearningNotes/tree/master/Part1/Android) + + * [Android基础知识](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Android基础知识.md) + * [Android内存泄漏总结](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Android内存泄漏总结.md) + * [Handler内存泄漏分析及解决](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Handler内存泄漏分析及解决.md) + * [Handler、Looper、Message、MessageQueue基础流程分析](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/线程通信基础流程分析.md) + * [Android性能优化](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Android性能优化.md) + * [ListView详解](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Listview详解.md) + * [RecyclerView和ListView的异同](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Recyclerview和Listview的异同.md) + * [AsyncTask源码分析](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Asynctask源码分析.md) + * [插件化技术](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/插件化技术学习.md) + * [自定义控件](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/自定义控件.md) * [事件分发机制](http://www.jianshu.com/p/e99b5e8bd67b) - * [ANR问题](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/ANR问题.md) - * [Art和Dalvik的区别](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Art和Dalvik区别.md) - * [Android关于OOM的解决方案](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Android关于oom的解决方案.md) - * [Fragment](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Fragment.md) + * [ANR问题](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/ANR问题.md) + * [Art和Dalvik的区别](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Art和Dalvik区别.md) + * [Android关于OOM的解决方案](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Android关于oom的解决方案.md) + * [Fragment](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Fragment.md) * [Activity&Fragment](https://github.com/xxv/android-lifecycle) - * [SurfaceView](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/SurfaceView.md) - * [Android几种进程](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Android几种进程.md) - * [APP启动过程](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/APP启动过程.md) + * [SurfaceView](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/SurfaceView.md) + * [Android几种进程](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Android几种进程.md) + * [APP启动过程](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/APP启动过程.md) * Activity启动流程以及界面展示过程 - * [图片三级缓存](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Android图片中的三级缓存.md) - * [Bitmap的分析与使用](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Bitmap的分析与使用.md) - * [热修复的原理](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/热修复技术.md) - * [AIDL](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/AIDL.md) - * [Binder机制](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Binder机制.md) - * [Zygote和System进程的启动过程](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Zygote和System进程的启动过程.md) - * [Android中的MVC,MVP和MVVM](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/MVC%2CMVP%2CMVVM的区别.md) - * [MVP](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/MVP.md) - * [Android开机过程](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Android开机过程.md) + * [图片三级缓存](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Android图片中的三级缓存.md) + * [Bitmap的分析与使用](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Bitmap的分析与使用.md) + * [热修复的原理](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/热修复技术.md) + * [AIDL](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/AIDL.md) + * [Binder机制](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Binder机制.md) + * [Zygote和System进程的启动过程](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Zygote和System进程的启动过程.md) + * [Android中的MVC,MVP和MVVM](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/MVC%2CMVP%2CMVVM的区别.md) + * [MVP](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/MVP.md) + * [Android开机过程](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Android开机过程.md) * [Retrofit源码分析](http://www.jianshu.com/p/c1a3a881a144) * [Glide源码分析](http://frodoking.github.io/2015/10/10/android-glide/) - * [EventBus用法详解](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/EventBus用法详解.md) + * [EventBus用法详解](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/EventBus用法详解.md) * [EventBus源码分析](http://p.codekk.com/blogs/detail/54cfab086c4761e5001b2538) * [Android ORM 框架之 greenDAO 使用心得](http://www.open-open.com/lib/view/open1438065400878.html) * [Data Binding(数据绑定)用户指南](http://www.jcodecraeer.com/a/anzhuokaifa/developer/2015/0606/3005.html) @@ -44,40 +44,40 @@ * 设计一套图片异步加载缓存方案 * Android UI适配 * [Gradle](http://wuxiaolong.me/categories/Gradle/) - * [查漏补缺](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/查漏补缺.md) - * [Git操作](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/Android/Git操作.md) + * [查漏补缺](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/查漏补缺.md) + * [Git操作](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/Android/Git操作.md) --- -* [DesignPattern(设计模式)](https://github.com/GeniusVJR/LearningNotes/tree/master/Part1/DesignPattern) +* [DesignPattern(设计模式)](https://github.com/HuYingBao/LearningNotes/tree/master/Part1/DesignPattern) - * [面向对象六大原则](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/DesignPattern/常见的面向对象设计原则.md) - * [单例模式](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/DesignPattern/单例模式.md) - * [Builder模式](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/DesignPattern/Builder模式.md) - * [原型模式](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/DesignPattern/原型模式.md) - * [简单工厂](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/DesignPattern/简单工厂.md) + * [面向对象六大原则](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/DesignPattern/常见的面向对象设计原则.md) + * [单例模式](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/DesignPattern/单例模式.md) + * [Builder模式](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/DesignPattern/Builder模式.md) + * [原型模式](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/DesignPattern/原型模式.md) + * [简单工厂](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/DesignPattern/简单工厂.md) * 工厂方法模式 * 抽象工厂模式 - * [策略模式](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/DesignPattern/策略模式.md) + * [策略模式](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/DesignPattern/策略模式.md) * 状态模式 - * [责任链模式](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/DesignPattern/责任链模式.md) + * [责任链模式](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/DesignPattern/责任链模式.md) * 解释器模式 * 命令模式 - * [观察者模式](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/DesignPattern/观察者模式.md) + * [观察者模式](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/DesignPattern/观察者模式.md) * 备忘录模式 * 迭代器模式 * 模板方法模式 * 访问者模式 * 中介者模式 - * [代理模式](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/DesignPattern/代理模式.md) + * [代理模式](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/DesignPattern/代理模式.md) * 组合模式 - * [适配器模式](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/DesignPattern/适配器模式.md) + * [适配器模式](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/DesignPattern/适配器模式.md) * 装饰模式 * 享元模式 - * [外观模式](https://github.com/GeniusVJR/LearningNotes/blob/master/Part1/DesignPattern/外观模式.md) + * [外观模式](https://github.com/HuYingBao/LearningNotes/blob/master/Part1/DesignPattern/外观模式.md) * 桥接模式 @@ -85,46 +85,46 @@ ## 第二部分 -* [JavaSE(Java基础)](https://github.com/GeniusVJR/LearningNotes/tree/master/Part2/JavaSE) - * [Java基础知识](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaSE/Java基础知识.md) - * [Java中的内存泄漏](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaSE/Java中的内存泄漏.md) - * [String源码分析](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaSE/String源码分析.md) - * [Java集合框架](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaSE/Java集合框架.md) - * [ArrayList源码剖析](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaSE/ArrayList源码剖析.md) - * [LinkedList源码剖析](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaSE/LinkedList源码剖析.md) - * [Vector源码剖析](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaSE/Vector源码剖析.md) - * [HashMap源码剖析](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaSE/HashMap源码剖析.md) - * [HashTable源码剖析](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaSE/HashTable源码剖析.md) - * [LinkedHashMap源码剖析](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaSE/LinkedHashMap源码剖析.md) - -* [JVM(Java虚拟机)](https://github.com/GeniusVJR/LearningNotes/tree/master/Part2/JVM) - * [JVM基础知识](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JVM/JVM.md) - * [JVM类加载机制](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JVM/JVM类加载机制.md) - * [Java内存区域与内存溢出](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JVM/Java内存区域与内存溢出.md) - * [垃圾回收算法](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JVM/垃圾回收算法.md) -* [JavaConcurrent(Java并发)](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/Java并发.md) - * [Java并发基础知识](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/Java并发基础知识.md) - * [生产者和消费者问题](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/生产者和消费者问题.md) - * [Thread和Runnable实现多线程的区别](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/Thread和Runnable实现多线程的区别.md) - * [线程中断](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/线程中断.md) - * [守护线程与阻塞线程](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/守护线程与阻塞线程.md) - * [synchronized](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/Synchronized.md) - * [多线程环境中安全使用集合API](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/多线程环境中安全使用集合API.md) - * [实现内存可见的两种方法比较:加锁和volatile变量](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/实现内存可见的两种方法比较:加锁和volatile变量.md) - * [死锁](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/死锁.md) - * [可重入内置锁](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/可重入内置锁.md) - * [使用wait/notify/notifyAll实现线程间通信](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/使用wait:notify:notifyall实现线程间通信.md) - * [NIO](https://github.com/GeniusVJR/LearningNotes/blob/master/Part2/JavaConcurrent/NIO.md) +* [JavaSE(Java基础)](https://github.com/HuYingBao/LearningNotes/tree/master/Part2/JavaSE) + * [Java基础知识](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaSE/Java基础知识.md) + * [Java中的内存泄漏](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaSE/Java中的内存泄漏.md) + * [String源码分析](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaSE/String源码分析.md) + * [Java集合框架](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaSE/Java集合框架.md) + * [ArrayList源码剖析](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaSE/ArrayList源码剖析.md) + * [LinkedList源码剖析](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaSE/LinkedList源码剖析.md) + * [Vector源码剖析](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaSE/Vector源码剖析.md) + * [HashMap源码剖析](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaSE/HashMap源码剖析.md) + * [HashTable源码剖析](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaSE/HashTable源码剖析.md) + * [LinkedHashMap源码剖析](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaSE/LinkedHashMap源码剖析.md) + +* [JVM(Java虚拟机)](https://github.com/HuYingBao/LearningNotes/tree/master/Part2/JVM) + * [JVM基础知识](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JVM/JVM.md) + * [JVM类加载机制](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JVM/JVM类加载机制.md) + * [Java内存区域与内存溢出](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JVM/Java内存区域与内存溢出.md) + * [垃圾回收算法](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JVM/垃圾回收算法.md) +* [JavaConcurrent(Java并发)](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/Java并发.md) + * [Java并发基础知识](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/Java并发基础知识.md) + * [生产者和消费者问题](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/生产者和消费者问题.md) + * [Thread和Runnable实现多线程的区别](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/Thread和Runnable实现多线程的区别.md) + * [线程中断](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/线程中断.md) + * [守护线程与阻塞线程](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/守护线程与阻塞线程.md) + * [synchronized](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/Synchronized.md) + * [多线程环境中安全使用集合API](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/多线程环境中安全使用集合API.md) + * [实现内存可见的两种方法比较:加锁和volatile变量](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/实现内存可见的两种方法比较:加锁和volatile变量.md) + * [死锁](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/死锁.md) + * [可重入内置锁](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/可重入内置锁.md) + * [使用wait/notify/notifyAll实现线程间通信](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/使用wait:notify:notifyall实现线程间通信.md) + * [NIO](https://github.com/HuYingBao/LearningNotes/blob/master/Part2/JavaConcurrent/NIO.md) --- ## 第三部分 -* [DataStructure(数据结构)](https://github.com/GeniusVJR/LearningNotes/tree/master/Part3/DataStructure) - * [数组](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/DataStructure/数组.md) +* [DataStructure(数据结构)](https://github.com/HuYingBao/LearningNotes/tree/master/Part3/DataStructure) + * [数组](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/DataStructure/数组.md) * 链表 - * [栈和队列](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/DataStructure/栈和队列.md) + * [栈和队列](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/DataStructure/栈和队列.md) * 字符串 * 树 * 图 @@ -134,35 +134,35 @@ * [冒泡排序](https://github.com/anAngryAnt/LearningNotes/tree/master/Part3/Algorithm/Sort/冒泡排序.md) * [快速排序](https://github.com/anAngryAnt/LearningNotes/tree/master/Part3/Algorithm/Sort/快速排序.md) * [归并排序](https://github.com/anAngryAnt/LearningNotes/tree/master/Part3/Algorithm/Sort/归并排序.md) - * [面试中的十大排序算法总结](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/Algorithm/Sort/%E9%9D%A2%E8%AF%95%E4%B8%AD%E7%9A%84%2010%20%E5%A4%A7%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95%E6%80%BB%E7%BB%93.md) + * [面试中的十大排序算法总结](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/Algorithm/Sort/%E9%9D%A2%E8%AF%95%E4%B8%AD%E7%9A%84%2010%20%E5%A4%A7%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95%E6%80%BB%E7%BB%93.md) * 查找 - * [顺序查找](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/Algorithm/Lookup/顺序查找.md) - * [折半查找](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/Algorithm/Lookup/折半查找.md) + * [顺序查找](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/Algorithm/Lookup/顺序查找.md) + * [折半查找](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/Algorithm/Lookup/折半查找.md) * 《剑指Offer》 - * [面试题2:实现Singleton模式](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/Algorithm/剑指Offer/1.七种方式实现singleton模式.md) - * [面试题6:重建二叉树](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/Algorithm/剑指Offer/面试题6:重建二叉树.md) - * [面试题11:数值的整数次方](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/Algorithm/剑指Offer/面试题11:数值的整数次方.md) - * [面试题44:扑克牌的顺子](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/Algorithm/剑指Offer/面试题44:扑克牌的顺子.md) - * [面试题45:圆圈中最后剩下的数字](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/Algorithm/剑指Offer/面试题45:圆圈中最后剩下的数字.md) + * [面试题2:实现Singleton模式](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/Algorithm/剑指Offer/1.七种方式实现singleton模式.md) + * [面试题6:重建二叉树](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/Algorithm/剑指Offer/面试题6:重建二叉树.md) + * [面试题11:数值的整数次方](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/Algorithm/剑指Offer/面试题11:数值的整数次方.md) + * [面试题44:扑克牌的顺子](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/Algorithm/剑指Offer/面试题44:扑克牌的顺子.md) + * [面试题45:圆圈中最后剩下的数字](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/Algorithm/剑指Offer/面试题45:圆圈中最后剩下的数字.md) * 《程序员面试金典》 * 《LeetCode》 - * [two-sum](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/Algorithm/LeetCode/two-sum.md) + * [two-sum](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/Algorithm/LeetCode/two-sum.md) * 《程序员代码面试指南(左程云)》 - * [1.设计一个有getMin功能的栈](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/Algorithm/程序员代码面试指南(左程云)/1.设计一个有getMin功能的栈.md) - * [2.由两个栈组成的队列](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/Algorithm/程序员代码面试指南(左程云)/2.由两个栈组成的队列.md) - * [3.如何仅用递归函数和栈操作逆序一个栈](https://github.com/GeniusVJR/LearningNotes/blob/master/Part3/Algorithm/程序员代码面试指南(左程云)/3.如何仅用递归函数和栈操作逆序一个栈.md) + * [1.设计一个有getMin功能的栈](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/Algorithm/程序员代码面试指南(左程云)/1.设计一个有getMin功能的栈.md) + * [2.由两个栈组成的队列](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/Algorithm/程序员代码面试指南(左程云)/2.由两个栈组成的队列.md) + * [3.如何仅用递归函数和栈操作逆序一个栈](https://github.com/HuYingBao/LearningNotes/blob/master/Part3/Algorithm/程序员代码面试指南(左程云)/3.如何仅用递归函数和栈操作逆序一个栈.md) --- ## 第四部分 -* [Network(网络)](https://github.com/GeniusVJR/LearningNotes/tree/master/Part4/Network) - * [TCP/UDP](https://github.com/GeniusVJR/LearningNotes/blob/master/Part4/Network/TCP与UDP.md) - * [HTTP](https://github.com/GeniusVJR/LearningNotes/blob/master/Part4/Network/Http协议.md) - * [Socket](https://github.com/GeniusVJR/LearningNotes/blob/master/Part4/Network/Socket.md) - * [计算机网络基础汇总](https://github.com/GeniusVJR/LearningNotes/blob/master/Part4/Network/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E5%9F%BA%E7%A1%80%E6%B1%87%E6%80%BB.md) -* [OperatingSystem(操作系统)](https://github.com/GeniusVJR/LearningNotes/blob/master/Part4/OperatingSystem/操作系统.md) - * [Linux系统的IPC](https://github.com/GeniusVJR/LearningNotes/blob/master/Part4/OperatingSystem/Linux系统的IPC.md) +* [Network(网络)](https://github.com/HuYingBao/LearningNotes/tree/master/Part4/Network) + * [TCP/UDP](https://github.com/HuYingBao/LearningNotes/blob/master/Part4/Network/TCP与UDP.md) + * [HTTP](https://github.com/HuYingBao/LearningNotes/blob/master/Part4/Network/Http协议.md) + * [Socket](https://github.com/HuYingBao/LearningNotes/blob/master/Part4/Network/Socket.md) + * [计算机网络基础汇总](https://github.com/HuYingBao/LearningNotes/blob/master/Part4/Network/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E5%9F%BA%E7%A1%80%E6%B1%87%E6%80%BB.md) +* [OperatingSystem(操作系统)](https://github.com/HuYingBao/LearningNotes/blob/master/Part4/OperatingSystem/操作系统.md) + * [Linux系统的IPC](https://github.com/HuYingBao/LearningNotes/blob/master/Part4/OperatingSystem/Linux系统的IPC.md) --- @@ -170,31 +170,31 @@ ## 第五部分 -* [ReadingNotes(读书笔记)](https://github.com/GeniusVJR/LearningNotes/tree/master/Part5/ReadingNotes) - * [《APP研发录》第1章读书笔记](https://github.com/GeniusVJR/LearningNotes/blob/master/Part5/ReadingNotes/《APP研发录》第1章读书笔记.md) - * [《APP研发录》第2章读书笔记](https://github.com/GeniusVJR/LearningNotes/blob/master/Part5/ReadingNotes/《APP研发录》第2章读书笔记.md) - * [《Android开发艺术探索》第一章笔记](https://github.com/GeniusVJR/LearningNotes/blob/master/Part5/ReadingNotes/《Android开发艺术探索》第一章笔记.md) - * [《Android开发艺术探索》第二章笔记](https://github.com/GeniusVJR/LearningNotes/blob/master/Part5/ReadingNotes/《Android开发艺术探索》第二章笔记.md) - * [《Android开发艺术探索》第三章笔记](https://github.com/GeniusVJR/LearningNotes/blob/master/Part5/ReadingNotes/《Android开发艺术探索》第三章笔记.md) - * [《Android开发艺术探索》第四章笔记](https://github.com/GeniusVJR/LearningNotes/blob/master/Part5/ReadingNotes/《Android开发艺术探索》第四章笔记.md) - * [《Android开发艺术探索》第八章笔记](https://github.com/GeniusVJR/LearningNotes/blob/master/Part5/ReadingNotes/《Android开发艺术探索》第八章笔记.md) - * [《Android开发艺术探索》第十五章笔记](https://github.com/GeniusVJR/LearningNotes/blob/master/Part5/ReadingNotes/《Android开发艺术探索》第十五章笔记.md) - * [《深入理解Java虚拟机》第12章](https://github.com/GeniusVJR/LearningNotes/blob/master/Part5/ReadingNotes/《深入理解java虚拟机》第12章.md) - * [《Java编程思想》第一章读书笔记](https://github.com/GeniusVJR/LearningNotes/blob/master/Part5/ReadingNotes/《Java编程思想》第一章读书笔记.md) - * [《Java编程思想》第二章读书笔记](https://github.com/GeniusVJR/LearningNotes/blob/master/Part5/ReadingNotes/《Java编程思想》第二章读书笔记.md) - -* [Project(项目)](https://github.com/GeniusVJR/LearningNotes/tree/master/Part5/Project) - * [项目难点](https://github.com/GeniusVJR/LearningNotes/blob/master/Part5/Project/项目.md) +* [ReadingNotes(读书笔记)](https://github.com/HuYingBao/LearningNotes/tree/master/Part5/ReadingNotes) + * [《APP研发录》第1章读书笔记](https://github.com/HuYingBao/LearningNotes/blob/master/Part5/ReadingNotes/《APP研发录》第1章读书笔记.md) + * [《APP研发录》第2章读书笔记](https://github.com/HuYingBao/LearningNotes/blob/master/Part5/ReadingNotes/《APP研发录》第2章读书笔记.md) + * [《Android开发艺术探索》第一章笔记](https://github.com/HuYingBao/LearningNotes/blob/master/Part5/ReadingNotes/《Android开发艺术探索》第一章笔记.md) + * [《Android开发艺术探索》第二章笔记](https://github.com/HuYingBao/LearningNotes/blob/master/Part5/ReadingNotes/《Android开发艺术探索》第二章笔记.md) + * [《Android开发艺术探索》第三章笔记](https://github.com/HuYingBao/LearningNotes/blob/master/Part5/ReadingNotes/《Android开发艺术探索》第三章笔记.md) + * [《Android开发艺术探索》第四章笔记](https://github.com/HuYingBao/LearningNotes/blob/master/Part5/ReadingNotes/《Android开发艺术探索》第四章笔记.md) + * [《Android开发艺术探索》第八章笔记](https://github.com/HuYingBao/LearningNotes/blob/master/Part5/ReadingNotes/《Android开发艺术探索》第八章笔记.md) + * [《Android开发艺术探索》第十五章笔记](https://github.com/HuYingBao/LearningNotes/blob/master/Part5/ReadingNotes/《Android开发艺术探索》第十五章笔记.md) + * [《深入理解Java虚拟机》第12章](https://github.com/HuYingBao/LearningNotes/blob/master/Part5/ReadingNotes/《深入理解java虚拟机》第12章.md) + * [《Java编程思想》第一章读书笔记](https://github.com/HuYingBao/LearningNotes/blob/master/Part5/ReadingNotes/《Java编程思想》第一章读书笔记.md) + * [《Java编程思想》第二章读书笔记](https://github.com/HuYingBao/LearningNotes/blob/master/Part5/ReadingNotes/《Java编程思想》第二章读书笔记.md) + +* [Project(项目)](https://github.com/HuYingBao/LearningNotes/tree/master/Part5/Project) + * [项目难点](https://github.com/HuYingBao/LearningNotes/blob/master/Part5/Project/项目.md) ## 第六部分 -* [InterviewExperience(面试经验)](https://github.com/GeniusVJR/LearningNotes/tree/master/Part6/InterviewExperience) - * [Alibaba](https://github.com/GeniusVJR/LearningNotes/blob/master/Part6/InterviewExperience/Alibaba.md) - * [美团](https://github.com/GeniusVJR/LearningNotes/blob/master/Part6/InterviewExperience/美团.md) - * [豌豆荚](https://github.com/GeniusVJR/LearningNotes/blob/master/Part6/InterviewExperience/豌豆荚.md) - * [蜻蜓FM](https://github.com/GeniusVJR/LearningNotes/blob/master/Part6/InterviewExperience/蜻蜓FM.md) - * [新浪微博](https://github.com/GeniusVJR/LearningNotes/blob/master/Part6/InterviewExperience/新浪微博.md) - * [网易杭研](https://github.com/GeniusVJR/LearningNotes/blob/master/Part6/InterviewExperience/网易杭研.md) +* [InterviewExperience(面试经验)](https://github.com/HuYingBao/LearningNotes/tree/master/Part6/InterviewExperience) + * [Alibaba](https://github.com/HuYingBao/LearningNotes/blob/master/Part6/InterviewExperience/Alibaba.md) + * [美团](https://github.com/HuYingBao/LearningNotes/blob/master/Part6/InterviewExperience/美团.md) + * [豌豆荚](https://github.com/HuYingBao/LearningNotes/blob/master/Part6/InterviewExperience/豌豆荚.md) + * [蜻蜓FM](https://github.com/HuYingBao/LearningNotes/blob/master/Part6/InterviewExperience/蜻蜓FM.md) + * [新浪微博](https://github.com/HuYingBao/LearningNotes/blob/master/Part6/InterviewExperience/新浪微博.md) + * [网易杭研](https://github.com/HuYingBao/LearningNotes/blob/master/Part6/InterviewExperience/网易杭研.md) ---