├── JavaNote ├── Java相关 │ ├── ArrayList、LinkedList、Vector的异同.md │ ├── Des加密算法.md │ ├── HashTable和HashMap的异同.md │ ├── Java中Error和Exception.md │ ├── Java利用ExecutorService实现同步执行大量线程.md │ ├── Java利用listener实现回调,即观察者模式.md │ ├── Java回调的原理与实现.md │ ├── Java注解的编写与Java的反射机制.md │ ├── 发布jar包到Maven中央仓库.md │ └── 面向对象的六大原则以及常见的十七种设计模式.md ├── img │ ├── background.jpg │ └── background2.jpg ├── test.java └── 设计模式相关 │ ├── 单例模式.md │ ├── 单例模式的四种实现方式.md │ ├── 观察者模式.md │ └── 设计模式概括.md ├── LICENSE └── README.md /JavaNote/Java相关/ArrayList、LinkedList、Vector的异同.md: -------------------------------------------------------------------------------- 1 | # ArrayList、LinkedList、Vector的异同 2 | 3 | 我们可以看出ArrayList、LinkedList、Vector都实现了List的接口。 4 | 5 | 接下来分别看一下三个数据结构的说明: 6 | 7 | - 首先是ArrayList 8 | 9 | ``public class **ArrayList** extends AbstractList 10 | implements List, RandomAccess, Cloneable, Serializable`` 11 | 12 | List 接口的**大小可变数组**的实现。实现了所有可选列表操作,并**允许包括 null 在内的所有元素**。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。(此类大致上等同于 Vector 类,除了**此类是不同步的**。) 13 | 14 | 每个 ArrayList 实例都有一个容量。该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长。并未指定增长策略的细节,因为这不只是添加元素会带来分摊固定时间开销那样简单。 15 | 16 | 在添加大量元素前,应用程序可以使用 ensureCapacity 操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。 17 | 18 | ``List list = Collections.synchronizedList(new ArrayList(...)); `` 19 | 20 | 此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的 remove 或 add 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。 21 | 注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。 22 | 23 | - 然后是LinkedList 24 | 25 | 26 | ``public class **LinkedList** extends AbstractSequentialList 27 | implements List, Deque, Cloneable, Serializable`` 28 | 29 | List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(**包括 null**)。除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。 30 | 31 | 此类实现 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作。 32 | 33 | 所有操作都是按照**双重链接列表**的需要执行的。在列表中编索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。 34 | 35 | 注意,此实现**不是同步**的。如果多个线程同时访问一个链接列表,而其中至少一个线程从结构上修改了该列表,则它必须 保持外部同步。(结构修改指添加或删除一个或多个元素的任何操作;仅设置元素的值不是结构修改。)这一般通过**对自然封装该列表的对象进行同步操作来完成**。如果不存在这样的对象,则应该使用 Collections.synchronizedList 方法来“包装”该列表。最好在创建时完成这一操作,以防止对列表进行意外的不同步访问,如下所示: 36 | 37 | ``List list = Collections.synchronizedList(new LinkedList(...));`` 38 | 39 | 此类的 iterator 和 listIterator 方法返回的迭代器是快速失败 的:在迭代器创建之后,如果从结构上对列表进行修改,除非通过迭代器自身的 remove 或 add 方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不冒将来不确定的时间任意发生不确定行为的风险。 40 | 41 | 注意,迭代器的快速失败行为不能得到保证,一般来说,存在不同步的并发修改时,不可能作出任何硬性保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException。因此,编写依赖于此异常的程序的方式是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测程序错误。 42 | 43 | - 最后是Vector 44 | 45 | public class **Vector** extends AbstractList 46 | implements List, RandomAccess, Cloneable, Serializable 47 | 48 | Vector 类可以**实现可增长的对象数组**。与数组一样,它包含可以使用整数索引进行访问的组件。但是,Vector 的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。 49 | 50 | 每个向量会试图通过维护 capacity 和 capacityIncrement 来优化存储管理。capacity 始终至少应与向量的大小相等;这个值通常比后者大些,因为随着将组件添加到向量中,其存储将按 capacityIncrement 的大小增加存储块。应用程序可以在插入大量组件前增加向量的容量;这样就减少了增加的重分配的量。 51 | 52 | 由 Vector 的 iterator 和 listIterator 方法所返回的迭代器是快速失败的:如果在迭代器创建后的任意时间从结构上修改了向量(通过迭代器自身的 remove 或 add 方法之外的任何其他方式),则迭代器将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就完全失败,而不是冒着在将来不确定的时间任意发生不确定行为的风险。Vector 的 elements 方法返回的 Enumeration 不是 快速失败的。 53 | 54 | 注意,迭代器的快速失败行为不能得到保证,一般来说,存在不同步的并发修改时,不可能作出任何坚决的保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException。因此,编写依赖于此异常的程序的方式是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测 bug。 55 | 56 | 从 Java 2 平台 v1.2 开始,此类改进为可以实现 List 接口,使它成为 Java Collections Framework 的成员。与新 collection 实现不同,**Vector 是同步的**。 57 | 58 | ---- 59 | 60 | - 区别 61 | 62 | 63 | ArrayList 本质上是一个可改变大小的**数组**.当元素加入时,其大小将会动态地增长.内部的元素可以直接通过get与set方法进行访问.元素顺序存储 ,**随机访问很快,删除非头尾元素慢,新增元素慢而且费资源** ,较适用于无频繁增删的情况 ,比数组效率低,如果不是需要可变数组,可考虑使用数组 ,**非线程安全**. 64 | 65 | LinkedList 是一个**双链表**,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList. 适用于 :没有大规模的随机读取,大量的增加/删除操作.**随机访问很慢,增删操作很快**,不耗费多余资源 ,允许null元素,**非线程安全.** 66 | 67 | Vector (类似于ArrayList)但其是**同步**的,开销就比ArrayList要大。如果你的程序本身是线程安全的,那么使用ArrayList是更好的选择。 68 | Vector和ArrayList在更多元素添加进来时会请求更大的空间。Vector每次请求其大小的双倍空间,而ArrayList每次对size增长50%. 69 | 70 | -------------------------------------------------------------------------------- /JavaNote/Java相关/Des加密算法.md: -------------------------------------------------------------------------------- 1 | # Des加密算法 2 | 3 | > des加密算法,是一个对称的加密算法,目前被广泛应用,所以打算写一个demo。 4 | 5 | 6 | ``` 7 | package com.dao; 8 | 9 | import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; 10 | import sun.misc.BASE64Decoder; 11 | import sun.misc.BASE64Encoder; 12 | 13 | import javax.crypto.Cipher; 14 | import javax.crypto.SecretKey; 15 | import javax.crypto.SecretKeyFactory; 16 | import javax.crypto.spec.DESKeySpec; 17 | import java.io.IOException; 18 | import java.security.SecureRandom; 19 | 20 | /** 21 | * Created by linSir on 2017/6/22.des加密算法 22 | */ 23 | public class Test { 24 | 25 | public static void main(String args[]) throws IOException { 26 | 27 | 28 | //加密 29 | //byte[] result = Test.encrypt(str.getBytes(),password); 30 | //BASE64Encoder base64encoder = new BASE64Encoder(); 31 | //String encode=base64encoder.encode(result); 32 | 33 | String miwen = "ZraEmkLPeVT1CBGRpcbXTfVRhUWt6riMMh8UoWcVEClwLcCRuJoMmZW+IS5MYshasXVUu1VIFeqE\n" + 34 | "ySjMvDvu4z6GxUR7BVq95mfILIT6kvCLW1rvgJoZGlkXzDW7R+n8R/POzu61cfKejnMnW0HiRmsK\n" + 35 | "CNLB3zf0KYfB5H0x0+GUtXQmtQyG0x5tQSyHSWOdQVyEj7mYFw4h6uFhN94ifgZq8ohpUduWZBgU\n" + 36 | "EN3B4akKt8+oPQPFv1GvrFucOmrfDpyTy+YuLZZ0nlPA5AYTa2TnC++ZPPo62XW4O2EZ0qGXcuO1\n" + 37 | "3zHfq8mmtdQ7DbGN2JIBNLL/EN97o7pHRkVNbB9/eHElf37MghHZWTUfIlvRtSTwaWkW3IR2aWzj\n" + 38 | "GQXrdqErVUdcTvLH2fGnInYU6XAtwJG4mgyZG6OZZ89Yg9iOcWG4GruJvFEa/UQNDmbS+vyvWpP/\n" + 39 | "75zOiDos5s5yeJUcUaJt+SkUR7z5yr7bbK/DHkS5aEvfNI/nL4Z4DrGN++9Uzv34XD4ZTg0csEuL\n" + 40 | "96+LAUKED43iaJUo6wruiZ/7KmpvP5p3ii5p03Z1ymscmTlqUTZ55YFBCz3dZg8OSGIlKj+7uaYF\n" + 41 | "umweL38ksAtVL1wjgWMVF+9oYUie/jf6+mAdmvwiACoGu71ZziWc4tz1UPb27Qx4Qf0h/nItAkuT\n" + 42 | "yLK6+Hx0+GQ2weK2q95kgf8zUs1igyhu1VdMGHbp/Ma3DyJIo6wPgwRlpFedCq0/w7ECGGPHfLUb\n" + 43 | "eNmBK3nCqqN7TABiLfHfzR8mBjjMcJQ1MtGGwZB6H6zAGkcSEQqHgsTbnG6t8GvS06t9eepMn6VG\n" + 44 | "7X+dS4LUS9LpIZ/OgNwxvyxd3vw/dKn9u0OLgvJRGv1EDQ5m0t80qIo6RxHCLmnTdnXKaxxFIhNG\n" + 45 | "caq19CPEthsSFziTHlX/qM5g/yCwbN9+qClQ0z5VI/ZGUAcs9Cz3WjimPGKNyLa+AKgUE7dh4sFr\n" + 46 | "vQGrlRxRom35KRRRd/VE9Goz3EAcQQ1NhiDMYobeoH0as5XkG3hTF2zZyfn/QJZnNwh4GxCLkZPS\n" + 47 | "VKFdg0bpAy3irJouw+IG69DUewM4W4a1u7h8i76pCLLxP5gIYqKqKgm97itSQe8ZV3qbG9gNxMrg\n" + 48 | "aUQ+fCE3TvsP07RdLW9Dn6Mazxnq7wnw9X2Qj9+sTl+hLLKhL+ZlHIJk5wvvmTz6OikBCmYmdEZb\n" + 49 | "Q1Prg0CgHVrFy4JOc9rTCmLnieHBG/xVwI5AOp42NUOk/Ycc7EIuzQ4tKEGS7RjmcpKEUMkog5c5\n" + 50 | "k693mGsn2VUQNeRPmfrcN7Ra+L18fvKMs1ESEjrUR/GpHwg6UcCBfBh8r/B5bYdoV2ik02liSVzX\n" + 51 | "Kt5vzA3ZjC5mvkF/RJJUoCUa6j3xqznjJhmABsN23gOcRh8RRWb8VGI2xD8ErYwuZr5Bf0SSTyTL\n" + 52 | "p6dacHJIz1u6+TEr9OfinHoMzBwXETOkAnPOt/YdwGw8/MM41w=="; 53 | 54 | BASE64Decoder base64decoder = new BASE64Decoder(); 55 | byte[] encodeByte = base64decoder.decodeBuffer(miwen); 56 | 57 | 58 | //直接将如上内容解密 59 | try { 60 | byte[] decryResult = Test.decrypt(encodeByte, ""); 61 | System.out.println("解密后:" + new String(decryResult)); 62 | } catch (Exception e1) { 63 | e1.printStackTrace(); 64 | } 65 | 66 | } 67 | 68 | /** 69 | * 加密 70 | */ 71 | public static byte[] encrypt(byte[] datasource, String password) { 72 | try { 73 | SecureRandom random = new SecureRandom(); 74 | DESKeySpec desKey = new DESKeySpec(password.getBytes()); 75 | //创建一个密匙工厂,然后用它把DESKeySpec转换成 76 | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 77 | SecretKey securekey = keyFactory.generateSecret(desKey); 78 | //Cipher对象实际完成加密操作 79 | Cipher cipher = Cipher.getInstance("DES"); 80 | //用密匙初始化Cipher对象 81 | cipher.init(Cipher.ENCRYPT_MODE, securekey, random); 82 | //现在,获取数据并加密 83 | //正式执行加密操作 84 | return cipher.doFinal(datasource); 85 | } catch (Throwable e) { 86 | e.printStackTrace(); 87 | } 88 | return null; 89 | } 90 | 91 | /* 92 | * 解密 93 | */ 94 | private static byte[] decrypt(byte[] src, String password) throws Exception { 95 | // DES算法要求有一个可信任的随机数源 96 | SecureRandom random = new SecureRandom(); 97 | // 创建一个DESKeySpec对象 98 | DESKeySpec desKey = new DESKeySpec(password.getBytes()); 99 | // 创建一个密匙工厂 100 | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 101 | // 将DESKeySpec对象转换成SecretKey对象 102 | SecretKey securekey = keyFactory.generateSecret(desKey); 103 | // Cipher对象实际完成解密操作 104 | Cipher cipher = Cipher.getInstance("DES"); 105 | // 用密匙初始化Cipher对象 106 | cipher.init(Cipher.DECRYPT_MODE, securekey, random); 107 | // 真正开始解密操作 108 | return cipher.doFinal(src); 109 | } 110 | } 111 | 112 | ``` -------------------------------------------------------------------------------- /JavaNote/Java相关/HashTable和HashMap的异同.md: -------------------------------------------------------------------------------- 1 | # HashTable和HashMap的异同 2 | 3 | - HashTable 4 | 5 | 1. Hashtable继承于Dictionary字典,实现Map接口 6 | 7 | 2. 键、值都不能是空对象 8 | 9 | 3. 多次访问,映射元素的顺序相同 10 | 11 | 4. 线程安全 12 | 13 | 14 | 5. hash算法 ,Hashtable则直接利用key本身的hash码来做验证 15 | 16 | 6. 数据遍历的方式 Iterator (支持fast-fail)和 Enumeration (不支持fast-fail) 17 | 18 | 7. 缺省初始长度为11,内部都为抽象方法,需要 它的实现类一一作自己的实现 19 | 20 | 备注:程序在对 collection 进行迭代时,某个线程对该 collection 在结构上对其做了修改,这时迭代器就会抛出 ConcurrentModificationException 异常信息,从而产生 fail-fast。 21 | 22 | ---- 23 | 24 | - HashMap 25 | 26 | 1. HashMap继承于AbstractMap抽象类 27 | 28 | 2. 键和值都可以是空对象 29 | 30 | 3. 多次访问,映射元素的顺序可能不同 31 | 32 | 4. 非线程安全 33 | HashMap可以通过下面的语句进行同步: 34 | ``Map m = Collections.synchronizeMap(hashMap);`` 35 | 36 | 5. 检测是否含有key时,HashMap内部需要将key的hash码重新计算一边再检测数据遍历的方式 Iterator (支持fast-fail) 37 | 38 | 6. 缺省初始长度为16,其内部已经实现了Map所需 要做的大部分工作, 它的子类只需要实现它的少量方法 39 | 40 | -------------------------------------------------------------------------------- /JavaNote/Java相关/Java中Error和Exception.md: -------------------------------------------------------------------------------- 1 | # Java中Error和Exception 2 | 3 | Java 异常类继承关系图: 4 | 5 | ![](http://img.blog.csdn.net/20160412143252629) 6 | 7 | 8 | (一)Throwable 9 | 10 |   Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类或其子类之一的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出,才可以是 catch 子句中的参数类型。 11 |   Throwable 类及其子类有两个构造方法,一个不带参数,另一个带有 String 参数,此参数可用于生成详细消息。 12 |   Throwable 包含了其线程创建时线程执行堆栈的快照。它还包含了给出有关错误更多信息的消息字符串。 13 |    14 | Java将可抛出(Throwable)的结构分为三种类型: 15 |   1. 错误(Error) 16 |   2. 运行时异常(RuntimeException) 17 |   3. 被检查的异常(Checked Exception) 18 | 19 |  1.**Error** 20 |   Error 是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题。大多数这样的错误都是异常条件。 21 |   和RuntimeException一样, 编译器也不会检查Error。 22 |   当资源不足、约束失败、或是其它程序无法继续运行的条件发生时,就产生错误,程序本身无法修复这些错误的。 23 |    24 |  2.**Exception** 25 |   Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。 26 |    对于可以恢复的条件使用**被检查异常**(Exception的子类中除了RuntimeException之外的其它子类),对于程序错误使用运行时异常。  27 |    28 | 2.1 ClassNotFoundException 29 |    30 | 当应用程序试图使用以下方法通过字符串名加载类时: 31 | Class 类中的 forName 方法。 32 | ClassLoader 类中的 findSystemClass 方法。 33 | ClassLoader 类中的 loadClass 方法。 34 | 但是没有找到具有指定名称的类的定义,抛出该异常。 35 | 36 | 2.2 CloneNotSupportedException 37 | 38 | 当调用 Object 类中的 clone 方法复制对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。重写 clone 方法的应用程序也可能抛出此异常,指示不能或不应复制一个对象。 39 |   40 | 41 | 2.3 IOException 42 | 当发生某种 I/O 异常时,抛出此异常。此类是失败或中断的 I/O 操作生成的异常的通用类。 43 | 44 | - EOFException 45 | 46 | 当输入过程中意外到达文件或流的末尾时,抛出此异常。 47 | 此异常主要被**数据输入流**用来表明到达流的末尾。 48 | 注意:其他许多输入操作返回一个特殊值表示到达流的末尾,而不是抛出异常。 49 |      50 | - FileNotFoundException 51 | 52 | 当试图打开指定路径名表示的文件失败时,抛出此异常。在不存在具有指定路径名的文件时,此异常将由 FileInputStream、FileOutputStream 和 RandomAccessFile 构造方法抛出。如果该文件存在,但是由于某些原因不可访问,比如试图打开一个只读文件进行写入,则此时这些构造方法仍然会抛出该异常。 53 | 54 | - MalformedURLException 55 | 56 | 抛出这一异常指示出现了错误的 URL。或者在规范字符串中找不到任何合法协议,或者无法解析字符串。  57 |   58 | -UnknownHostException 59 |   指示主机 IP 地址无法确定而抛出的异常。 60 | 61 | 2.4 RuntimeException 62 |    是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。可能在执行方法期间抛出但未被捕获的 RuntimeException 的任何子类都无需在 throws 子句中进行声明。 63 |    Java编译器不会检查它。当程序中可能出现这类异常时,还是会编译通过。 64 |    虽然Java编译器不会检查运行时异常,但是我们也可以通过throws进行声明抛出,也可以通过try-catch对它进行捕获处理。 65 | 66 | - ArithmeticException 67 | 68 | 当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。 69 | 70 | - ClassCastException 71 | 72 | 当试图将对象强制转换为不是实例的子类时,抛出该异常。 73 | 例如:Object x = new Integer(0); 74 | 75 | - LllegalArgumentException 76 | 77 | 抛出的异常表明向方法传递了一个不合法或不正确的参数。 78 | 79 | - IllegalStateException 80 | 81 | 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。 82 | 83 | - IndexOutOfBoundsException  84 | 85 | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 86 | 应用程序可以为这个类创建子类,以指示类似的异常。 87 | 88 | - NoSuchElementException 89 | 90 | 由 Enumeration 的 nextElement 方法抛出,表明枚举中没有更多的元素。 91 | 92 | - NullPointerException 93 | 94 | 当应用程序试图在需要对象的地方使用 null 时,抛出该异常。这种情况包括: 95 | 调用 null 对象的实例方法。 96 | 访问或修改 null 对象的字段。 97 | 将 null 作为一个数组,获得其长度。 98 | 将 null 作为一个数组,访问或修改其时间片。 99 | 将 null 作为 Throwable 值抛出。 100 | 应用程序应该抛出该类的实例,指示其他对 null 对象的非法使用。 101 | 102 | 103 | 104 | (二) SOF (堆栈溢出 StackOverflow) 105 | 106 | > StackOverflowError 的定义: 107 | > 当应用程序递归太深而发生堆栈溢出时,抛出该错误。 108 | > 109 | 因为栈一般默认为1-2m,一旦出现死循环或者是大量的递归调用,在不断的压栈过程中,造成栈容量超过1m而导致溢出。 110 | 111 | 栈溢出的原因: 112 | 113 | 1. 递归调用 114 | 115 | 2. 大量循环或死循环 116 | 117 | 3. 全局变量是否过多 118 | 119 | 4. 数组、List、map数据过大 120 | 121 | 122 | 123 | (三)Android的OOM(Out Of Memory) 124 | 125 |   当内存占有量超过了虚拟机的分配的最大值时就会产生内存溢出(VM里面分配不出更多的page)。 126 |    127 | 一般出现情况:加载的图片太多或图片过大时、分配特大的数组、内存相应资源过多没有来不及释放。 128 | 129 | 解决方法: 130 | 131 | ①在内存引用上做处理 132 | 133 | 软引用是主要用于内存敏感的高速缓存。在jvm报告内存不足之前会清除所有的软引用,这样以来gc就有可能收集软可及的对象,可能解决内存吃紧问题,避免内存溢出。什么时候会被收集取决于gc的算法和gc运行时可用内存的大小。 134 | 135 | ②对图片做边界压缩,配合软引用使用 136 |   137 | ③显示的调用GC来回收内存  138 |   139 | 140 | ``` 141 | if(bitmapObject.isRecycled()==false) //如果没有回收 142 | bitmapObject.recycle(); 143 | ``` 144 |   145 | ④优化Dalvik虚拟机的堆内存分配 146 |    147 | 1.增强程序堆内存的处理效率 148 |    149 | 150 | ``` 151 | //在程序onCreate时就可以调用 即可 152 | private final static floatTARGET_HEAP_UTILIZATION = 0.75f; 153 | 154 | VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 155 | ``` 156 | 157 | 2.设置缓存大小 158 | 159 | ``` 160 | private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ; 161 | //设置最小heap内存为6MB大小 162 | VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); 163 | ``` 164 | 165 | ⑤ 用LruCache 和 AsyncTask<>解决 166 | 167 |   从cache中去取Bitmap,如果取到Bitmap,就直接把这个Bitmap设置到ImageView上面。 168 |   如果缓存中不存在,那么启动一个task去加载(可能从文件来,也可能从网络)。 169 | 170 | -------------------------------------------------------------------------------- /JavaNote/Java相关/Java利用ExecutorService实现同步执行大量线程.md: -------------------------------------------------------------------------------- 1 | >自从java1.5以后,官网就推出了Executor这样一个类,这个类,可以维护我们的大量线程在操作临界资源时的稳定性。 2 | 3 | 先上一段代码吧: 4 | ```` 5 | TestRunnable.java 6 | public class TestRunnable implements Runnable { 7 | private String name; 8 | 9 | public TestRunnable(String name) { 10 | this.name = name; 11 | } 12 | 13 | @Override 14 | public void run() { 15 | while (true) { 16 | if (Main.Surplus < 0) 17 | return; 18 | Main.Surplus--; 19 | System.out.println(name + " " + Main.Surplus); 20 | } 21 | } 22 | } 23 | ```` 24 | 25 | ```` 26 | main入口 27 | public static void main(String[] args) { 28 | 29 | TestRunnable runnable = new TestRunnable("runnable1"); 30 | TestRunnable runnable2 = new TestRunnable("runnable2"); 31 | 32 | Thread t1 = new Thread(runnable); 33 | Thread t2 = new Thread(runnable2); 34 | 35 | t1.start(); 36 | t2.start(); 37 | 38 | } 39 | ```` 40 | 41 | ![result](http://upload-images.jianshu.io/upload_images/2585384-b60f973afce827b2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 42 | 43 | 这样,我们就看到了,数据肯定是乱了的,当然这个时候我们可以加上一个synchronized的关键字,但是这样也会出现点小问题的 44 | 45 | ![result2](http://upload-images.jianshu.io/upload_images/2585384-3cc19f76464d6831.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 46 | 47 | ---- 48 | 下面我打算采用一种java内置的线程管理的机制,来解决这个问题,解决这个问题的思路大概就是,我们维护了一个线程池,当有请求操作的时候统统进入线程池,并且我们只开了一个线程,可以让请求顺序执行,顺序调用临界资源,就很安全了。 49 | 50 | ```` 51 | import java.util.concurrent.Callable; 52 | import java.util.concurrent.ExecutionException; 53 | import java.util.concurrent.ExecutorService; 54 | import java.util.concurrent.Executors; 55 | import java.util.concurrent.Future; 56 | 57 | public class Main { 58 | public static int Surplus = 10; 59 | 60 | private ExecutorService executor = Executors.newSingleThreadExecutor(); 61 | 62 | void addTask(Runnable runnable) { 63 | executor.execute(runnable); 64 | } 65 | 66 | V addTask(Callable callable) { 67 | Future submit = executor.submit(callable); 68 | try { 69 | return submit.get(); 70 | } catch (InterruptedException e) { 71 | System.out.println("InterruptedException" + e.toString()); 72 | } catch (ExecutionException e) { 73 | System.out.println("ExecutionException" + e.toString()); 74 | } 75 | return null; 76 | } 77 | 78 | public void testAddTask(String name) { 79 | addTask(new Runnable() { 80 | @Override 81 | public void run() { 82 | for (int i = 0; i < 3; i++) { 83 | if (Main.Surplus <= 0) 84 | return; 85 | Main.Surplus--; 86 | System.out.println(name + " " + Main.Surplus); 87 | } 88 | 89 | } 90 | }); 91 | } 92 | 93 | public void testAddTask2(String name) { 94 | int count = addTask(new Callable() { 95 | @Override 96 | public Integer call() throws Exception { 97 | for (int i = 0; i < 3; i++) { 98 | if (Main.Surplus <= 0) 99 | return 0; 100 | Main.Surplus--; 101 | System.out.println(name + " " + Main.Surplus); 102 | } 103 | return Main.Surplus; 104 | } 105 | }); 106 | 107 | } 108 | 109 | public void close() { 110 | executor.shutdown(); 111 | } 112 | 113 | public static void main(String[] args) { 114 | Main main = new Main(); 115 | main.testAddTask("task1"); 116 | main.testAddTask2("task2"); 117 | main.testAddTask("task3"); 118 | main.testAddTask2("task4"); 119 | main.close(); 120 | } 121 | } 122 | 123 | ```` 124 | 125 | 在这里,我们定义了两种方法,分别是addTask,具有泛型的addTask,这两种方法实现原理都是一样的,其中一个是有回调的,一个是没有回调的,就看项目需求了吧。 126 | 127 | ![result3](http://upload-images.jianshu.io/upload_images/2585384-ee988c2286ef99a1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 128 | 然后分别调用这两个方法咯,就可以看到结果是非常有序,且不会混乱的。 129 | 130 | ---- 131 | 当然啊,系统为我们提供这样一个类,肯定不是为了实现这么小的一个功能的,它还有很多功能,我也在进一步的学习中~ 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /JavaNote/Java相关/Java利用listener实现回调,即观察者模式.md: -------------------------------------------------------------------------------- 1 | > java中实现观察者模式有很多种方式,上一篇文章介绍到了,[利用callback的方式实现了回调](http://www.jianshu.com/p/67190bdce647),这篇文章准备介绍的是利用listener实现回调。 2 | 3 | ---- 4 | #Java回调机制 5 | 6 | ####根据实时性划分: 7 | - [同步回调](http://www.jianshu.com/p/67190bdce647) 8 | - [异步回调](http://www.jianshu.com/p/67190bdce647) 9 | 10 | ####实现方式 11 | * [利用匿名内部类即callbck来实现](http://www.jianshu.com/p/67190bdce647) 12 | * 用listener来实现 13 | 14 | 这两种实现方式本质上是类似的,应用场景略有不同,如果有熟知安卓的朋友应该可以知道,在为一个view添加点击实现的时候是有两种方式的 15 | 16 | 1. 利用callback来实现 17 | 18 | ```` 19 | view.setOnClickListener(new View.OnClickListener() { 20 | @Override public void onClick(View view) { 21 | 22 | } 23 | }); 24 | ```` 25 | 26 | 2.实现View.OnClickListener接口 27 | 28 | ```` 29 | public class Test extends AppCompatActivity implements View.OnClickListener { 30 | private Button button; 31 | 32 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | button = (Button) findViewById(R.id.ac_video_btn_getValue); 35 | button.setOnClickListener(this); 36 | } 37 | 38 | @Override public void onClick(View view) { 39 | //TODO 40 | } 41 | } 42 | 43 | 44 | 45 | ```` 46 | 47 | ####回调的本质 48 | 其实无论哪种方式来实现回调,利用的思想都是观察者模式,即在我们选择订阅之后,当对方做出任何举动的时候会给我们发送一条信息,这样做的好处是省着我们用一个新的线程轮训检测对方的状态,可以节省很多的资源。 49 | 50 | ####应用的场景 51 | 52 | - 如果我们需要将信息一层一层的返回去的时候,正如我下面的例子,那么可能用listener更为适合我们,因为我们可以将这个listener进行传递,在需要查看数据的时候进行回调它。或者当我们有很多事件需要回调的时候,可以实现一个listener然后发送不同的信息,进行区分。这样代码看起来会简洁一些,不会像callback一样,会嵌套很多层,也不会写出很多个callback来。 53 | 54 | - 如果我们只有一处,或者简单的几处需要回调的话,那么我们完全可以不用实现这个接口,而是用callback的方式来进行处理。 55 | 56 | ---- 57 | 58 | 还是举一个简单的生活中的例子吧,在公司中有一件事情,老板想要问员工,但是老板只能联系到部门经理,那么便有了,A问B,B问C,C经过思考,回答了B,B又将答案告诉了A,A知道了答案,便高兴的说了出来。 59 | 60 | ---- 61 | 我下面的代码采用了单例模式来写: 62 | ```` 63 | Listner.java 64 | 65 | public interface Listener { 66 | void onFinish(String msg); 67 | } 68 | ```` 69 | 70 | ```` 71 | People.java 72 | 73 | public class People implements Listener { 74 | 75 | private static People people; 76 | 77 | private People() { 78 | 79 | } 80 | 81 | synchronized public static People getInstance() { 82 | if (people == null) { 83 | people = new People(); 84 | } 85 | return people; 86 | } 87 | 88 | public void askPeople2() { 89 | People2.getInstance().askPeople3(this); 90 | } 91 | 92 | @Override 93 | public void onFinish(String msg) { 94 | System.out.println("收到的消息是 ---> " + msg); 95 | } 96 | 97 | } 98 | ```` 99 | 100 | ```` 101 | People2.java 102 | 103 | public class People2 { 104 | 105 | private static People2 people2; 106 | 107 | private People2() { 108 | 109 | } 110 | 111 | synchronized public static People2 getInstance() { 112 | if (people2 == null) 113 | people2 = new People2(); 114 | return people2; 115 | } 116 | 117 | public void askPeople3(Listener listener){ 118 | People3.getInstance().thinking(listener); 119 | } 120 | 121 | } 122 | ```` 123 | 124 | ```` 125 | People3.java 126 | 127 | public class People3 { 128 | 129 | private static People3 people3; 130 | 131 | private People3() { 132 | 133 | } 134 | 135 | synchronized public static People3 getInstance() { 136 | if (people3 == null) 137 | people3 = new People3(); 138 | return people3; 139 | } 140 | 141 | public void thinking(Listener listener3) { 142 | try { 143 | Thread.sleep(2000); 144 | } catch (InterruptedException e) { 145 | e.printStackTrace(); 146 | } 147 | listener3.onFinish("我已经思考完毕"); 148 | } 149 | 150 | } 151 | 152 | ```` 153 | 154 | 155 | ![result](http://upload-images.jianshu.io/upload_images/2585384-74c3bfc1ef9ee2aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 156 | 157 | -------------------------------------------------------------------------------- /JavaNote/Java相关/Java回调的原理与实现.md: -------------------------------------------------------------------------------- 1 | > 回调原本应该是一个非常简单的概念,但是可能因为平时只用系统为我们写好的回调的接口了,自己很少实现回调,所以在自己实现回调的时候还是有一点点晕的,现在写这篇文章记录一下,也和大家分享一下怎么写回调接口。 2 | 3 | ##回调 4 | 回调的概念:举个例子就是,我们想要问别人一道题,我们把题跟对方说了一下,对方说好,等我做完这道题,我就告诉你,这个时候就用到了回调,因为我们并不知道对方什么时候会做完,而是对方做完了来主动找我们。 5 | ####同步回调 6 | 代码运行到某一个位置的时候,如果遇到了需要回调的代码,会在这里等待,等待回调结果返回后再继续执行。 7 | ####异步回调 8 | 代码执行到需要回调的代码的时候,并不会停下来,而是继续执行,当然可能过一会回调的结果会返回回来。 9 | 10 | 11 | ---- 12 | ###具体代码: 13 | 14 | [代码链接](https://github.com/linsir6/TestCallback) 15 | 16 | 总体的代码还是很简单的,就是模拟了一个打印机,还有一个人,打印机具有打印的功能,但是打印需要时间,不能在收到任务的同时给出反馈,需要等待一段时间才能给出反馈。这个人想做的就是打印一份简历,然后知道打印的结果。这里面代码实现了这两种方式。 17 | 18 | ```` 19 | Callback.java 20 | 21 | public interface Callback { 22 | void printFinished(String msg); 23 | } 24 | 25 | ```` 26 | 27 | ```` 28 | Printer.java 29 | 30 | public class Printer { 31 | public void print(Callback callback, String text) { 32 | System.out.println("正在打印 . . . "); 33 | try { 34 | Thread.currentThread(); 35 | Thread.sleep(3000);// 毫秒 36 | } catch (Exception e) { 37 | } 38 | callback.printFinished("打印完成"); 39 | } 40 | } 41 | ```` 42 | 43 | ```` 44 | People.java 45 | 46 | public class People { 47 | 48 | Printer printer = new Printer(); 49 | 50 | /* 51 | * 同步回调 52 | */ 53 | public void goToPrintSyn(Callback callback, String text) { 54 | printer.print(callback, text); 55 | } 56 | 57 | /* 58 | * 异步回调 59 | */ 60 | public void goToPrintASyn(Callback callback, String text) { 61 | new Thread(new Runnable() { 62 | public void run() { 63 | printer.print(callback, text); 64 | } 65 | }).start(); 66 | } 67 | } 68 | ```` 69 | 70 | ```` 71 | Main.java 72 | 73 | public class Main {//测试类,同步回调 74 | public static void main(String[] args) { 75 | People people = new People(); 76 | Callback callback = new Callback() { 77 | @Override 78 | public void printFinished(String msg) { 79 | System.out.println("打印机告诉我的消息是 ---> " + msg); 80 | } 81 | }; 82 | System.out.println("需要打印的内容是 ---> " + "打印一份简历"); 83 | people.goToPrintSyn(callback, "打印一份简历"); 84 | System.out.println("我在等待 打印机 给我反馈"); 85 | } 86 | } 87 | ```` 88 | 89 | 90 | ![同步回调](http://upload-images.jianshu.io/upload_images/2585384-38d968042a37386f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 91 | 92 | 93 | ```` 94 | Main.java 95 | 96 | public class Main {//异步回调 97 | public static void main(String[] args) { 98 | People people = new People(); 99 | Callback callback = new Callback() { 100 | @Override 101 | public void printFinished(String msg) { 102 | System.out.println("打印机告诉我的消息是 ---> " + msg); 103 | } 104 | }; 105 | System.out.println("需要打印的内容是 ---> " + "打印一份简历"); 106 | people.goToPrintASyn(callback, "打印一份简历"); 107 | System.out.println("我在等待 打印机 给我反馈"); 108 | } 109 | } 110 | ```` 111 | 112 | 113 | ![异步回调](http://upload-images.jianshu.io/upload_images/2585384-2b0788ad5d711c05.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 114 | -------------------------------------------------------------------------------- /JavaNote/Java相关/Java注解的编写与Java的反射机制.md: -------------------------------------------------------------------------------- 1 | > 最近我的助理,“娃娃”问了我一次注解应该怎么写,我想注解应该太简单了吧,从我刚开始看java代码就能看到的@Override,到后来经常挺行我加上的@SuppressWarnings,当然这些注解我们用起来,看起来都是非常简单的。并且我本人是做安卓开发的,经常用各种注解框架做界面的绑定,我就简单的说了几句,利用反射啊,不改变代码逻辑,可以起到拦截的作用啊等等。但是当我自己想从头想写一个的时候,就发现并非那么简单了,经过了几个小时的研究,打算写这么一篇文章记录一下。 2 | 3 | 4 | 想了解注解标签的原理,我们最好先搞懂,java的反射机制。所以可能这篇文章的篇幅较长,希望大家可以认真的读完。 5 | 6 | > JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。 7 | 8 | 以上内容,来自百度文库。 9 | 10 | 用我的话说java的反射机制就是,可以通过程序的编写,让程序在运行时加载使用一个全新的Classes。 11 | 12 | Java反射机制主要提供了以下功能: 13 | 在运行时判断任意一个对象所属的类,在运行时构造任意一个类的对象,在运行时判断任意一个类所具有的成员变量和方法,在运行时调用任意一个对象的方法,生成动态代理。 14 | 15 | 16 | 在java中,所有类的基类是Object类,在这个函数中为我们提供了getClass()的方法。这个Class是一个非常特殊的类,由于我对这部分知识理解的也不是很到位,下面借用一下百度百科的解释吧: 17 | > Class 类十分特殊。它和一般类一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。如果您想借由“修改Java标准库源码”来观察Class 对象的实际生成时机(例如在Class的constructor内添加一个println()),这样是行不通的!因为Class并没有public constructor。 18 | 19 | 20 | 下面我们便可以开始手动实现一个注解了: 21 | 22 | 23 | 24 | ```` 25 | package annotation; 26 | 27 | import java.lang.annotation.ElementType; 28 | import java.lang.annotation.Retention; 29 | import java.lang.annotation.RetentionPolicy; 30 | import java.lang.annotation.Target; 31 | 32 | @Target(ElementType.METHOD) 33 | @Retention(RetentionPolicy.RUNTIME) 34 | public @interface Reflect { 35 | String name() default "sunguoli"; 36 | } 37 | 38 | ```` 39 | 40 | ```` 41 | package annotation; 42 | 43 | import java.lang.reflect.Method; 44 | 45 | public class ReflectProcessor { 46 | public void parseMethod(final Class clazz) throws Exception { 47 | final Object obj = clazz.getConstructor(new Class[] {}).newInstance(new Object[] {}); 48 | final Method[] methods = clazz.getDeclaredMethods(); 49 | for (final Method method : methods) { 50 | final Reflect my = method.getAnnotation(Reflect.class); 51 | if (null != my) { 52 | method.invoke(obj, my.name()); 53 | } 54 | } 55 | } 56 | } 57 | 58 | 59 | ```` 60 | 61 | 62 | ```` 63 | package annotation; 64 | 65 | public class ReflectTest { 66 | 67 | @Reflect 68 | public static void sayHello(final String name) { 69 | System.out.println("==>> Hi, " + name + " [sayHello]"); 70 | } 71 | 72 | @Reflect(name = "AngelaBaby") 73 | public static void sayHelloToSomeone(final String name) { 74 | System.out.println("==>> Hi, " + name + " [sayHelloToSomeone]"); 75 | } 76 | 77 | public static void main(final String[] args) throws Exception { 78 | final ReflectProcessor relectProcessor = new ReflectProcessor(); 79 | relectProcessor.parseMethod(ReflectTest.class); 80 | } 81 | } 82 | 83 | 84 | ```` 85 | 86 | 以上我们的接口就写完了~下面看一下运行结果~ 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | ![展示图.png](http://upload-images.jianshu.io/upload_images/2585384-a61b2ff9c871718d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 97 | 98 | 99 | 这样我们就测试了我们的注解,主要利用的是java的反射,在反射过程中调用了装载的方法就可以啦~ 100 | 101 | > 当然啊,我知道我们这里面调用的反射只能算是反射的原理和最基本的概念,我写出来的注解,都是相当的水的注解,和各种框架中的注解几乎不可能相提并论,我最近也很留意这方面的源码,有别的收货还是会分享出来的~~ 102 | -------------------------------------------------------------------------------- /JavaNote/Java相关/发布jar包到Maven中央仓库.md: -------------------------------------------------------------------------------- 1 | # 发布jar包到Maven中央仓库 2 | 3 | > 当我们开发完一些java的jar的时候,可能想将它发布到远端的代码仓库,这样就可以让更多的人同样用到它。 4 | > 同样maven也是一个非常完备的项目,我们可以在上面下载到各种我们喜欢想要的jar包,下面将介绍一下如何将本地jar包发布到maven中央仓库。 5 | 6 | 7 | ## 发布的全部流程 8 | ### 注册Sonatype账号 9 | 需要注册一个Sonatype的账号,然后在上面提交一个工单,[注册链接](https://issues.sonatype.org/secure/Signup!default.jspa ),注册之后我们需要提交一个工单,点击Create就可以创建工单了,然后我们需要填写一些它的描述信息,描述信息类似下图: 10 | ![](https://ws2.sinaimg.cn/large/006tNbRwly1ffsyt6fjhoj318w1kcjy9.jpg) 11 | 12 | 这里面填写了一个Group Id,这个一般用公司的官网就可以了,然后可能工作人员会在工单的界面进行询问这个网站的所有权是否在你的手里,只需要回答一个yes就可以了,不过如果没有官网的话,用github它所在的网址也是非常不错的。 13 | 14 | 然后这个工单应该应该就已经提完了,然后需要等待工作人员的审核,如果审核完毕这个工单的状态就会变成RESOLVED状态,当这个状态的时候我们就可以提交审核了。 15 | 16 | ### 下载gpg对发布的文件进行签名 17 | gpg应该是一个对称的加密工具,会生成公钥和私钥,[mac下载链接](https://gpgtools.org/),[windows下载链接](http://www.gpg4win.org/download.html),然后就可以通过命令行生成秘钥了。 18 | 19 | ``` 20 | gpg --gen-key 21 | ``` 22 | 通过这个命令,会提示出一些东西,我们需要输入用户名,还有邮箱,然后还会弹出来一个对话框我们需要输入密码,其它的东西我们只需要敲回车就可以了,最后我们选择O,就可以了。如下图所示: 23 | 24 | ![](https://ws3.sinaimg.cn/large/006tNbRwly1ffszb6utc6j31331o2wrf.jpg) 25 | 26 | 27 | 然后我们需要把这个gpg的key,上传到服务器,如下图所示: 28 | ![](https://ws1.sinaimg.cn/large/006tNbRwly1fft0dh64evj31kw0yhqat.jpg) 29 | 30 | 31 | ### 配置Maven下面的setting.xml 32 | 33 | ``` 34 | 35 | 38 | 39 | 40 | 41 | ossrh 42 | linSir 43 | 8888888 44 | 45 | 46 | nexus-snapshots 47 | linSir 48 | Jx1523,, 49 | 50 | 51 | 52 | 53 | 54 | ``` 55 | 56 | 这里面有三个地方我们需要注意一下,分别是,,其中username和password需要和我们提交工单的网站的账号密码所对上,id可以随便写,但是需要和pom.xml里面对上。 57 | 这里面有个小小的坑,我在这里说一下,我们需要配置的是Maven真正用到的setting.xml,我之前一直配置的是另一个Maven下面的xml,就导致一直没有权限做这件事情,希望大家不要掉进坑里。 58 | 59 | 如果用的是idea的话,可以查到Maven用到的setting.xml的位置,如下图: 60 | 61 | ![Maven所在位置的截图](http://upload-images.jianshu.io/upload_images/2585384-b8645927c2126f74.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 62 | 63 | 64 | ### 配置pom.xml 65 | 66 | ``` 67 | 68 | 71 | 4.0.0 72 | 73 | com.github.dotengine 74 | dotEngine-java-sdk 75 | 0.1.1 76 | jar 77 | dotEngine-java-sdk 78 | dot engine java sdk 79 | https://github.com/dotEngine/dotEngine-java-sdk 80 | 81 | 82 | 83 | Apache License, Version 2.0 84 | http://www.apache.org/licenses/LICENSE-2.0 85 | repo 86 | 87 | 88 | 89 | 90 | scm:git:https://github.com/dotEngine/dotEngine-java-sdk 91 | scm:git:git@github.com:dotEngine/dotEngine-java-sdk 92 | git@github.com:dotEngine/dotEngine-java-sdk 93 | 0.1.0 94 | 95 | 96 | GitHub Issues 97 | https://github.com/dotEngine/dotEngine-java-sdk/issues 98 | 99 | 100 | Web site 101 | http://dot.cc 102 | 103 | 104 | 105 | 106 | denghaizhu 107 | haizhu12345@gmail.com 108 | 109 | 110 | liulianxiang 111 | notedit@gmail.com 112 | 113 | 114 | 115 | 116 | 117 | 118 | dotEngine 119 | 0.7.0 120 | 2.8.1 121 | 4.13.1 122 | 1.7 123 | 3.0.2 124 | 3.5.1 125 | 126 | UTF-8 127 | ${user.name}-${maven.build.timestamp} 128 | 1.55 129 | 3.4 130 | 4.12 131 | 1.6.5 132 | 2.19.1 133 | 134 | 135 | 136 | io.jsonwebtoken 137 | jjwt 138 | ${jwt.version} 139 | provided 140 | 141 | 142 | com.fasterxml.jackson.core 143 | jackson-databind 144 | ${jackjson.version} 145 | provided 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | ossrh 154 | https://oss.sonatype.org/content/repositories/snapshots 155 | 156 | 157 | ossrh 158 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | org.apache.maven.plugins 167 | maven-source-plugin 168 | 2.2.1 169 | 170 | 171 | attach-sources 172 | 173 | jar-no-fork 174 | 175 | 176 | 177 | 178 | 179 | org.apache.maven.plugins 180 | maven-javadoc-plugin 181 | 2.9.1 182 | 183 | 184 | attach-javadocs 185 | 186 | jar 187 | 188 | 189 | 190 | 191 | 192 | org.apache.maven.plugins 193 | maven-gpg-plugin 194 | 1.5 195 | 196 | 197 | sign-artifacts 198 | verify 199 | 200 | sign 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | ``` 225 | 226 | 这个是我配置的我的项目的pom.xml,大家可以参考一下,注意的就是要和setting里面的id对上,还有一些基本的配置,大家可以参考我的项目,改成自己项目需要的。 227 | 228 | 229 | ### 上传 230 | 231 | ``` 232 | mvn clean deploy -X 233 | ``` 234 | 235 | 236 | ![结果](http://upload-images.jianshu.io/upload_images/2585384-aa6f7a2ba2ec0041.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 237 | 238 | 最后我们就能看到结果了,然后登陆[仓库的网站](https://oss.sonatype.org/#stagingRepositories)网站,查看我们提交的代码 239 | 240 | 241 | ![提交完成的代码.png](http://upload-images.jianshu.io/upload_images/2585384-fed37b08edb17cf9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 242 | 243 | ### 联系工作人员close掉这个issues 244 | 在工单的下面,就可以通知工作人员关闭这个工单的,同时我们需要在上图的界面中close掉这个,close的时候可能需要输入一些描述性信息,当关闭成功之后,再次选中这个,然后右侧还有一个release,点击之后同样需要输入描述信息,然后等几个小时,就可以在Maven的中央仓库中找到我们提交的库了。 245 | 246 | [中央仓库地址](http://search.maven.org/#search%7Cga%7C1%7C) 247 | 248 | 搜索到的效果图: 249 | 250 | ![效果图](http://upload-images.jianshu.io/upload_images/2585384-58eadc0aeca8818f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 251 | 252 | ---- 253 | 254 | 以上便是上传的全部过程了,虽然有点折腾,但还是痛并快乐着的,等下一次,就不需要这么麻烦了~ 255 | 256 | 下一次的操作,只需要,close掉这个,然后再重新release即可 257 | 258 | 259 | ![效果图](http://upload-images.jianshu.io/upload_images/2585384-03a88f8c439ed074.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 260 | -------------------------------------------------------------------------------- /JavaNote/Java相关/面向对象的六大原则以及常见的十七种设计模式.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | > 本文转载自:[菜刀文大神的GitHub](https://github.com/helen-x/AndroidInterview/blob/master/android/Android%20%E6%BA%90%E7%A0%81%E4%B8%AD%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F(%E4%BD%A0%E9%9C%80%E8%A6%81%E7%9F%A5%E9%81%93%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E5%85%A8%E5%9C%A8%E8%BF%99%E9%87%8C).md) 4 | 5 | # 面向对象的六大原则 6 | 7 | 8 | - **单一职责原则** 9 | 10 |   所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。通俗的说,即一个类只负责一项职责,将一组相关性很高的函数、数据封装到一个类中。 11 | 12 | - **开闭原则** 13 | 14 |   对于扩展是开放的,这意味着模块的行为是可以扩展的。当应用的需求改变时,我们可以对模块进行扩展,使其具有满足那些改变的新行为。 15 |   对于修改是关闭的,对模块行为进行扩展时,不必改动模块的源代码。 16 | 17 |   通俗的说,尽量通过扩展的方式实现系统的升级维护和新功能添加,而不是通过修改已有的源代码。 18 | 19 | - **里氏替换原则** 20 | 21 |   使用“抽象(Abstraction)”和“多态(Polymorphism)”将设计中的静态结构改为动态结构,维持设计的封闭性。任何基类可以出现的地方,子类一定可以出现。 22 | 23 |   在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立。在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。 24 | 25 | - **依赖倒置原则** 26 | 27 |   高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。 28 |    29 |   程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合(各个模块之间相互传递的参数声明为抽象类型,而不是声明为具体的实现类)。 30 | 31 | - **接口隔离原则** 32 | 33 |   一个类对另一个类的依赖应该建立在最小的接口上。其原则是将非常庞大的、臃肿的接口拆分成更小的更具体的接口。 34 | 35 | - **迪米特原则** 36 | 37 |   又叫作最少知识原则,就是说一个对象应当对其他对象有尽可能少的了解。 38 |   通俗地讲,一个类应该对自己需要耦合或调用的类知道得最少,不关心被耦合或调用的类的内部实现,只负责调用你提供的方法。 39 | 40 |   下面开始设计模式学习...   41 | # 1. Singleton(单例模式) 42 | 43 | 作用:   44 | > 保证在Java应用程序中,一个类Class只有一个实例存在。 45 | 46 | 好处: 47 | >由于单例模式在内存中只有一个实例,减少了内存开销。 48 | > 49 |  单例模式可以避免对资源的多重占用,例如一个写文件时,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。 50 |    51 | >单例模式可以再系统设置全局的访问点,优化和共享资源访问。 52 | 53 | 使用情况: 54 | >建立目录 数据库连接的单线程操作 55 | > 56 | >某个需要被频繁访问的实例对象  57 | 58 | ## 1.1 使用方法 59 | 60 | **第一种形式:** 61 | 62 | ``` 63 | public class Singleton { 64 | 65 | /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */ 66 | private static Singleton instance = null; 67 | 68 | /* 私有构造方法,防止被实例化 */ 69 | private Singleton() { 70 | } 71 | 72 | /* 懒汉式:第一次调用时初始Singleton,以后就不用再生成了 73 | 静态方法,创建实例 */ 74 | public static Singleton getInstance() { 75 | if (instance == null) { 76 | instance = new Singleton(); 77 | } 78 | return instance; 79 | } 80 | } 81 | ``` 82 |   但是这有一个问题,不同步啊!在对据库对象进行的频繁读写操作时,不同步问题就大了。 83 | 84 | **第二种形式**: 85 | 86 |   既然不同步那就给getInstance方法加个锁呗!我们知道使用synchronized关键字可以同步方法和同步代码块,所以:   87 | 88 | ``` 89 | public static synchronized Singleton getInstance() { 90 | if (instance == null) { 91 | instance = new Singleton(); 92 | } 93 | return instance; 94 | } 95 | ``` 96 | 或是 97 | 98 | ``` 99 | public static Singleton getInstance() { 100 | synchronized (Singleton.class) { 101 | if (instance == null) { 102 | instance = new Singleton(); 103 | } 104 | } 105 | return instance; 106 | } 107 | ``` 108 | 109 | 获取Singleton实例: 110 | 111 | ``` 112 | Singleton.getInstance().方法() 113 | ``` 114 | ## 1.2 android中的Singleton 115 | 116 | > 软键盘管理的 InputMethodManager 117 | 118 | 源码(以下的源码都是5.1的): 119 | ``` 120 | 205 public final class InputMethodManager { 121 | //......... 122 | 211 static InputMethodManager sInstance; 123 | //......... 124 | 619 public static InputMethodManager getInstance() { 125 | 620 synchronized (InputMethodManager.class) { 126 | 621 if (sInstance == null) { 127 | 622 IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE); 128 | 623 IInputMethodManager service = IInputMethodManager.Stub.asInterface(b); 129 | 624 sInstance = new InputMethodManager(service, Looper.getMainLooper()); 130 | 625 } 131 | 626 return sInstance; 132 | 627 } 133 | 628 } 134 | ``` 135 | 136 |   使用的是第二种同步代码块的单例模式(可能涉及到多线程),类似的还有 137 |   AccessibilityManager(View获得点击、焦点、文字改变等事件的分发管理,对整个系统的调试、问题定位等) 138 |   BluetoothOppManager等。 139 | 140 | 当然也有同步方法的单例实现,比如:CalendarDatabaseHelper 141 | 142 | ``` 143 | 307 public static synchronized CalendarDatabaseHelper getInstance(Context context) { 144 | 308 if (sSingleton == null) { 145 | 309 sSingleton = new CalendarDatabaseHelper(context); 146 | 310 } 147 | 311 return sSingleton; 148 | 312 } 149 | ``` 150 | 151 | **注意Application并不算是单例模式** 152 | 153 | ``` 154 | 44 public class Application extends ContextWrapper implements ComponentCallbacks2 { 155 | 156 | 79 public Application() { 157 | 80 super(null); 158 | 81 } 159 | ``` 160 | 在Application源码中,其构造方法是公有的,意味着可以生出多个Application实例,但为什么Application能实现一个app只存在一个实例呢?请看下面: 161 | 162 | 在ContextWrapper源码中: 163 | 164 | ``` 165 | 50 public class ContextWrapper extends Context { 166 | 51 Context mBase; 167 | 52 168 | 53 public ContextWrapper(Context base) { 169 | 54 mBase = base; 170 | 55 } 171 | 172 | 64 protected void attachBaseContext(Context base) { 173 | 65 if (mBase != null) { 174 | 66 throw new IllegalStateException("Base context already set"); 175 | 67 } 176 | 68 mBase = base; 177 | 69 } 178 | ``` 179 | ContextWrapper构造函数传入的base为null, 就算有多个Application实例,但是没有通过attach()绑定相关信息,没有上下文环境,三个字。 180 | 181 | **然并卵** 182 | 183 | 184 | # 2. Factory(工厂模式) 185 | 186 | > 定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。 187 |  **对同一个接口的实现类进行管理和实例化创建** 188 | 189 | ![这里写图片描述](http://img.blog.csdn.net/20160620135007144)  190 | 191 | 假设我们有这样一个需求: 192 | 193 |   动物Animal,它有行为move()。有两个实现类cat和dog。为了统一管理和创建我们设计一个工厂模式。 194 |   同时两个子类有各自的行为,Cat有eatFish(),Dog有eatBone(). 195 | 196 | 结构图: 197 | ![这里写图片描述](http://img.blog.csdn.net/20160620141023393) 198 | 199 | Animal接口: 200 | 201 | ``` 202 | interface animal { 203 | void move(); 204 | } 205 | ``` 206 | Cat类: 207 | 208 | ``` 209 | public class Cat implements Animal{ 210 | 211 | @Override 212 | public void move() { 213 | // TODO Auto-generated method stub 214 | System.out.println("我是只肥猫,不爱动"); 215 | } 216 | public void eatFish() { 217 | System.out.println("爱吃鱼"); 218 | } 219 | } 220 | ``` 221 | Dog类: 222 | 223 | ``` 224 | public class Dog implements Animal{ 225 | 226 | @Override 227 | public void move() { 228 | // TODO Auto-generated method stub 229 | System.out.println("我是狗,跑的快"); 230 | } 231 | public void eatBone() { 232 | System.out.println("爱吃骨头"); 233 | } 234 | } 235 | ``` 236 | 那么现在就可以建一个工厂类(Factory.java)来对实例类进行管理和创建了. 237 | 238 | ``` 239 | public class Factory { 240 | //静态工厂方法 241 | //多处调用,不需要实例工厂类 242 | public static Cat produceCat() { 243 | return new Cat(); 244 | } 245 | public static Dog produceDog() { 246 | return new Dog(); 247 | } 248 | //当然也可以一个方法,通过传入参数,switch实现 249 | } 250 | ``` 251 | 使用: 252 | 253 | ``` 254 | Animal cat = Factory.produceCat(); 255 | cat.move(); 256 | //----------------------------- 257 | Dog dog = Factory.produceDog(); 258 | dog.move(); 259 | dog.eatBone(); 260 | ``` 261 |   工厂模式在业界运用十分广泛,如果都用new来生成对象,随着项目的扩展,animal还可以生出许多其他儿子来,当然儿子还有儿子,同时也避免不了对以前代码的修改(比如加入后来生出儿子的实例),怎么管理,想着就是一团糟。 262 | 263 | ``` 264 | Animal cat = Factory.produceCat(); 265 | ``` 266 |  这里实例化了Animal但不涉及到Animal的具体子类(减少了它们之间的偶合联系性),达到封装效果,也就减少错误修改的机会。 267 | 268 |   Java面向对象的原则,封装(Encapsulation)和分派(Delegation)告诉我们:**具体事情做得越多,越容易范错误,** 269 | 270 |   一般来说,这样的普通工厂就可以满足基本需求。但是我们如果要新增一个Animal的实现类panda,那么必然要在工厂类里新增了一个生产panda的方法。就违背了 闭包的设计原则(对扩展要开放对修改要关闭) ,于是有了抽象工厂模式。 271 | 272 | ## 2.1 Abstract Factory(抽象工厂) 273 | 274 |   抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 275 |   啥意思?就是把**生产抽象成一个接口,每个实例类都对应一个工厂类**(普通工厂只有一个工厂类),**同时所有工厂类都继承这个生产接口**。 276 | 277 | 生产接口Provider: 278 | 279 | ``` 280 | interface Provider { 281 | Animal produce(); 282 | } 283 | ``` 284 | 每个产品都有自己的工厂 285 | CatFactory: 286 | 287 | ``` 288 | public class CatFactory implements Provider{ 289 | 290 | @Override 291 | public Animal produce() { 292 | // TODO Auto-generated method stub 293 | return new Cat(); 294 | } 295 | } 296 | ``` 297 | DogFactory: 298 | 299 | ``` 300 | public class DogFactory implements Provider{ 301 | 302 | @Override 303 | public Animal produce() { 304 | // TODO Auto-generated method stub 305 | return new Dog(); 306 | } 307 | } 308 | ``` 309 | 产品生产: 310 | 311 | ``` 312 | Provider provider = new CatFactory(); 313 | Animal cat =provider.produce(); 314 | cat.move(); 315 | ``` 316 |   现在我们要加入panda,直接新建一个pandaFactory就行了,这样我们系统就非常灵活,具备了动态扩展功能。 317 | 318 | ## 2.1 Android中的Factory 319 | 320 |   比如AsyncTask的抽象工厂实现: 321 | 322 | 工厂的抽象: 323 | 324 | ``` 325 | 59 public interface ThreadFactory { 326 | //省略为备注 327 | 69 Thread newThread(Runnable r); 328 | 70 } 329 | ``` 330 | 产品的抽象(new Runnable就是其实现类): 331 | 332 | ``` 333 | 56 public interface Runnable { 334 | //省略为备注 335 | 68 public abstract void run(); 336 | 69 } 337 | ``` 338 | AsyncTask中工厂类的实现: 339 | ``` 340 | 185 private static final ThreadFactory sThreadFactory = new ThreadFactory() { 341 | 186 private final AtomicInteger mCount = new AtomicInteger(1); 342 | 187 343 | 188 public Thread newThread(Runnable r) { 344 | 189 return new Thread(r, "AsyncTask #" + mCount.getAndIncrement()); 345 | 190 } 346 | 191 }; 347 | ``` 348 | 我们可以创建另外类似的工厂,生产某种专门的线程(多线程),非常容易扩展。 349 | 当然,android中的应用还有很多(比如BitmapFactory),有兴趣的小伙伴可以去扒一扒。 350 | 351 | # 3. Adapter(适配器模式) 352 | 353 | **将一个类的接口转换成客户希望的另外一个接口**。 354 | 355 |   我们经常碰到要将两个没有关系的类组合在一起使用,第一解决方案是:修改各自类的接口,但是如果我们没有源代码,或者,我们不愿意为了一个应用而修改各自的接口。 怎么办? 356 | 357 | 使用Adapter,在这两种接口之间创建一个混合接口。 358 | 359 | > 模式中的角色 360 | 361 | >需要适配的类(Adaptee):需要适配的类。 362 | 363 | >适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。 364 | 365 | >目标接口(Target):客户所期待的接口。可以是**具体的或抽象的类,也可以是接口。** 366 | 367 | ![这里写图片描述](http://img.blog.csdn.net/20160620135007144)  368 | ``` 369 | // 需要适配的类 370 | class Adaptee { 371 | public void specificRequest() { 372 | System.out.println("需要适配的类"); 373 | } 374 | } 375 | 376 | // 目标接口 377 | interface Target { 378 | public void request(); 379 | } 380 | ``` 381 | 382 | 实现方式: 383 | 384 | ①、对象适配器(采用对象组合方式实现) 385 | 386 | ``` 387 | // 适配器类实现标准接口 388 | class Adapter implements Target{ 389 | // 直接关联被适配类 390 | private Adaptee adaptee; 391 | 392 | // 可以通过构造函数传入具体需要适配的被适配类对象 393 | public Adapter (Adaptee adaptee) { 394 | this.adaptee = adaptee; 395 | } 396 | 397 | public void request() { 398 | // 这里是使用委托的方式完成特殊功能 399 | this.adaptee.specificRequest(); 400 | } 401 | } 402 | 403 | // 测试类 404 | public class Client { 405 | public static void main(String[] args) { 406 | // 需要先创建一个被适配类的对象作为参数 407 | Target adapter = new Adapter(new Adaptee()); 408 | adapter.request(); 409 | } 410 | } 411 | ``` 412 |   如果Target不是接口而是一个具体的类的情况,这里的Adapter直接继承Target就可以了。 413 | 414 | ②、类的适配器模式(采用继承实现) 415 | 416 | ``` 417 | // 适配器类继承了被适配类同时实现标准接口 418 | class Adapter extends Adaptee implements Target{ 419 | public void request() { 420 | super.specificRequest(); 421 | } 422 | } 423 | 424 | // 测试类 425 | public static void main(String[] args) { 426 | // 使用适配类 427 | Target adapter = new Adapter(); 428 | adapter.request(); 429 | } 430 | ``` 431 |   如果Target和 Adaptee都是接口,并且都有实现类。 可以通过Adapter实现两个接口来完成适配。 432 |   还有一种叫PluggableAdapters,可以动态的获取几个adapters中一个。使用Reflection技术,可以动态的发现类中的Public方法。 433 | 434 | > 优点 435 | 436 |   系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到**更好的复用**。 437 |   将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码,**更好的扩展性**。 438 | 439 | > 缺点 440 | 441 |   过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是A接口,其实内部被适配成了B接口的实现。如果不是必要,不要使用适配器,而是直接对系统进行重构。 442 | 443 | ## 3.1 Android中的Adapter 444 | 445 |   android中的Adapter就有很多了,这个大家都经常用。 446 |   Adapter是AdapterView视图与数据之间的桥梁,Adapter提供对数据的访问,也负责为每一项数据产生一个对应的View。 447 | 448 | > Adapter的继承结构 449 | 450 | ![这里写图片描述](http://img.blog.csdn.net/20160621094155219) 451 | 452 | BaseAdapter的部分源码: 453 | ``` 454 | 30public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { 455 | 31 private final DataSetObservable mDataSetObservable = new DataSetObservable(); 456 | 32 457 | 33 public boolean hasStableIds() { 458 | 34 return false; 459 | 35 } 460 | 36 461 | 37 public void registerDataSetObserver(DataSetObserver observer) { 462 | 38 mDataSetObservable.registerObserver(observer); 463 | 39 } 464 | 40 465 | 41 public void unregisterDataSetObserver(DataSetObserver observer) { 466 | 42 mDataSetObservable.unregisterObserver(observer); 467 | 43 } 468 | ``` 469 | ListAdapter, SpinnerAdapter都是Target ,数据是Adaptee ,采用对象组合方式。 470 | 471 | # 4. Chain of Responsibility(责任链模式) 472 | 473 |   使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 474 |    475 |   发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。  476 | 477 | 编程中的小体现: 478 | 479 | ``` 480 | if(a<10){ 481 | ... 482 | } 483 | else if (a<20){ 484 | ... 485 | } 486 | else if(a<30){ 487 | ... 488 | } 489 | else{ 490 | ... 491 | } 492 | ``` 493 | 程序必须依次扫描每个分支进行判断,找到对应的分支进行处理。 494 | 495 | > 责任链模式的优点 496 | 497 |   可以降低系统的耦合度(请求者与处理者代码分离),简化对象的相互连接,同时增强给对象指派职责的灵活性,增加新的请求处理类也很方便; 498 | 499 | > 责任链模式的缺点 500 | 501 |   不能保证请求一定被接收,且对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,而且在进行代码调试时不太方便。 502 |   每次都是从链头开始,这也正是链表的缺点。 503 |    504 | ## 4.1 Android中的Chain of Responsibility 505 | 506 |   触摸、按键等各种事件的传递 507 |    508 | ![这里写图片描述](http://img.blog.csdn.net/20160621101505594) 509 | 510 | 有兴趣的可以看一下这篇文章[View事件分发机制源码分析](http://blog.csdn.net/Amazing7/article/details/51274481),我这就不多说了。 511 | 512 | # 5. Observer(观察者模式) 513 | 514 |   有时被称作发布/订阅模式,观察者模式定义了一种**一对多**的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 515 | 516 |   将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的(依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。)。 517 | 518 | > 观察者模式的组成 519 | 520 | ①抽象主题(Subject) 521 | 522 |   它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。 523 | 524 | ②具体主题(ConcreteSubject) 525 | 526 |   将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。 527 | 528 | ③抽象观察者(Observer) 529 | 530 |   为所有的具体观察者定义一个接口,在得到主题通知时更新自己。 531 | 532 | ④具体观察者(ConcreteObserver) 533 | 534 |   实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。 535 | 536 | ![这里写图片描述](http://img.blog.csdn.net/20160621104419553)  537 | 538 | 言语苍白,上代码: 539 | 540 | ``` 541 | //抽象观察者 542 | public interface Observer 543 | { 544 | public void update(String str); 545 | 546 | } 547 | ``` 548 | 549 | ``` 550 | //具体观察者 551 | public class ConcreteObserver implements Observer{ 552 | @Override 553 | public void update(String str) { 554 | // TODO Auto-generated method stub 555 | System.out.println(str); 556 | } 557 | } 558 | ``` 559 | 560 | ``` 561 | //抽象主题 562 | public interface Subject 563 | { 564 | public void addObserver(Observer observer); 565 | public void removeObserver(Observer observer); 566 | public void notifyObservers(String str); 567 | } 568 | ``` 569 | 570 | ``` 571 | //具体主题 572 | public class ConcreteSubject implements Subject{ 573 | // 存放观察者 574 | private List list = new ArrayList(); 575 | @Override 576 | public void addObserver(Observer observer) { 577 | // TODO Auto-generated method stub 578 | list.add(observer); 579 | } 580 | 581 | @Override 582 | public void removeObserver(Observer observer) { 583 | // TODO Auto-generated method stub 584 | list.remove(observer); 585 | } 586 | 587 | @Override 588 | public void notifyObservers(String str) { 589 | // TODO Auto-generated method stub 590 | for(Observer observer:list){ 591 | observer.update(str); 592 | } 593 | } 594 | } 595 | ``` 596 | 下面是测试类: 597 | 598 | ``` 599 | /** 600 | * @author fanrunqi 601 | */ 602 | public class Test { 603 | public static void main(String[] args) { 604 | //一个主题 605 | ConcreteSubject eatSubject = new ConcreteSubject(); 606 | //两个观察者 607 | ConcreteObserver personOne = new ConcreteObserver(); 608 | ConcreteObserver personTwo = new ConcreteObserver(); 609 | //观察者订阅主题 610 | eatSubject.addObserver(personOne); 611 | eatSubject.addObserver(personTwo); 612 | 613 | //通知开饭了 614 | eatSubject.notifyObservers("开饭啦"); 615 | } 616 | } 617 | ``` 618 | 619 | > “关于代码你有什么想说的?” 620 | >“没有,都在代码里了” 621 | >“(⊙o⊙)哦.....” 622 | 623 | ## 5.1 Android中的Observer 624 | 625 |   观察者模式在android中运用的也比较多,最熟悉的ContentObserver。 626 | 627 | ① 抽象类ContentResolver中(Subject) 628 | 629 | 注册观察者: 630 | 631 | ``` 632 | 1567 public final void registerContentObserver(Uri uri, boolean notifyForDescendents, 633 | 1568 ContentObserver observer, int userHandle) 634 | 635 | ``` 636 | 取消观察者: 637 | 638 | ``` 639 | 1583 public final void unregisterContentObserver(ContentObserver observer) 640 | ``` 641 | 抽象类ContentObserver中(Observer) 642 | 643 | ``` 644 | 94 public void onChange(boolean selfChange) { 645 | 95 // Do nothing. Subclass should override. 646 | 96 } 647 | 648 | 144 public void onChange(boolean selfChange, Uri uri, int userId) { 649 | 145 onChange(selfChange, uri); 650 | 146 } 651 | 652 | 129 public void onChange(boolean selfChange, Uri uri) { 653 | 130 onChange(selfChange); 654 | 131 } 655 | ``` 656 |  观察特定Uri引起的数据库的变化,继而做一些相应的处理(最终都调用的第一个函数). 657 | 658 | ② DataSetObserver,其实这个我们一直在用,只是没意识到。 659 | 660 | 我们再看到BaseAdapter的部分源码: 661 | 662 | ``` 663 | 37 public void registerDataSetObserver(DataSetObserver observer) { 664 | 38 mDataSetObservable.registerObserver(observer); 665 | 39 } 666 | 40 667 | 41 public void unregisterDataSetObserver(DataSetObserver observer) { 668 | 42 mDataSetObservable.unregisterObserver(observer); 669 | 43 } 670 | 671 | ``` 672 |  上面两个方法分别向向BaseAdater注册、注销一个DataSetObserver实例。 673 | 674 | DataSetObserver 的源码: 675 | ``` 676 | 24 public abstract class DataSetObserver { 677 | 678 | 29 public void onChanged() { 679 | 30 // Do nothing 680 | 31 } 681 | 682 | 38 public void onInvalidated() { 683 | 39 // Do nothing 684 | 40 } 685 | 41} 686 | ``` 687 |   DataSetObserver就是一个观察者,它一旦发现BaseAdapter内部数据有变量,就会通过回调方法DataSetObserver.onChanged和DataSetObserver.onInvalidated来通知DataSetObserver的实现类。 688 | 689 | # 6. Builder(建造者模式) 690 |    691 |   建造者模式:是将一个复杂的对象的构建与它的表示分离(同构建不同表示),使得同样的构建过程可以创建不同的表示。 692 | 693 | >   一个人活到70岁以上,都会经历这样的几个阶段:婴儿,少年,青年,中年,老年。并且每个人在各个阶段肯定是不一样的,世界上不存在两个人在人生的这5个阶段的生活完全一样,但是活到70岁以上的人,都经历了这几个阶段是肯定的。实际上这是一个比较经典的建造者模式的例子了。 694 | 695 |   将复杂的内部创建封装在内部,对于外部调用的人来说,只需要传入建造者和建造工具,对于内部是如何建造成成品的,调用者无需关心。 696 | 697 | 建造者模式通常包括下面几个角色: 698 | 699 | ① Builder:一个抽象接口,用来规范产品对象的各个组成成分的建造。 700 | 701 | ② ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建,在建造过程完成后,提供产品的实例。 702 | 703 | ③ Director:指导者,调用具体建造者来创建复杂对象的各个部分,不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。 704 | 705 | ④ Product:要创建的复杂对象。 706 | 707 | > 与抽象工厂的区别:在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者联系的,指导者联系建造者最后得到产品。即建造模式可以强制实行一种分步骤进行的建造过程。 708 | 709 | ![这里写图片描述](http://img.blog.csdn.net/20160621134142566)  710 | 711 | 712 | Product和产品的部分Part接口 713 | ``` 714 |  public interface Product { } 715 |  public interface Part { } 716 | ``` 717 | 718 | Builder: 719 | 720 | ``` 721 | public interface Builder { 722 |     void buildPartOne(); 723 |     void buildPartTwo(); 724 |    725 |     Product getProduct(); 726 |   } 727 | ``` 728 | ConcreteBuilder: 729 | 730 | ``` 731 | //具体建造工具 732 |   public class ConcreteBuilder implements Builder { 733 |     Part partOne, partTwo; 734 | 735 |     public void buildPartOne() { 736 |       //具体构建代码 737 |     }; 738 |     public void buildPartTwo() { 739 |       //具体构建代码 740 |     }; 741 |      public Product getProduct() { 742 |       //返回最后组装的产品 743 |     }; 744 |   } 745 | ``` 746 | Director : 747 | 748 | ``` 749 |  public class Director { 750 |     private Builder builder; 751 |    752 |     public Director( Builder builder ) { 753 |       this.builder = builder; 754 |     } 755 |     public void construct() { 756 |       builder.buildPartOne(); 757 |       builder.buildPartTwo(); 758 |     } 759 |   } 760 | 761 | ``` 762 | 建造: 763 | 764 | ``` 765 | ConcreteBuilder builder = new ConcreteBuilder(); 766 | Director director = new Director(builder); 767 | //开始各部分建造  768 | director.construct(); 769 | Product product = builder.getResult(); 770 | ``` 771 | 772 | > 优点: 773 | 774 | 客户端不必知道产品内部组成的细节。 775 | 776 | 具体的建造者类之间是相互独立的,对系统的扩展非常有利。 777 | 778 | 由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。 779 | 780 | > 使用场合: 781 | 782 | 创建一些复杂的对象时,这些对象的内部组成构件间的建造**顺序是稳定**的,但是对象的内**部组成构件面临着复杂的变化**。 783 | 784 | 要创建的复杂对象的算法,独立于该对象的组成部分,也独立于组成部分的装配方法时。 785 | 786 | ## 6.1 Android中的Builder 787 | 788 |  android中的Dialog就使用了Builder Pattern,下面来看看AlertDialog的部分源码。 789 | 790 | ``` 791 | 371 public static class Builder { 792 | 372 private final AlertController.AlertParams P; 793 | 373 private int mTheme; 794 | 795 | 393 public Builder(Context context, int theme) { 796 | 394 P = new AlertController.AlertParams(new ContextThemeWrapper( 797 | 395 context, resolveDialogTheme(context, theme))); 798 | 396 mTheme = theme; 799 | 397 } 800 | ``` 801 |   AlertDialog的Builder 是一个静态内部类,没有定义Builder 的抽象接口。 802 |   对AlertDialog设置的属性会保存在Build类的成员变量P(AlertController.AlertParams)中。 803 | 804 | Builder类中部分方法: 805 | 806 | ``` 807 | 416 public Builder setTitle(int titleId) { 808 | 417 P.mTitle = P.mContext.getText(titleId); 809 | 418 return this; 810 | 419 } 811 | ``` 812 | 813 | ``` 814 | 452 public Builder setMessage(int messageId) { 815 | 453 P.mMessage = P.mContext.getText(messageId); 816 | 454 return this; 817 | 455 } 818 | 819 | ``` 820 | 821 | ``` 822 | 525 public Builder setPositiveButton(CharSequence text, final OnClickListener listener) { 823 | 526 P.mPositiveButtonText = text; 824 | 527 P.mPositiveButtonListener = listener; 825 | 528 return this; 826 | 529 } 827 | ``` 828 | 而show()方法会返回一个结合上面设置的dialog实例 829 | 830 | ``` 831 | 991 public AlertDialog show() { 832 | 992 AlertDialog dialog = create(); 833 | 993 dialog.show(); 834 | 994 return dialog; 835 | 995 } 836 | 996 } 837 | 997 838 | 998} 839 | ``` 840 | 841 | ``` 842 | 972 public AlertDialog create() { 843 | 973 final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false); 844 | 974 P.apply(dialog.mAlert); 845 | 975 dialog.setCancelable(P.mCancelable); 846 | 976 if (P.mCancelable) { 847 | 977 dialog.setCanceledOnTouchOutside(true); 848 | 978 } 849 | 979 dialog.setOnCancelListener(P.mOnCancelListener); 850 | 980 dialog.setOnDismissListener(P.mOnDismissListener); 851 | 981 if (P.mOnKeyListener != null) { 852 | 982 dialog.setOnKeyListener(P.mOnKeyListener); 853 | 983 } 854 | 984 return dialog; 855 | 985 } 856 | ``` 857 | 858 | 简单建造: 859 | 860 | ``` 861 | new AlertDialog.Builder(context) 862 | .setTitle("标题") 863 | .setMessage("消息框") 864 | .setPositiveButton("确定", null) 865 | .show(); 866 | ``` 867 | # 7. Memento(备忘录模式) 868 | 869 |   备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式。 870 | 871 |   备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一同使用。 872 | 873 | 备忘录模式所涉及的角色有三个: 874 | 875 | ① Originator(发起人): 负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可使用备忘录恢复内部状态。Originator可根据需要决定Memento存储Originator的哪些内部状态。  876 | 877 | ② Memento(备忘录): 负责存储Originnator对象的内部状态,并可防止Originator以外的其他对象访问备忘录Memento,备忘录有两个接口,Caretaker只能看到备忘录的窄接口,它只能将备忘录传递给其他对象。 878 | 879 | ③、 Caretaker(管理者):负责保存好备忘录Memento,不能对备忘录的内容进行操作或检查。 880 | 881 |  ![这里写图片描述](http://img.blog.csdn.net/20160621134142566)  882 | 883 | ``` 884 | public class Originator { 885 | 886 | private String state; 887 | /** 888 | * 工厂方法,返回一个新的备忘录对象 889 | */ 890 | public Memento createMemento(){ 891 | return new Memento(state); 892 | } 893 | /** 894 | * 将发起人恢复到备忘录对象所记载的状态 895 | */ 896 | public void restoreMemento(Memento memento){ 897 | this.state = memento.getState(); 898 | } 899 | 900 | public String getState() { 901 | return state; 902 | } 903 | 904 | public void setState(String state) { 905 | this.state = state; 906 | System.out.println("当前状态:" + this.state); 907 | } 908 | 909 | } 910 | ``` 911 | 912 | ``` 913 | public class Memento { 914 | 915 | private String state; 916 | 917 | public Memento(String state){ 918 | this.state = state; 919 | } 920 | 921 | public String getState() { 922 | return state; 923 | } 924 | 925 | public void setState(String state) { 926 | this.state = state; 927 | } 928 | 929 | } 930 | ``` 931 | 932 | ``` 933 | public class Caretaker { 934 | 935 | private Memento memento; 936 | /** 937 | * 备忘录的取值方法 938 | */ 939 | public Memento retrieveMemento(){ 940 | return this.memento; 941 | } 942 | /** 943 | * 备忘录的赋值方法 944 | */ 945 | public void saveMemento(Memento memento){ 946 | this.memento = memento; 947 | } 948 | } 949 | ``` 950 | 951 | 使用: 952 | 953 | ``` 954 | Originator o = new Originator(); 955 | Caretaker c = new Caretaker(); 956 | //改变负责人对象的状态 957 | o.setState("On"); 958 | //创建备忘录对象,并将发起人对象的状态储存起来 959 | c.saveMemento(o.createMemento()); 960 | //修改发起人的状态 961 | o.setState("Off"); 962 | //恢复发起人对象的状态 963 | o.restoreMemento(c.retrieveMemento()); 964 | ``` 965 | 不需要了解对象的内部结构的情况下备份对象的状态,方便以后恢复。 966 | 967 | ## 7.1 Android中的Memento 968 | 969 |   Activity的onSaveInstanceState和onRestoreInstanceState就是通过Bundle(相当于备忘录对象)这种序列化的数据结构来存储Activity的状态,至于其中存储的数据结构,这两个方法不用关心。 970 | 971 | 还是看一下源码: 972 | 973 | ``` 974 | 1365 protected void onSaveInstanceState(Bundle outState) { 975 | 1366 outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState()); 976 | 1367 Parcelable p = mFragments.saveAllState(); 977 | 1368 if (p != null) { 978 | 1369 outState.putParcelable(FRAGMENTS_TAG, p); 979 | 1370 } 980 | 1371 getApplication().dispatchActivitySaveInstanceState(this, outState); 981 | 1372 } 982 | ``` 983 | 984 | ``` 985 | 1019 protected void onRestoreInstanceState(Bundle savedInstanceState) { 986 | 1020 if (mWindow != null) { 987 | 1021 Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG); 988 | 1022 if (windowState != null) { 989 | 1023 mWindow.restoreHierarchyState(windowState); 990 | 1024 } 991 | 1025 } 992 | 1026 } 993 | ``` 994 | ## 8. Prototype(原型模式) 995 | 996 |   原型模式,能快速克隆出一个与已经存在对象类似的另外一个我们想要的新对象。 997 |   工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。 998 | 999 |   分为深拷贝和浅拷贝。深拷贝就是把对象里面的引用的对象也要拷贝一份新的对象,并将这个新的引用对象作为拷贝的对象引用(多读两遍)。 1000 | 1001 |  一般使用原型模式有个明显的特点,就是实现cloneable的clone()方法。 1002 | 1003 | 在Intent源码中: 1004 | ``` 1005 | 4084 @Override 1006 | 4085 public Object clone() { 1007 | 4086 return new Intent(this); 1008 | 4087 } 1009 | ``` 1010 | 这里Intent通过实现Cloneable接口来实现原型拷贝。 1011 | 1012 | ## 9. Strategy(策略模式) 1013 |    1014 |   定义:有一系列的算法,将每个算法封装起来(每个算法可以封装到不同的类中),各个算法之间可以替换,策略模式让算法独立于使用它的客户而独立变化。 1015 | 1016 |   举例: 1017 |   一个影碟机,你往里面插什么碟子,就能放出什么电影。 1018 |   属性动画,设置不同的插值器对象,就可以得到不同的变化曲线。 1019 |   返回值解析,传入什么样的解析器,就可以把二进制数据转换成什么格式的数据,比如String、Json、XML。 1020 | 1021 |   策略模式其实就是多态的一个淋漓精致的体现。 1022 | 1023 | 在android中不同Animation动画的实现,主要是依靠Interpolator的不同而实现的。 1024 | 1025 | ``` 1026 | 401 public void setInterpolator(Interpolator i) { 1027 | 402 mInterpolator = i; 1028 | 403 } 1029 | ``` 1030 | ## 10. Template(模板模式) 1031 | 1032 |   定义:定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定的步骤。 1033 |    1034 |   **实现流程已经确定,实现细节由子类完成**。 1035 |    1036 |   生命周期对于我们都不陌生,它就是典型的Template模式,在具体流程确定的情况下,至于我们要复写生命周期那些方法,实现那些功能由继承activity的子类去具体实现。 1037 | 1038 |   关键在于必须有具体的执行流程,比如AsyncTask。 1039 | 1040 | ## 11. Proxy(代理模式) 1041 | 1042 |   定义:为其他对象提供一种代理以控制对这个对象的访问。 1043 |   代理: 在出发点到目的地之间有一道中间层。 1044 | 1045 | 应用:Android跨进程通信方式 ,建议去了解一下Binder机制。 1046 | 1047 | ## 12. Interpreter(解释器模式) 1048 | 1049 |   定义语言的文法,并且建立一个解释器来解释该语言中的句子。 1050 | 1051 | 比如Android中通过PackageManagerService来解析AndroidManifest.xml中定义的Activity、service等属性。 1052 | 1053 | ## 13. State(状态模式) 1054 | 1055 |   行为是由状态来决定的,不同状态下有不同行为。 1056 | 1057 |   注意:状态模式的行为是平行的、不可替换的,策略模式的行为是彼此独立可相互替换的。 1058 | 1059 |   体现:不同的状态执行不同的行为,当WIFI开启时,自动扫描周围的接入点,然后以列表的形式展示;当wifi关闭时则清空。 1060 | 1061 | ## 14. Command(命令模式) 1062 | 1063 |   我们有很多命令,把它们放在一个下拉菜单中,用户通过先选择菜单再选择具体命令,这就是Command模式。 1064 | 1065 |   本来用户(调用者)是直接调用这些命令的,在菜单上打开文档,就直接指向打开文档的代码,使用Command模式,就是在这两者之间增加一个中间者,将这种直接关系拗断,同时两者之间都隔离,基本没有关系了。 1066 |    1067 |   显然这样做的好处是符合封装的特性,降低耦合度,有利于代码的健壮性 可维护性 还有复用性。Command是将对行为进行封装的典型模式,Factory是将创建进行封装的模式。 1068 | 1069 |   android底层逻辑对事件的转发处理就用到了Command模式。 1070 | 1071 | ## 15. Iterator(迭代模式) 1072 | 1073 |   提供一种方法顺序访问一个容器对象中的各个元素,而不需要暴露该对象的内部表示。 1074 | 1075 | 应用: 1076 | 1077 | 在Java中的Iterator类。 1078 | 1079 | Android中的 Cursor。 1080 | 1081 | ``` 1082 | cursor.moveToFirst(); 1083 | ``` 1084 | 1085 | ## 16. Composite(组合模式)   1086 | 1087 |   将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。 1088 | 1089 |   Android中View的结构是树形结构,每个ViewGroup包含一系列的View,而ViewGroup本身又是View。这是Android中非常典型的组合模式。 1090 |    1091 | ## 17. Flyweight(共享模式/享元模式)  1092 | 1093 |   定义:避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类)。 1094 | 1095 |   面向对象语言的原则就是一切都是对象,但是如果真正使用起来,有时对象数可能显得很庞大,比如,字处理软件,如果以每个文字都作为一个对象,几千个字,对象数就是几千,无疑耗费内存,那么我们还是要"求同存异",找出这些对象群的共同点,设计一个元类,封装可以被共享的类,另外,还有一些特性是取决于应用(context),是不可共享的,这也Flyweight中两个重要概念内部状态intrinsic和外部状态extrinsic之分。 1096 | 1097 | 说白点,就是先捏一个的原始模型,然后随着不同场合和环境,再产生各具特征的具体模型,很显然,在这里需要产生不同的新对象,所以Flyweight模式中常出现Factory模式。Flyweight的内部状态是用来共享的,Flyweight factory负责维护一个Flyweight pool(模式池)来存放内部状态的对象。 1098 | 1099 | Flyweight模式是一个提高程序效率和性能的模式,会大大加快程序的运行速度。应用场合很多:比如你要从一个数据库中读取一系列字符串,这些字符串中有许多是重复的,那么我们可以将这些字符串储存在Flyweight池(pool)中。 1100 | 1101 | 1102 |   在Android线程通信中,每次获取Message时调Message.obtain()其实就是从消息池中取出可重复使用的消息,避免产生大量的Message对象。 1103 |    1104 | ## 最后 1105 | 1106 | 1107 | > 那么问题来了,什么是设计模式? 1108 | 1109 | 1110 | ![这里写图片描述](http://img.blog.csdn.net/20160621150602180) 1111 | 1112 | > 设计模式是前辈、大牛在实际编程中对遇到的问题解决方案的抽象。 1113 | 1114 | 1115 | -------------------------------------------------------------------------------- /JavaNote/img/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linsir6/JavaNote/fb1729c39160fbcd3d2e0e161154f26dab873593/JavaNote/img/background.jpg -------------------------------------------------------------------------------- /JavaNote/img/background2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linsir6/JavaNote/fb1729c39160fbcd3d2e0e161154f26dab873593/JavaNote/img/background2.jpg -------------------------------------------------------------------------------- /JavaNote/test.java: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /JavaNote/设计模式相关/单例模式.md: -------------------------------------------------------------------------------- 1 | #单例模式 2 | 3 | > 单例模式,顾名思义,就是我们的代码中只实例化出一个对象,就是单例模式,有的人说,为什么用单例模式啊,这个很简单,因为有一些时候,不是所有的对象都可以被实例化多次的,因为,无论是内存空间的大小,和逻辑关系上面都是不允许的,举个最简单的例子,有一件事情,需要皇上去做,但是由于客观事实的要求,我们只能有且只有一个皇上,所以这个时候一定要控制,对象数量的个数,不能够超过1,以下我会为大家介绍单例模式怎么实现。 4 | 5 | 单例模式,比较重要的应用是,我们可以确保我们的线程安全,因为如果我们用多个对象来操作我们的线程池的时候是很为危险的。 6 | 7 | 单例模式,同时又会分为饿汉模式,和懒汉模式,他们有一点不同,饿汉模式是在初始化类的时候,就把对象声明好,而懒汉模式,则是在调用的时候再去声明这个对象,不过他们起到的效果是一样的,就是都能确保对象的唯一性。 8 | 9 | 饿汉模式: 10 | ```` 11 | 12 | public class Singleton { 13 | private Singleton() { 14 | } 15 | private static Singleton iSingleton = new Singleton(); 16 | public static Singleton getInstance() { 17 | return iSingleton; 18 | } 19 | } 20 | 21 | public class Test { 22 | public static void main(String[] args) { 23 | Singleton aSingleton = Singleton.getInstance(); 24 | Singleton bSingleton = Singleton.getInstance(); 25 | if (aSingleton==bSingleton) { 26 | System.out.println(true); 27 | }else { 28 | System.out.println(false); 29 | } 30 | } 31 | } 32 | 33 | ```` 34 | 35 | 当我们将构造方法,变成私有之后,便不能够再通过new的方法来创造对象了,但是我们有暴露一个接口,让用户来获取我们已经写好了对象,这样就能够确保我们所有用到的所有的对象,都是同一个对象了,当然我还加上了测试,当然最终的结果肯定是true了。 36 | 37 | ---- 38 | 39 | 懒汉模式: 40 | > 懒汉模式和饿汉模式不同的仅仅是,当第一个人访问这个对象的时候,这个对象是不存在的,只需要新建一个这个对象就可以了。 41 | 42 | ```` 43 | 44 | public class Singleton2 { 45 | private Singleton2() { 46 | } 47 | private static Singleton2 singleton2; 48 | public static Singleton2 getInstance() { 49 | if (singleton2 == null) { 50 | singleton2 = new Singleton2(); 51 | } 52 | return singleton2; 53 | } 54 | } 55 | 56 | ```` 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /JavaNote/设计模式相关/单例模式的四种实现方式.md: -------------------------------------------------------------------------------- 1 | # 单例模式的四种实现方式 2 | 3 | > 原本单纯的我一直认为这世界上的单例模式,只有饿汉和懒汉呢,今天发现了,原来单例模式有四种实现方式。 4 | 5 | 6 | ## 饿汉模式 7 | 8 | ``` 9 | public class Singleton { 10 | /** 11 | * 饿汉式 12 | */ 13 | private Singleton() { 14 | 15 | } 16 | 17 | private static final Singleton SINGLETON = new Singleton(); 18 | 19 | public static Singleton getInstance(){ 20 | return SINGLETON; 21 | } 22 | 23 | public void system(){ 24 | System.out.println("---lin---> singleton"); 25 | } 26 | 27 | } 28 | 29 | ``` 30 | 31 | ## 懒汉模式 32 | 33 | ``` 34 | public class Singleton2 { 35 | /** 36 | * 懒汉式 37 | */ 38 | private Singleton2() { 39 | 40 | } 41 | 42 | private static Singleton2 singleton2 = null; 43 | 44 | public static Singleton2 getInstance() { 45 | if (singleton2 == null) { 46 | synchronized (Singleton.class) { 47 | if (singleton2 == null) { 48 | singleton2 = new Singleton2(); 49 | } 50 | } 51 | } 52 | return singleton2; 53 | } 54 | 55 | public void system(){ 56 | System.out.println("---lin---> singleton2"); 57 | } 58 | } 59 | 60 | ``` 61 | 62 | ## 枚举模式 63 | 64 | ``` 65 | public enum Singleton3 { 66 | INSTANCE; 67 | private Singleton3(){ 68 | 69 | } 70 | 71 | public void system(){ 72 | System.out.println("---lin---> singleton3"); 73 | } 74 | } 75 | 76 | ``` 77 | 78 | ## Holder模式 79 | 80 | ``` 81 | public class Singleton4 { 82 | /** 83 | * 带有Holder的方式 84 | * 类级内部类,也就是静态的成员内部类,该内部类的实例与外部类的实例没有绑定关系 85 | * 只有被调用的时候才会装在,从而实现了延迟加载 86 | */ 87 | private Singleton4() { 88 | 89 | } 90 | 91 | private static class SingletonHolder { 92 | /** 93 | * 静态初始化器,由JVM来保证线程安全 94 | */ 95 | public static final Singleton4 INSTANCE = new Singleton4(); 96 | } 97 | 98 | public static Singleton4 getInstance() { 99 | return SingletonHolder.INSTANCE; 100 | } 101 | 102 | public void system() { 103 | System.out.println("---lin---> singleton4"); 104 | } 105 | } 106 | ``` 107 | 108 | -------------------------------------------------------------------------------- /JavaNote/设计模式相关/观察者模式.md: -------------------------------------------------------------------------------- 1 | #设计模式-观察者模式 2 | 3 | 4 | > 观察者模式:观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。 5 | 6 | 7 | ![图片来自网络](http://upload-images.jianshu.io/upload_images/2585384-1efae6ff8877c554.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 8 | 9 | 10 | 实现方式:观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。 11 | 观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。 12 | 13 | ---- 14 | 15 | 过程:比较直观的方式就是当你注册了我们的服务的时候,就会收到通知,当你撤销注册的时候就不会再收到通知。 16 | 17 | 18 | ---- 19 | 20 | 实例1:(我们以一个微信公众号和一个qq的订阅号为订阅者提供消息,为实例的代码让大家看一下)(自己纯手写了一个观察者模式): 21 | 22 | 23 | ```` 24 | 25 | ObjectForWeiXin.java: 26 | /* 27 | * @author linSir; 28 | * 2016-08-04 29 | * 这是一个微信的公众号 30 | */ 31 | 32 | public class ObjectForWeiXin implements Subject { 33 | /* 34 | * 一个观察者的集合 35 | */ 36 | private List observers = new ArrayList(); 37 | 38 | private String msg;// 微信提示的消息 39 | 40 | @Override 41 | public void registerObserber(Observer obsever) { 42 | 43 | observers.add(obsever);//向用户集合中添加用户 44 | } 45 | 46 | @Override 47 | public void removeObserver(Observer obserber) {//移除观察者 48 | int index = observers.indexOf(obserber); 49 | if (index >= 0) { 50 | observers.remove(index); 51 | } 52 | 53 | } 54 | 55 | @Override 56 | public void notifyObservers() {//遍历,让每一个用户都更新 57 | for (Observer observer : observers) { 58 | observer.update(msg); 59 | } 60 | 61 | } 62 | 63 | public void setMsg(String msg) {//设置推送信息 64 | this.msg = msg; 65 | notifyObservers(); 66 | } 67 | 68 | } 69 | 70 | 71 | ```` 72 | 73 | 74 | ```` 75 | Observer.java: 76 | /* 77 | * @author linSir; 78 | * 2016-08-04 79 | * 所有用户的基类,有一个更新消息的方法 80 | */ 81 | 82 | public interface Observer { 83 | 84 | public void update(String msg); 85 | 86 | } 87 | 88 | 89 | ```` 90 | 91 | 92 | ```` 93 | 94 | Observer1.java: 95 | /* 96 | * @author linSir; 97 | * 2016-08-04 98 | * 模拟的用户1 99 | */ 100 | 101 | public class Observer1 implements Observer { 102 | 103 | 104 | public Observer1(Subject subject) { 105 | subject.registerObserber(this); 106 | } 107 | 108 | public Observer1(Subject subject,Subject subject2) { 109 | subject.registerObserber(this); 110 | subject2.registerObserber(this); 111 | } 112 | 113 | @Override 114 | public void update(String msg) { 115 | System.out.println("我(O1)收到消息是--->" + msg + ",我要记下来"); 116 | } 117 | 118 | } 119 | 120 | ```` 121 | 122 | 123 | 124 | ```` 125 | 126 | Observer2.java: 127 | /* 128 | * @author linSir; 129 | * 2016-08-04 130 | * //模拟的用户2 131 | */ 132 | 133 | public class Observer2 implements Observer{ 134 | 135 | private Subject subject; 136 | 137 | public Observer2(Subject subject) { 138 | this.subject=subject; 139 | subject.registerObserber(this); 140 | } 141 | 142 | @Override 143 | public void update(String msg) { 144 | System.out.println("我(O2)收到消息是--->" + msg + ",我要记下来"); 145 | 146 | } 147 | } 148 | 149 | ```` 150 | 151 | 152 | ```` 153 | 154 | Subject.java: 155 | /* 156 | * @author lin_sir; 157 | * 2016-08-04 158 | */ 159 | 160 | public interface Subject { 161 | /* 162 | * 注册一个观察者 163 | */ 164 | public void registerObserber(Observer obsever); 165 | 166 | /* 167 | * 移除一个观察者 168 | */ 169 | public void removeObserver(Observer obserber); 170 | 171 | /* 172 | * 通知所有观察者 173 | */ 174 | public void notifyObservers(); 175 | 176 | } 177 | 178 | ```` 179 | 180 | ```` 181 | 182 | Test.java: 183 | /* 184 | * 测试类 185 | * 用户1订阅了两个公众号,用户2订阅了一个微信的公众号 186 | */ 187 | public class Test { 188 | 189 | public static void main(String[] args) { 190 | 191 | ObjectForWeiXin weiXin = new ObjectForWeiXin(); 192 | ObjectForQQ qq = new ObjectForQQ(); 193 | 194 | Observer observer1 = new Observer1(weiXin, qq); 195 | Observer observer2 = new Observer2(weiXin); 196 | 197 | qq.setMsg("qq : 祝大家开心快乐!"); 198 | weiXin.setMsg("微信 :祝大家财源滚滚!"); 199 | } 200 | } 201 | 202 | ```` 203 | 204 | 205 | ```` 206 | 输出结果: 207 | 我(O1)收到消息是--->qq : 祝大家开心快乐!,我要记下来 208 | 我(O1)收到消息是--->微信 :祝大家财源滚滚!,我要记下来 209 | 我(O2)收到消息是--->微信 :祝大家财源滚滚!,我要记下来 210 | 211 | ```` 212 | 213 | 214 | 以上便是我们的手写的观察者模式了; 215 | 216 | **** 217 | 218 | 实例2:(我们以一个微信公众号和QQ公众号为实例的代码让大家看一下)(利用java内置的观察者模式来完成): 219 | 220 | 下面我们使用java内置的类实现观察者模式: 221 | 222 | ```` 223 | Observer1.java: 224 | /* 225 | * @author linSir; 226 | * 2016-08-04 227 | */ 228 | public class Observer1 implements Observer {//模拟的用户 229 | 230 | public void registerSubject(Observable observable) { 231 | observable.addObserver((Observer) this); 232 | } 233 | 234 | public void update(Observable o, Object arg) { 235 | if (o instanceof SubjectForWeiSXin) { 236 | SubjectForWeiSXin subjectFor3d = (SubjectForWeiSXin) o; 237 | System.out.println("subjectForWeiXin's msg -- >" + subjectFor3d.getMsg()); 238 | } 239 | 240 | if (o instanceof SubjectForQQ) { 241 | SubjectForQQ subjectForSSQ = (SubjectForQQ) o; 242 | System.out.println("subjectForQQ's msg -- >" + subjectForSSQ.getMsg()); 243 | } 244 | } 245 | 246 | } 247 | ```` 248 | 249 | ```` 250 | SubjectForQQ.java: 251 | /* 252 | * @author linSir; 253 | * 2016-08-04 254 | */ 255 | 256 | public class SubjectForQQ extends Observable { 257 | 258 | private String msg; 259 | 260 | public String getMsg() { 261 | return msg; 262 | } 263 | 264 | public void setMsg(String msg) { 265 | this.msg = msg; 266 | setChanged(); 267 | notifyObservers(); 268 | } 269 | 270 | } 271 | ```` 272 | 273 | ```` 274 | SubjectForWeiSXin.java: 275 | /* 276 | * @author lin_sir; 277 | * 2016-08-04 278 | */ 279 | 280 | public class SubjectForWeiSXin extends Observable { 281 | 282 | private String msg; 283 | 284 | public String getMsg() { 285 | return msg; 286 | } 287 | 288 | public void setMsg(String msg) { 289 | this.msg = msg; 290 | setChanged(); 291 | notifyObservers(); 292 | } 293 | 294 | } 295 | ```` 296 | 297 | ```` 298 | Test.java: 299 | /* 300 | * @author linSir; 301 | * 2016-08-04 302 | */ 303 | 304 | public class Test { 305 | 306 | public static void main(String[] args) { 307 | 308 | SubjectForQQ subjectForQQ=new SubjectForQQ(); 309 | SubjectForWeiSXin subjectForWeiSXin=new SubjectForWeiSXin(); 310 | 311 | Observer1 observer1=new Observer1(); 312 | observer1.registerSubject(subjectForQQ); 313 | observer1.registerSubject(subjectForWeiSXin); 314 | 315 | subjectForQQ.setMsg("QQ让聊天更生动"); 316 | subjectForWeiSXin.setMsg("微信让聊天更简洁"); 317 | 318 | 319 | 320 | } 321 | 322 | } 323 | ```` 324 | 325 | ```` 326 | 输出结果: 327 | subjectForQQ's msg -- >QQ让聊天更生动 328 | subjectForWeiXin's msg -- >微信让聊天更简洁 329 | ```` 330 | 331 | 332 | > 以上就是我们利用java内置的观察者模式,写出来的一段示例代码了,这样的好处是代码非常的简洁,但是并没有使用接口模式,这也是一个不足之处经常为人所诟病,当然我就是抱着学习的态度去看它的,在这里就不加以评价了。 333 | -------------------------------------------------------------------------------- /JavaNote/设计模式相关/设计模式概括.md: -------------------------------------------------------------------------------- 1 | #设计模式 2 | > 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。 3 | 4 | 设计模式总共有六大原则: 5 | 1、开闭原则(Open Close Principle) 6 | 7 | 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。 8 | 9 | 2、里氏代换原则(Liskov Substitution Principle) 10 | 11 | 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科 12 | 13 | 3、依赖倒转原则(Dependence Inversion Principle) 14 | 15 | 这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。 16 | 17 | 4、接口隔离原则(Interface Segregation Principle) 18 | 19 | 这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。 20 | 21 | 5、迪米特法则(最少知道原则)(Demeter Principle) 22 | 23 | 为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。 24 | 25 | 6、合成复用原则(Composite Reuse Principle) 26 | 27 | 原则是尽量使用合成/聚合的方式,而不是使用继承。 28 | 29 | 我们广泛使用的设计模式,大概有23种,这些设计模式,可以使我们的代码复用变得更简单,可以使我们的代码的可读性变得更好,所有我们应该掌握这些设计模式,接下来,我的文章中,会着重介绍这些设计模式。 30 | 31 | > 参考文章:http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaNote 2 | 3 | [![Travis](https://img.shields.io/badge/build-passing-brightgreen.svg)](https://github.com/linsir6) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![GitHub (pre-)release](https://img.shields.io/badge/release-v1.0.0-ff69b4.svg)](https://github.com/linsir6/Android-Notes/releases) [![User](https://img.shields.io/badge/user-linsir-yellow.svg)](https://github.com/linsir6) 4 | 5 | 6 | 7 | 8 | ## Java 9 | 10 | ### 基础 11 | 12 | - [Java回调原理与实现1](/JavaNote/Java相关/Java回调的原理与实现.md) 13 | - [Java回调原理与实现2](/JavaNote/Java相关/Java利用listener实现回调,即观察者模式.md) 14 | - [大量线程的同步操作](/JavaNote/Java相关/Java利用ExecutorService实现同步执行大量线程.md) 15 | - [Java反射机制](/JavaNote/Java相关/Java注解的编写与Java的反射机制.md) 16 | - [ArrayList、LinkedList、Vector的异同](/JavaNote/Java相关/ArrayList、LinkedList、Vector的异同.md) 17 | - [Java中Error和Exception](/JavaNote/Java相关/Java中Error和Exception.md) 18 | - [Des加密算法](/JavaNote/Java相关/Des加密算法.md) 19 | - [HashTable和HashMap的异同](/JavaNote/Java相关/HashTable和HashMap的异同.md) 20 | 21 | 22 | 23 | ### 设计模式 24 | 25 | #### [设计模式概括](/JavaNote/设计模式相关/设计模式概括.md) 26 | 27 | - [单例模式](/JavaNote/设计模式相关/单例模式.md) 28 | - [单例模式的四种实现方式.md](/JavaNote/设计模式相关/单例模式的四种实现方式.md) 29 | - [观察者模式](/JavaNote/设计模式相关/观察者模式.md) 30 | - [常见的十七种设计模式总括](/JavaNote/Java相关/面向对象的六大原则以及常见的十七种设计模式.md) 31 | 32 | 33 | ### 打包 34 | 35 | - [发布jar包到Maven中央仓库](/JavaNote/Java相关/发布jar包到Maven中央仓库.md) 36 | 37 | ---- 38 | 39 | 40 | 41 | 42 | # Getting Help 43 | 44 | To report a specific problem or feature request, open a new issue on Github. For questions, suggestions, or anything else, email linsir678@gmail.com. 45 | 46 | 47 | 48 | # Author 49 | 50 | 关玮琳linSir - @[linsir6](https://github.com/linsir6) on GitHub, @[linsir.top](http://linsir.top) 51 | 52 | # License 53 | 54 | Copyright 2017 linsir 55 | 56 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 57 | 58 | [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) 59 | 60 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 61 | 62 | 63 | 64 | # PS 65 | **已经看到这里啦,不妨给个star~** 66 | 67 | ![](/JavaNote/img/background.jpg) 68 | --------------------------------------------------------------------------------