集合(下)
7 set 接口
set 接口表示一个唯一、无序的容器(和添加顺序无关)。
7.1 set 提供的方法
1 public static void main(string[] args) { 2 /** 3 * 增:add/addall 4 * 删:clear/remove/removeall/retainall 5 * 改: 6 * 查:contains/containsall 7 * 遍历:iterator 8 * 其他:size/isempty 9 */ 10 11 set<integer> set = new hashset<integer>(); 12 // [1]添加 13 // 无序 14 set.add(10); 15 set.add(3); 16 set.add(20); 17 set.add(0); 18 // 不能添加重复元素 19 boolean r = set.add(1); 20 system.out.println(set); 21 22 // 【2】删除 23 // set.remove(1); 24 // set.clear(); 25 // system.out.println(set); 26 27 // 【3】查看是否包含 28 system.out.println(set.contains(1)); 29 30 // 【4】其他 31 system.out.println(set.size()); 32 system.out.println(set.isempty()); 33 }
7.2 set 的遍历
1 public static void main(string[] args) { 2 3 set<string> set = new hashset<string>(); 4 set.add("banana"); 5 set.add("apple"); 6 set.add("coco"); 7 8 // 快速遍历 9 for (string item : set) { 10 system.out.println(item); 11 } 12 13 // 迭代器 14 iterator<string> it = set.iterator(); 15 while(it.hasnext()) { 16 string item = it.next(); 17 system.out.println(item); 18 } 19 }
8 hashset
hashset 是 set 接口的实现类,底层数据结构是哈希表。hashset 是线程不安全的(不保证同步)。优点:添加、删除、查询效率高;缺点:无序
8.1 添加自定义对象
如果向 hashset 中存储元素时,元素一定要实现hashcode方法和equals方法。
1 public class student { 2 private string id; 3 private string name; 4 private int age; 5 6 @override 7 public int hashcode() { 8 final int prime = 31; 9 int result = 1; 10 result = prime * result + age; 11 result = prime * result + ((id == null) ? 0 : id.hashcode()); 12 result = prime * result + ((name == null) ? 0 : name.hashcode()); 13 return result; 14 }//当属性相同时,两个对象的 hashcode 相同,判断两个对象相等的必要不充分条件 15 16 @override 17 public boolean equals(object obj) { 18 if (this == obj) 19 return true; 20 if (obj == null) 21 return false; 22 if (getclass() != obj.getclass()) 23 return false; 24 student other = (student) obj; 25 if (age != other.age) 26 return false; 27 if (id == null) { 28 if (other.id != null) 29 return false; 30 } else if (!id.equals(other.id)) 31 return false; 32 if (name == null) { 33 if (other.name != null) 34 return false; 35 } else if (!name.equals(other.name)) 36 return false; 37 return true; 38 }//两个对象相等的充分必要条件 39 40 @override 41 public string tostring() { 42 return "student [id=" + id + ", name=" + name + ", age=" + age + "]"; 43 } 44 45 }
9 linkedhashset
linkedhashset是set接口的实现类,底层数据结构哈希表+链表。哈希表用于散列元素;链表用于维持添加顺序。如果要添加自定义对象元素,也需要重写 hashcode 和 equals 方法。
10 treeset
treeset 是set接口的实现类,底层数据结构是二叉树。treeset 存储的数据按照一定的规则存储。存储规则让数据表现出自然顺序。
10.1 工作原理
添加一个新元素 t 的存储的步骤:
- 如果集合无元素,t 直接加入;如果集合有元素,t 和根节点比较;
- 如果 t 小于根节点;把 t 放到根节点的左子树上;重复1-3步骤
- t 大于根节点;把 t 放到根节点的右子树上;重复1-3步骤
输出时按照一定的规则:左子树->根节点->右子树
向treeset中添加元素时,一定要提供比较策略,否则会出现 classcastexception。
10.2 内部比较器
当一个自定义对象实现comparable并实现compareto方法时,通过指定具体的比较策略,此时称为内部比较器。
1 public class student implements comparable<student>{ 2 private string id; 3 private string name; 4 private int age; 5 6 @override 7 public string tostring() { 8 return "student [id=" + id + ", name=" + name + ", age=" + age + "]"; 9 } 10 11 @override 12 public int compareto(student o) { 13 if(this.getage()<o.getage()) { 14 return -1; 15 }else if(this.getage() == o.getage()) { 16 return 0; 17 }else { 18 return 1; 19 } 20 } 21 22 }
默认的比较器是按升序排列,所以只要重写的 compareto 方法也是参数较大时返回 -1 即可实现升序排列。
10.3 外部比较器
当实际开发过程中不知道添加元素的源代码、无权修改别人的代码,此时可以使用外部比较器。treeset 接受一个指定比较策略的构造方法,这些比较策略的实现类必须实现 compa-rator 接口。comparator 位于java.util包中,定义了compare (o1,o2) 用于提供外部比较策略。推荐使用匿名内部类方法实现。
1 public static void main(string[] args) { 2 3 treeset<string> set2 = new treeset<string>(new comparator<string>() { 4 5 @override 6 public int compare(string o1, string o2) { 7 return o1.length() - o2.length(); 8 } 9 10 });//比较规则是字符串长度的升序 11 12 set2.add("banana"); 13 set2.add("coco"); 14 set2.add("apple"); 15 16 set2.add("apple"); 17 system.out.println(set2); 18 19 }
11 map 接口
map接口称为键值对集合或者映射集合,其中的元素(entry)是以键值对(key-value)的形式存在。map 容器接口中提供了增、删、改、查的方式对集合进行操作。map接口中都是通过key来操作键值对,一般key是已知。通过key获取value。
11.1 map 常用方法
1 public static void main(string[] args) { 2 3 /** 4 * 增:put/putall 5 * 删:clear/remove 6 * 改:put 7 * 查:get/containskey/containsvalue 8 * 其他:isempty/size 9 */ 10 11 map<string, string> map = new hashmap<string,string>(); 12 13 // 【1】put 14 map.put("a", "apple"); 15 map.put("b", "banana"); 16 map.put("c", "coco"); 17 18 // 【2】删除 19 // map.clear(); 20 // smap.remove("a"); 21 22 // 【3】修改 23 //map.put("a", "apple x"); 24 25 // 【4】查看 26 string val = map.get("a"); 27 system.out.println(map.containskey("d")); 28 29 30 system.out.println(map); 31 }
11.2 map 的遍历
- 通过keyset() 返回map中键的set集合。
1 public static void main(string[] args) { 2 3 map<string, string> map = new hashmap<string,string>(); 4 5 map.put("b", "banana"); 6 map.put("a", "apple"); 7 map.put("c", "coco"); 8 // map无序 9 // 可以根据key的自然顺序 让map有序 => 一般用string作为key 10 system.out.println(map); 11 12 13 // 遍历 14 set<string> keys = map.keyset(); 15 for (string key : keys) { 16 system.out.println(key+"=>"+map.get(key)); 17 } 18 19 iterator<string> it = keys.iterator(); 20 while(it.hasnext()) { 21 string key = it.next(); 22 system.out.println(key+"=>"+map.get(key)); 23 } 24 }
- map 中以键值对作为元素,键值对在map中称为entry,entryset() 返回键值对的set集合,通过此集合遍历。
1 public static void main(string[] args) { 2 3 map<string, string> map = new hashmap<string,string>(); 4 5 map.put("b", "banana"); 6 map.put("a", "apple"); 7 map.put("c", "coco"); 8 // map无序 9 // 可以根据key的自然顺序 让map有序 => 一般用string作为key 10 system.out.println(map); 11 12 // entryset 13 set<entry<string, string>> entryset = map.entryset(); 14 for (entry<string, string> entry : entryset) { 15 system.out.println(entry.getkey()+"=>"+entry.getvalue()); 16 } 17 18 iterator<entry<string, string>> it2 = entryset.iterator(); 19 while(it2.hasnext()) { 20 entry<string, string> entry = it2.next(); 21 system.out.println(entry.getkey()+"=>"+entry.getvalue()); 22 } 23 }
12 hashmap
hashmap 是 map 的实现类,key 以 hashset 存储。hashmap 线程不安全,jdk1.2;hashtable 是 hashmap 的线程安全版本,jdk1.0。向hashmap中存储元素时,key一定要实现 hashcode 和 equals。
13 linkedhashmap
linkedhashmap 是 map 接口的实现类,key 以 linkedhashset 存储。哈希表散列key,链表维持key的添加顺序。
14 treemap
treemap 是 map 的实现类,key 以 treeset 存储。key 如 treeset 一样要具有比较器。