目录

一、UML类图几种关系的总结

1. 泛化(Generalization)

2. 实现(Realization)

3. 关联(Association)

4. 聚合(Aggregation)

5. 组合(Composition)

6. 依赖(Dependency)

二、常用集合类的UML图

三、List集合

List实现类

1.ArrayList

ArrayList的删除注意事项

2.LinkedList

3.Vector

4.CopyOnWriteArrayList

四、set集合

用foreach和迭代器进行遍历

set实现类

1.HashSet

2.TreeSet

五、map集合

map实现类

1.HashMap

遍历map数组

2.HashTable

3.ConcurrentHashMap

4.TreeMap

5.LinkedHashMap


一、UML类图几种关系的总结

1. 泛化(Generalization)

【泛化关系】:是一种继承关系,表示一般与特殊的关系,它指定了子类如何特化父类的所有特征和行为。例如:老虎是动物的一种,即有老虎的特性也有动物的共性。

【箭头指向】:带三角箭头的实线,箭头指向父类

2. 实现(Realization)

【实现关系】:是一种类与接口的关系,表示类是接口所有特征和行为的实现.

【箭头指向】:带三角箭头的虚线,箭头指向接口

3. 关联(Association)

【关联关系】:是一种拥有的关系,它使一个类知道另一个类的属性和方法;如:老师与学生,丈夫与妻子关联可以是双向的,也可以是单向的。双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。

【代码体现】:成员变量

【箭头及指向】:带普通箭头的实心线,指向被拥有者

上图中,老师与学生是双向关联,老师有多名学生,学生也可能有多名老师。但学生与某课程间的关系为单向关联,一名学生可能要上多门课程,课程是个抽象的东西他不拥有学生。

下图为自身关联:

4. 聚合(Aggregation)

【聚合关系】:整体与部分的关系,且部分可以离开整体而单独存在。如车和轮胎是整体和部分的关系,轮胎离开车仍然可以存在。

聚合关系是关联关系的一种,是强的关联关系;关联和聚合在语法上无法区分,必须考察具体的逻辑关系。

【代码体现】:成员变量

【箭头及指向】:带空心菱形的实心线,菱形指向整体

5. 组合(Composition)

【组合关系】:整体与部分的关系,但部分不能离开整体而单独存在。如公司和部门是整体和部分的关系,没有公司就不存在部门。

组合关系是关联关系的一种,是比聚合关系还要强的关系,它要求普通的聚合关系中代表整体的对象负责代表部分的对象的生命周期。

【代码体现】:成员变量

【箭头及指向】:带实心菱形的实线,菱形指向整体

6. 依赖(Dependency)

【依赖关系】:是一种使用的关系,即一个类的实现需要另一个类的协助,所以要尽量不使用双向的互相依赖.

【代码表现】:局部变量、方法的参数或者对静态方法的调用

【箭头及指向】:带箭头的虚线,指向被使用者

各种关系的强弱顺序:

泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖

下面这张UML图,比较形象地展示了各种类图关系:

二、常用集合类的UML图

由于上图map有点不全,可以看下图 

三、List集合

特点:元素有序,且可重复

遍历:下标,foreach,迭代器

迭代器:是一种用于访问集合的方法,可用于迭代 ArrayList 和 HashSet 等集合,terator 是 Java 迭代器最简单的实现,ListIterator 是 Collection API 中的接口, 它扩展了 Iterator 接口。

扩容:初始容量10,负载因子0.5,扩容增量0.5倍

新容量 = 原容量 + 原容量 * 0.5  ,

如 ArrayList的容量为10,一次扩容后是容量为15

 三种遍历方法 

package com.xyz.test;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;import org.junit.Before;
import org.junit.Test;public class ListTest {List<Integer> list=new ArrayList<Integer>();@Beforepublic void setup() {list.add(1);list.add(3);list.add(5);list.add(2);list.add(6);list.add(4);}/*** foreach遍历*/@Testpublic void test01() {for (Integer e : list) {System.out.println(e);}}/*** 下标遍历*/@Testpublic void test02() {for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}}/*** 迭代器遍历*/@Testpublic void test03() {Iterator<Integer> it = list.iterator();while(it.hasNext()) {System.out.println(it.next());}}}

List实现类

1.ArrayList

  • 简单数据结构,超出容量自动扩容,动态数组

  • 内部实现是基于基础的对象数组的

  • 随机访问快,遍历快

  • 不适合随机增加或删除

  • 适用于不确定数据的最大个数的情况

  • 线程不安全

ArrayList的删除注意事项

package com.xyz.test;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;import org.junit.Before;
import org.junit.Test;public class ListRemove {private List<Integer> list;@Beforepublic void setup() {list=new ArrayList<>();list.add(1);list.add(2);list.add(3);list.add(3);list.add(4);list.add(5);}/*** 删除集合中为3的元素的下标*/@Testpublic void test01() {for(int i=0;i<list.size();i++){if(list.get(i)==3) list.remove(i);}System.out.println(list);//运行结果:[1,2,3,4,5]//原因:list.get(i)拿到下标为i的元素,当两个一样的元素3相邻时,//     第一个3在判断并删除后,第二个3及其后面的所有元素的下标都会向前移动一位,//       这样第二个3就到了第一个3下标所在的位置,但是指针已经判断过第一个3所在位置的元素是否为3了,故不会删除掉第二个3}@Testpublic void test02() {for(int i=0;i<list.size();i++){if(list.get(i)==3) list.remove(i--);}System.out.println(list);//运行结果:[1,2,4,5]//原因:第一个3在判断并删除后,第二个3及其后面的所有元素的下标都会向前移动一位,//       使用了i--,即在进行删除之后指针会向前移一位,再回到删除过的下标位置进行判断,//     而这样就避免了因为ArrayList的位移现象所导致的判断遗漏。}@Testpublic void test03() {for(int i=list.size()-1;i>=0;i--){if(list.get(i)==3){list.remove(i);}}System.out.println(list);//运行结果:[1,2,4,5]//原因:这是从集合中的最后一位元素向第一位元素方向进行遍历的倒序遍历方法,//    这样即使ArrayList的位移现象发生也无法对删除产生影响}@Testpublic void test04() {for(Integer i:list){if(i==3) list.remove(i);}System.out.println(list);//运行结果:运行错误//原因:因为ArrayList中有一个变量(modCount=原数组的元素个数)还在内部封装了一个内部类(Itr),//       这个内部类实现了迭代器,当使用foreach方法遍历时,使用的是ArrayList内部类的迭代器,//    其中内部类中定义了一个改变次数的变量(expectedModCount),这个变量被赋值为外部modcount的值,//    当使用内部类(Itr)发生增加或者修改操作时,抛出异常,其目的是阻止ArrayList长度发生改变。}@Testpublic void test05() {Iterator<Integer> it=list.iterator();while(it.hasNext()){if(it.next()==3){it.remove();}}System.out.println(list);//运行结果:[1,2,4,5]//ArrayList集合在进行删除、增加等操作时,要考虑其动态位移的特性,推荐使用迭代器,会比较安全//上述代码的it.remove不要写成list.remove(i)}@Testpublic void test06() {Iterator<Integer> it=list.iterator();while(it.hasNext()){Integer value=it.next();if(value==3){list.remove(value);}}System.out.println(list);//运行结果:运行错误//由于写成了list.remove(value)}@Testpublic void test07() {list.remove(2);System.out.println(list);//运行结果:[1,2,3,4,5]//删除下标为2的元素}@Testpublic void test08() {list.remove(Integer.valueOf(2));System.out.println(list);//运行结果:[1,3,3,4,5]//删除元素2}}

2.LinkedList

  • LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部

  • 线程不安全

  • LinkedList可被用作堆栈(stack)【包括了push,pop方法】,队列(queue)或双向队列(deque)

  • 以双向链表实现,链表无容量限制,允许元素为null,线程不安全

  • 适合做随机的增加或删除

3.Vector

线程安全

并行性能慢,不建议使用

4.CopyOnWriteArrayList

  • 写时复制

  • 线程安全

  • 适合于读多,写少的场景

  • 写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array

  • 比Vector性能高

  • 最终一致性

  • 实现了List接口,使用方式与ArrayList类似

写时复制是指将原本集合中的数据复制过去,然后在复制过去的集合里的元素进行操作,最终一致性是指修改完成后,这个修改过的集合就会给到原本的集合那里

四、set集合

特点:无序,不重复

遍历:foreach,迭代器

扩容: 初始容量16,负载因子0.75,扩容增量1倍

思考:如何对List容器中的元素去重?试试以下代码吧

package com.xyz.test;import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;import org.junit.Before;
import org.junit.Test;public class SetTest {private List<Integer> list=new ArrayList<Integer>(); @Beforepublic void setup() {list.add(1);list.add(2);list.add(2);list.add(3);list.add(3);list.add(4);list.add(5);list.add(6);}/*** 使用set去重*/@Testpublic void test01() {List<Integer> tmp=new ArrayList<Integer>(new HashSet<Integer>(list));System.out.println(tmp);//运行结果:[1,2,3,4,5,6]}  }

用foreach和迭代器进行遍历

package com.xyz.test;import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;import org.junit.Before;
import org.junit.Test;public class SetTest { private Set<Integer> set=new HashSet<Integer>();@Beforepublic void setup() {set.add(1);set.add(1);set.add(2);set.add(4);set.add(4);set.add(5);set.add(3);}/*** foreach遍历*/@Testpublic void test02() {for (Integer e : set) {System.out.println(e);//运行结果:1 2 3 4 5}}/*** 迭代器遍历*/@Testpublic void test03() {Iterator<Integer> it=set.iterator();while(it.hasNext()) {System.out.println(it.next());//运行结果:1 2 3 4 5}}}

set实现类

1.HashSet

  • 它存储唯一元素并允许空值,依据对象的hashcode来确定该元素是否存在

  • 由HashMap支持

  • 不保持插入顺序

  • 非线程安全

  • 性能参数:初始容量,负载因子

默认值: 初始容量16,负载因子0.75

示例:new HashSet<>(20, 0.5f);

在上面我们用set对数组进行了去重,那对象我们能不能去重呢?

1.首先我们实例一个学生对象

package com.xyz.test;public class Student {private Integer sid;private String sname;private Integer age;public Integer getSid() {return sid;}public void setSid(Integer sid) {this.sid = sid;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((age == null) ? 0 : age.hashCode());result = prime * result + ((sid == null) ? 0 : sid.hashCode());result = prime * result + ((sname == null) ? 0 : sname.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Student other = (Student) obj;if (age == null) {if (other.age != null)return false;} else if (!age.equals(other.age))return false;if (sid == null) {if (other.sid != null)return false;} else if (!sid.equals(other.sid))return false;if (sname == null) {if (other.sname != null)return false;} else if (!sname.equals(other.sname))return false;return true;}@Overridepublic String toString() {return "Student [sid=" + sid + ", sname=" + sname + ", age=" + age + "]";}public Student(Integer sid, String sname, Integer age) {super();this.sid = sid;this.sname = sname;this.age = age;}}

不要忘了加上hashCode和equals方法,因为这两个方法是用来判断对象是否相同的

2.下面我们来测试一下能不能去重 

我们增加两个id,姓名,年龄一样的对象

package com.xyz.test;import java.util.HashSet;
import java.util.Set;import org.junit.Test;public class SetTest {@Testpublic void test04() {Set<Student> stu=new HashSet<Student>();stu.add(new Student(1, "小黑", 18));stu.add(new Student(1, "小黑", 18));stu.add(new Student(2, "小黄", 16));stu.add(new Student(3, "小白", 24));stu.add(new Student(4, "张三", 18));stu.add(new Student(5, "李四", 23));for (Student s : stu) {System.out.println(s);}}}

结果显示,只有一个增加进去了

 那我们来试一下增加两个id不同,姓名年龄相同的,看是都能增加进去还是只能增加一个?

package com.xyz.test;import java.util.HashSet;
import java.util.Set;import org.junit.Test;public class SetTest {@Testpublic void test04() {Set<Student> stu=new HashSet<Student>();stu.add(new Student(1, "小黑", 18));stu.add(new Student(2, "小黑", 18));stu.add(new Student(3, "小黄", 16));stu.add(new Student(4, "小白", 24));stu.add(new Student(5, "张三", 18));stu.add(new Student(6, "李四", 23));      for (Student s : stu) {System.out.println(s);}}}

结果显示:两个都增加成功了,因为id不同,说明这不是同一个人,没有人规定不能同名同龄

如果要进行排序,那么需要用到TreeSet

2.TreeSet

  • 是一个包含有序的且没有重复元素的集合
  • 作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序
  • TreeSet是基于TreeMap实现的

排序有两种方法,第一种是在测试类写一个比较器进行比较 ,如下面代码所示

package com.xyz.test;import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;import org.junit.Test;public class SetTest {@Testpublic void test04() {Set<Student> stu=new TreeSet<Student>(new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return o1.getSid()-o2.getSid();//o1代表第一个对象,o2代表第二个对象//o1-o2就可以实现升序//o2-o1就是实现降序}});stu.add(new Student(1, "小黑", 18));stu.add(new Student(1, "小黑", 18));stu.add(new Student(5, "小黄", 16));stu.add(new Student(6, "小白", 24));stu.add(new Student(3, "张三", 18));stu.add(new Student(4, "李四", 23));for (Student s : stu) {System.out.println(s);}}}

可以看到,这个既去重了又排序了

第二种是在实体类中写一个比较器。下面代码所示

package com.xyz.test;import java.util.Comparator;public class Student implements Comparable<Student>{private Integer sid;private String sname;private Integer age;public Integer getSid() {return sid;}public void setSid(Integer sid) {this.sid = sid;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((age == null) ? 0 : age.hashCode());result = prime * result + ((sid == null) ? 0 : sid.hashCode());result = prime * result + ((sname == null) ? 0 : sname.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Student other = (Student) obj;if (age == null) {if (other.age != null)return false;} else if (!age.equals(other.age))return false;if (sid == null) {if (other.sid != null)return false;} else if (!sid.equals(other.sid))return false;if (sname == null) {if (other.sname != null)return false;} else if (!sname.equals(other.sname))return false;return true;}@Overridepublic String toString() {return "Student [sid=" + sid + ", sname=" + sname + ", age=" + age + "]";}public Student(Integer sid, String sname, Integer age) {super();this.sid = sid;this.sname = sname;this.age = age;}@Overridepublic int compareTo(Student o) {return this.getSid()-o.getSid();}}

测试类

package com.xyz.test;import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;import org.junit.Test;public class SetTest {@Testpublic void test04() {Set<Student> stu=new TreeSet<Student>();stu.add(new Student(1, "小黑", 18));stu.add(new Student(1, "小黑", 18));stu.add(new Student(5, "小黄", 16));stu.add(new Student(6, "小白", 24));stu.add(new Student(3, "张三", 18));stu.add(new Student(4, "李四", 23));for (Student s : stu) {System.out.println(s);}}}

五、map集合

 特点:

  • 键值对,键不能重复,值可以重复,
  • 键重复则覆盖,后面的覆盖前面的,没有继承Collection接口

扩容:初始容量16,负载因子0.75,扩容增量1倍

遍历

  • 先获取所有键的Set集合,再遍历(通过键获取值)
  • 取出保存所有Entry的Set,再遍历此Set即可

map实现类

1.HashMap

  • 无序的,线程不安全,最常用,速度快

  • 内部采用数组来存放数据

 基本原理——put执行过程

Table数组中的的Node           

1.链表结构示意图

2.红黑树结构示意图

流程图中绿色标出的部分为JDK8新增的处理逻辑,目的是在Table[i]中的Node节点数量大于8时,通过红黑树提升查找速度。

获取键的值

package com.xyz.test;import java.util.HashMap;
import java.util.Map;import org.junit.Before;
import org.junit.Test;public class MapTest {private Map<String, String > map=new HashMap<String, String>();@Beforepublic void setup() {map.put("1", "小黑");map.put("2", "小白");map.put("3", "嘿嘿");map.put("4", "小蓝");}/*** 获取键的值*/@Testpublic void test01() {System.out.println(map.get("1"));//运行结果:小黑}}

遍历map数组

方法一:先获取map集合的键,再用键获取值,再遍历(通过键获取值

package com.xyz.test;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;import org.junit.Before;
import org.junit.Test;public class MapTest {private Map<String, String > map=new HashMap<String, String>();@Beforepublic void setup() {map.put("1", "小黑");map.put("1", "小黄");map.put("2", "小白");map.put("3", "嘿嘿");map.put("4", "小蓝");map.putIfAbsent("1", "aa");}/*** 遍历map数组的值*/@Testpublic void test02() {Iterator<String> it = map.keySet().iterator();while(it.hasNext()) {String key = it.next();System.out.println(map.get(key));}}}
  • 由于小黑和小黄的键重复了,所以后面的小黄覆盖了小黑
  • putIfAbsent是判断如果有那个键了就不增加,没有则增加

方法二:用Entry直接获取键与值

package com.xyz.test;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;import org.junit.Before;
import org.junit.Test;public class MapTest {private Map<String, String > map=new HashMap<String, String>();@Beforepublic void setup() {map.put("1", "小黑");map.put("1", "小黄");map.put("2", "小白");map.put("3", "嘿嘿");map.put("4", "小蓝");map.putIfAbsent("1", "aa");}@Testpublic void test03() {Iterator<Entry<String, String>> it = map.entrySet().iterator();while(it.hasNext()) {Entry<String, String> e = it.next();System.out.println("key:"+e.getKey()+"--value:"+e.getValue());}}}

2.HashTable

线程安全,不太常用

3.ConcurrentHashMap

线程安全,比HashTable性能高

4.TreeMap

  • 有序的,key值按一定的顺序排序
  • 添加或获取元素时性能较HashMap慢
  • 因为需求维护内部的红黑树,用于保证key值的顺序

5.LinkedHashMap

  • 继承HashMap

  • 维护了一个双向链表

  • LinkedHashMap是有序的,且默认为插入顺序

package com.xyz.test;import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;import org.junit.Before;
import org.junit.Test;public class MapTest {Map<String, String> linkedHashMap = new LinkedHashMap<>();@Testpublic void linkedHashMap() {linkedHashMap.put("5", "嘿嘿");linkedHashMap.put("4", "喜喜");linkedHashMap.put("1", "哈哈");linkedHashMap.put("3", "呵呵");linkedHashMap.put("3", "嗨嗨");linkedHashMap.put("4", "喜喜");linkedHashMap.put("1", "哈哈");Set<Entry<String, String>> set = linkedHashMap.entrySet();Iterator<Entry<String, String>> iterator = set.iterator();while(iterator.hasNext()) {Entry entry = iterator.next();String key = (String) entry.getKey();String value = (String) entry.getValue();System.out.println("key:" + key + ",value:" + value);}}}

可以看到是有序的,是我们的插入顺序

内容有点多,请大家耐心观看,就说到这啦~

UML类图以及常用集合相关推荐

  1. UML概述及UML类图详解

    引言 UML图有很多种,但是并非必须掌握所有的UML图,才能完整系统分析和设计工作.一般说来,在UML图中,只要掌握类图.用例图.时序图的使用,就能完成大部分的工作.也就是说,掌握UML的20%,就能 ...

  2. java集合UML类图 总览

    Java集合框架主要包括两种类型的容器, 一种是集合(Collection),存储一个元素集合, Collection 接口又有 3 种子类型,List.Set 和 Queue. 另一种是图(Map) ...

  3. 23种常用设计模式的UML类图

    23种常用设计模式的UML类图 本文UML类图参考<Head First 设计模式>(源码)与<设计模式:可复用面向对象软件的基础>(源码)两书中介绍的设计模式与UML图. 整 ...

  4. VS 2010 通过 Architecture创建UML类图设计

    [赛迪网报道]类是对应用领域或应用解决方案中概念的描述.类图以类为中心进行组织,类图中的其他元素或属于某个类,或与类相关联.类也是对象的集合,展示了对象的结构及与系统交互的行为,其目的是显示建模系统的 ...

  5. UML类图与类间六种关系表示

    1.类与类图 类封装了数据和行为,是面向对象的重要组成部分,它是具有相同属性,操作,关系的对象集合的总称. 类图是使用频率最高的UML图之一. 类图用于描述系统中所包含的类以及它们之间的相互关系,帮助 ...

  6. 【转】30分钟学会UML类图

    转自:30分钟学会UML类图 - 知乎 30分钟学会UML类图 肖继潮 UML图有很多种,但是并非必须掌握所有的UML图,才能完整系统分析和设计工作.一般说来,在UML图中,只要掌握类图.用例图.时序 ...

  7. 全面认识UML类图元素

    2019独角兽企业重金招聘Python工程师标准>>> 开发Java应用程序时,开发者要想有效地利用统一建模语言(UML),必须全面理解UML元素以及这些元素如何映射到Java.本文 ...

  8. 深入浅出UML类图(二)

    类与类之间的关系(1) 在软件系统中,类并不是孤立存在的,类与类之间存在各种关系,对于不同类型的关系,UML提供了不同的表示方式. 1. 关联关系 关联(Association)关系是类与类之间最常用 ...

  9. [轉]VS 2010 通过 Architecture创建UML类图设计

    类是对应用领域或应用解决方案中概念的描述.类图以类为中心进行组织,类图中的其他元素或属于某个类,或与类相关联.类也是对象的集合,展示了对象的结构及与系统交互的行为,其目的是显示建模系统的类型.类主要由 ...

最新文章

  1. 13个 ASP.NET MVC 的扩展
  2. 台式机BIOS被加密后密码忘记解决办法
  3. 一步一步写算法(之hash表)
  4. javascript 内部函数的定义及调用
  5. ubuntu11.04 安装sun-java6-jdk_Ubuntu下安装sun-java6-jdk和eclipse
  6. 【机器视觉】 halcon中图像获取
  7. windows 8   远程桌面(RemoteFX )
  8. 官宣,11月8号,.NET6+64位VS璀璨面世!
  9. 局域网中设备的管理之StackCluster
  10. 爬虫-urlencode与parse_qs函数
  11. mysql中sysdate(),curdate(),curtime(),now()
  12. 总结分析一下三种求解最短路问题的算法,dijkstra算法,spfa算法,floyd算法。
  13. 【渝粤教育】国家开放大学2018年春季 0706-21T行政管理学导论 参考试题
  14. Amesim17.0安装教程(基于Win64)
  15. mysql5.7绿色版安装与卸载教程
  16. win2008服务器系统玩红警,如何让Win8顺利兼容红警2
  17. java 200以内的素数_Java——200以内的质数
  18. 对于谷歌搜索的一些基本语法整理
  19. QQ如何应对中年困境?
  20. wlan网页登录认证原理

热门文章

  1. SEO中长尾关键字的挖掘与布局思路
  2. 零基础Unreal Engine 4(UE4)图文笔记之准备篇(一)
  3. 51单片机利用8266获取网络时间
  4. 探索Ristretto量化工程—问题记录
  5. 推荐一本书《Atomic Habits》
  6. 基于FPGA的数字滤波器设计(IIR滤波)
  7. 基于java的中文分词工具ANSJ
  8. PKCS #5: Password-Based Cryptography Specification Version 2.1 中文翻译
  9. 精华帖:最全的编程自学网站介绍,白嫖
  10. Service Mesh介绍