您的位置:首页 > 其它

集合框架(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
类,可以很方便地产生伪随机数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: