集合框架(Map和Collections)
2015-08-18 13:00
495 查看
一、概述
Map是一种存储键值对的存储容器,而且保证键的唯一性。提供一种以“键”标识“值”的数据存储方式。接口形式为:
Map<K,V>,其中K是此映射所维护的键的类型,V是映射值的类型。其有两个常用子类,
HashMap和
TreeMap,另有
HashTable与
HashMap功能类似,是早期版本。三者特点与不同如下:
HashMap:JDK1.2版本出现,底层使用哈希表数据结构,允许使用
null作为键值和
null值,线程非同步。
TreeMap:JDK1.2版本出现,底层使用二叉树数据结构,可用于按照键值排序,线程非同步。
Hashtable:JDK1.0版本出现,底层使用哈希表数据结构,不允许使用
null作为键值,也不允许
null作为值,线程同步。
HashMap和
Hashtable的键值需要实现
hashCode和
equals功能,应为键值是唯一的,如同在
HashSet中添加元素一样,因为底层为哈希表结构。
Collections是集合框架中的工具类,其内部有全是一些静态的方法,可以直接使用,如
sort(List<T> list)对列表进行排序,
max(...)求最大值,
min(...)求最小值,
binarySearch(...)二分查找等。
二、Map中的共性方法
clear()清空Map。
containsKey(Object o)判断是否包含key。
containsValue(Object o)判断是否包含value。
put(K, V)添加键-值对。
putAll(Map<? extends K, ? extends V>)添加另一个集合的内容。
get(Object key)获取key对应的值。
size()获取大小。
values()获取所有的值。
keySet
和entrySet
的应用
Map没有想
List和
Set的那种迭代器遍历方式,Map的遍历一般可以使用
keySet和
entrySet两种方式。
使用
keySet遍历
Map,这种方式是先获取键的集合对象,然会遍历键的集合,最后根据键的获取对应的值。示例代码如下:
import java.util.*; class Main { public static void main(String[] args) { HashMap<String, String> map = new HashMap<String, String>(); map.put("hello", "hi"); map.put("key1", "value1"); map.put("key2", "value2"); map.put("key3", "value3"); // 取出键的集合 Set<String> set = map.keySet(); Iterator<String> it = set.iterator(); // 遍历键的集合 while(it.hasNext()) { String key = it.next(); // 根据键获取值 System.out.println("(" + key + "," + map.get(key) +")"); } } } // 执行结果为 (key1,value1) (key2,value2) (key3,value3) (hello,hi)
另一中
Map的遍历方式是通过
entrySet实现的。示例代码如下:
import java.util.*; class Main { public static void main(String[] args) { HashMap<String, String> map = new HashMap<String, String>(); map.put("hello", "hi"); map.put("key1", "value1"); map.put("key2", "value2"); map.put("key3", "value3"); // 取出键-值的集合 Set<Map.Entry<String, String>> set = map.entrySet(); // 遍历键-值集合 Iterator<Map.Entry<String, String>> it = set.iterator(); while(it.hasNext()) { Map.Entry<String, String> entry = it.next(); // 通过getKey和getValue方法可获取键和值 System.out.println("(" + entry.getKey() + "," + entry.getValue() +")"); } } } // 执行结果为 (key1,value1) (key2,value2) (key3,value3) (hello,hi)
Map
使用自定义类作为键
每个学生对应一个地址,学生有姓名和年龄属性。姓名和年龄相同视为同一个学生。学生类Student需要完成
hashCode和
equals的方法功能,当
hashCode的返回值相同且
equals返回为
true时,认为两个键是同一个键,内容的值被覆盖。可以看到结果无序,且
Student(lisi1, 21)的值唯一为
tianjin,示例代码如下:
import java.util.*; class Student { private String name; private int age; Student(String name,int age) { this.name = name; this.age = age; } /** * 复写hashCode方法 */ public int hashCode() { return name.hashCode()+age*34; } /** * 复写equals方法 */ public boolean equals(Object obj) { if(!(obj instanceof Student)) throw new ClassCastException("类型不匹配"); Student s = (Student)obj; return this.name.equals(s.name) && this.age==s.age; } public String getName() { return name; } public int getAge() { return age; } public String toString() { return name+":"+age; } } class Main { public static void main(String[] args) { HashMap<Student, String> map = new HashMap<Student, String>(); map.put(new Student("lisi1",21),"beijing"); map.put(new Student("lisi1",21),"tianjin"); map.put(new Student("lisi2",22),"shanghai"); map.put(new Student("lisi3",23),"nanjing"); map.put(new Student("lisi4",24),"wuhan"); // 获取键-值集合 Set<Map.Entry<Student,String>> entrySet = map.entrySet(); // 获取键-值集合迭代器 Iterator<Map.Entry<Student,String>> it = entrySet.iterator(); // 遍历集合 while(it.hasNext()) { Map.Entry<Student,String> entry = it.next(); // 打印学生和对应的地址 System.out.println(entry.getKey() + "/" + entry.getValue()); } } } // 执行结果为 lisi4:24/wuhan lisi2:22/shanghai lisi1:21/tianjin lisi3:23/nanjing
TreeMap
使用简介
与TreeSet类似,
TreeSet是对值按一定顺序排序,而
TreeMap则是对键进行按一定顺序排序。同样的,作为
TreeMap键的类需要实现
Comparable接口或者在创建
TreeMap对象时指定比较器(实现
Comparator接口的类)。下面通过一个实例来说明,例子内容为统计一串字符串中各个字母出现的次数,并按照字母顺序输出,这里自定义一个类
CharKey作为键,让其实现Comparable接口,并覆写
hashCode(不过这里用不到)与
equals方法:
import java.util.*; import java.lang.*; class CharKey implements Comparable<CharKey> { private String key; public CharKey(char key) { this.key = String.valueOf(key); } public int compareTo(CharKey o) { return this.key.compareTo(o.getKey()); } public String getKey() { return this.key; } // 用第一个字符的Unicode代码点作为哈希值 public int hashCode() { return this.key.codePointAt(0); } // 判断字符是否相同 public boolean equals(Object o) { if(!(o instanceof CharKey)) { throw new RuntimeException("类型不匹配"); } CharKey key = (CharKey) o; return this.key.equals(key.getKey()); } } class Main { public static void main(String[] args) { // 待统计字符串 String str = "sdfgzxcvasdfxcvdf"; // 创建TreeMap对象,CharKey作为键,Integer作为值 TreeMap<CharKey, Integer> map = new TreeMap<CharKey, Integer>(); // 扫描字符串,统计各个字母出现的次数 for(int i=0; i<str.length(); i++) { // 构造第i个字母的键 CharKey key = new CharKey(str.charAt(i)); if(map.get(key) == null) { // 键不存在则是第一次,直接添加1 map.put(key, 1); } else { // 键存在,则将值取出再加1放入 map.put(key, map.get(key)+1); } } // 遍历统计的结果 Set<Map.Entry<CharKey, Integer>> entrySet = map.entrySet(); Iterator<Map.Entry<CharKey, Integer>> it = entrySet.iterator(); while(it.hasNext()) { Map.Entry<CharKey, Integer> entry = it.next(); CharKey key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key.getKey()+"("+ value +")"); } } } // 执行结果为 a(1) c(2) d(3) f(3) g(1) s(2) v(2) x(2) z(1)
三、Collections
使用简介
Collections为
java.util包中为集合框架提供的工具类,其内部全部是静态函数,如
sort(对
List进行排序),完全的定义为:
public static <T extends Comparable<? super T>> void sort(List<T> list)也就是说
T需要时实现
Comparable接口,且
T的父类实现了
Comparable接口(即使用父类的排序方法),或者使用
sort(List<T> list, Comparator<? super T> c)来指定比较器来实现自定义的数据比较。
import java.util.*; class Main { public static void main(String[] args) { ArrayList<String> list = new ArrayList<String>(); list.add("hello"); list.add("z"); list.add("haje"); list.add("vssddda"); list.add("abcdef"); // 排序前的list System.out.println(list); Collections.sort(list); // 排序后的list System.out.println(list); } } // 执行结果如下(排序前后的list) [hello, z, haje, vssddda, abcdef] [abcdef, haje, hello, vssddda, z]
binarySearch的使用,使用
binarySearch的前提必须对
list进行排序,否则无法正常使用,其返回值为所查找的元素的位置,如果元素不存在,那么返回的为
(-(插入点) - 1),如这个值为
index,那么
~index即为这个元素正在该插入的位置。同样
binarySearch也可以指定自定义比较器。示例代码如下:
import java.util.*; class Main { public static void main(String[] args) { ArrayList<String> list = new ArrayList<String>(); list.add("hello"); list.add("z"); list.add("haje"); list.add("vssddda"); list.add("abcdef"); Collections.sort(list); int index = Collections.binarySearch(list, "b"); /* 返回值为元素的位置,如果不存在则返回负数index, 然而~index则表示元素应该插入的位置 */ System.out.println("Index:" + ~index); } }
使用
Collections.reverseOreder()获取,默认逆序比较器。或者
Collections.reverseOrder(比较器)将指定比较器转化为逆序比较器。
synchronizeCollection(),
synchronizedList(),
...使集合具有多线程访问能力,
shuffle(List)将集合随机打乱等等。
四、Arrays
使用简介
Arrays为数组操作的一个工具类,功能有
asList()将数组转换为集合,但是不能对此集合进行增删操作,否则会报
UnsupportedOperationException异常。
对基本数据类型和非基本数据类型的不同写法:
// 基本数据类型数组转集合 int[] nums = {1, 3, 2}; List<int[]> list = Arrays.asList(nums); // 基本数据类型数组转集合 int[] strs = {"hello", "hi", "oo"}; List<String> list = Arrays.asList(strs);
集合转成数组,使用
toArray(t[] t)方法可以将集合转为数组,这里的参数数组的大小如果小于
list.size()那么方法会重新创建一个长度为
list.size()大小的数组,然后返回,如果大于
list.size(),那么会使用参数的数组,并将其返回,示例代码如下:
ArrayList<String> list = new ArrayList<String>(); list.add("hello"); list.add("hi"); String[] strs = list.toArray(new String[0]);
五、JDK1.5新特性
1.泛型:再上一篇集合框架已经介绍过了,即提高了程序的安全性。2.增强
for循环:格式为
for(数据类型 变量:被遍历Collection或数组)。与传统
for循环的区别在于,增强型
for必须有被遍历的对象,且无法访问下标。示例代码如下:
ArrayList<String> list = new ArrayList<String>(); for(String s : list) { // 操作 } int[] arr = {2, 3, 4}; for(int i : arr) { // 操作 }
3.自动装箱/自动拆箱:在上一篇博客已经介绍过。
4.可变参数:当方法的参数类型相同且不确定有多少个时,可以使用可变参数。注意:当还有其他参数时,可变参数必须放在参数列表的最后面,如
show(String, int...),示例代码如下:
show(1, 2, 3); show(); show(1, 2, 3, 4, 5, 6); public void show(int... arr) { // arr就是一个数组 }
5.静态导入:如
Arrays类内部全部是静态方法,可以将其直接导入使用,不需要再指明方法名,但是需要注意的是当有方法重名时,需要指明所属类,当类重名时,需要指明所属包。示例代码如下:
import java.util.*; import static java.util.Arrays.*; class Main { public static void main(String[] args) { int[] arr = {2, 4, 2, 1, 9, 8}; // 直接调用Arrays内的静态方法sort sort(arr); System.out.println(Arrays.toString(arr)); } }
六、其他对象
System类,不能被实例化,内部全是静态方法,常用的有一些内部对象,如
in和
out用于标准输入输出。一些系统相关方法,如
currentTimeMillis()用于获取系统时间(1970年1月1日到现在的毫秒数),
getProperties()获取虚拟机环境信息等。
Rumtime类,通过
getRuntime()获取对象,可以通过
Rumtime对象执行系统命令,如
getRuntime().exec("cmd");,通过
destory()杀掉进程等。
Date类,可以通过
SimpleDateFormat将
Date类转变成自定义格式。
Calendar类,通过
getInstance()获取实例,然后可以通过
get(Calendar.YEAR)获取年份或者其他等。
Math类,一些常用方法
ceil(double )上取整,
floor(double )下取整,
random()返回
[0, 1)之间的浮点数值。
Random类,可以很方便地产生伪随机数。
相关文章推荐
- PHP 页面跳转到另一个页面的多种方法方法总结
- 桌面虚拟化实施遇到的基本问题
- 利用PowerCLI不重启系统更新VMware Tools
- 如何解决inline-block元素的空白间距 css 完美解决
- 【控件】UICollectionView
- 人格的五因素模型
- 1001 - Say Cheese (Dijkstra算法)
- 矩阵相乘这个代码也应该是需要掌握的内容,今天一大早就写了一下
- 在线编辑图片(转)
- 每当在测试之路迷茫的时候来看看这篇文章
- 如何解决inline-block元素的空白间距 css 完美解决
- 【转载】【milk】This is the code that I use for my research projects.
- Java技术1-线程池
- Java虚拟机垃圾回收过程
- PAT 1096. Consecutive Factors (20)
- 网上搜集的一段php可逆加密函数
- 浅析pinyin4j源码 简单利用pinyin4j对中文字符进行自然排序(转)
- Flickr Architecture
- codeforces - 3C - Tic-tac-toe
- 开发Android硬件访问服务