Java,Map双列集合、HashMap、TreeMap、Collections集合工具类

目录

 

Map

HashMap集合

LinkedHashMap

哈希表

TreeMap,v>

Hashtable,v>

Collections工具类

运用实例


Map<K,V>

    概念

键值的映射关系的一种集合(接口),键和值是一一对应的关系,HashMap和TreeMap是Map集合的两个子实现类。

Map类的操作都是针对键操作的,跟值无关。

键是唯一的,不能包含重复的键。

    区别

Map集合和Collection的区别
MapCollection
是一种键和值的映射关系单列集合,只能存储一种类型的元素

 

HashMap和Hashtable的区别
 HashMapHashtable
安全性不安全,不同步安全,同步
效率效率高效率低
键和值允许存在null不允许存在null

    间接关系

HashSet依赖于Map接口的子实现类HashMap。
TreeSet依赖于Map接口的子实现类TreeMap。

    常用方法

        添加功能

V put(K key,V value)

    将指定的值和键关联起来,如果当前的这个键是一次存储,则返回值null,如果不是第一次存储,返回值是第一次对应的值,当前的值就把之前的键对应的值替换掉。

import java.util.HashMap;
import java.util.Map;

public class MapTest {
	public static void main(String[] args) {
		Map<String, String> m = new HashMap<String, String>();
		System.out.println(m.put("张三", "李四"));// null
		System.out.println(m.put("张三", "王五"));// 李四
	}
}

 

        获取功能

 

Set<Map.Entry<K,V>> entrySet()   

和Map集合的遍历有关系(键值对对象)

Set<K> keySet()

获取映射关系中所有的键的集合

int size()

返回此映射中的键-值映射关系数

get(Object key)

返回到指定键所映射的值

        删除功能

void clear()

删除所有映射关系

remove(Object key)

如果存在一个键的映射关系,则将其从此映射中移除

        判断功能

boolean containsKey(Object key)

如果此映射包含指定键的映射关系,则返回 true

boolean containsValue(Object value)

映射关系中是否包含指定的值

boolean isEmpty()

判断映射关系是否为空

Map集合的遍历

    利用keySet()和get(Object key)

实际开发这种方式最常用。

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapTest {
	public static void main(String[] args) {
		Map<String, String> m = new HashMap<String, String>();
		m.put("张三", "刘一");
		m.put("李四", "陈二");
		m.put("王五", "孙七");
		m.put("赵六", "周八");
		//keySet()获取映射关系中所有的键的集合
		Set<String> s=m.keySet();
		for (String key : s) {
			//通过键找值
			//get(Object key)返回到指定键所映射的值
			String value=m.get(key);
			System.out.println(key+"--\t"+value);
		}
	}
}
/**
李四--	陈二
张三--	刘一
王五--	孙七
赵六--	周八
*/

利用entrySet()

Set<Map.Entry<K,V>> entrySet()  获取所有的键值对对象

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapTest {
	public static void main(String[] args) {
		Map<String, String> m = new HashMap<String, String>();
		m.put("张三", "刘一");
		m.put("李四", "陈二");
		m.put("王五", "孙七");
		m.put("赵六", "周八");
		//获取所有的键值对对象
		Set<Map.Entry<String, String>> s =m.entrySet();
		for (Map.Entry<String, String> e : s) {
			//获取到每一个键值对对象
			//通过键值对对象找键和值
			String key=e.getKey();
			String value=e.getValue();
			System.out.println(key+"---\t"+value);
		}
	}
}
/**
李四---	陈二
张三---	刘一
王五---	孙七
赵六---	周八
*/

HashMap集合

    基于哈希表的实现的Map接口。

存储自定义对象,因为键具有唯一性,当自定义对象作为键的时候需要在自定义对象中重写hashCode()和equals()方法才能保证唯一性。

import java.util.HashMap;
import java.util.Set;

class Student{
	private String name;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Student() {
		super();
	}
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	//重写hashCode
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	//重写equals
	@Override
	public 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 != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	@Override
	public String toString() {
		return "学生:[姓名=" + name + ", 年龄=" + age + "]";
	}
	
	
}
public class Test {
	public static void main(String[] args) {
		//创建map集合对象
		HashMap<Student, String> map=new HashMap<Student, String>();
		//创建学生对象
		Student s1=new Student("张三", 21);
		Student s2=new Student("张三", 21);//姓名年龄一样算同一个人
		Student s3=new Student("张三", 23);//姓名一样年龄不同算两个人
		Student s4=new Student("李四", 20);
		Student s5=new Student("王五", 25);
		Student s6=new Student("王五", 25);
		//添加到map集合中
		map.put(s1, "132001");
		map.put(s2, "132002");
		map.put(s3, "132003");
		map.put(s4, "132004");
		map.put(s5, "132005");
		map.put(s6, "132006");
		//获取键的集合
		Set<Student> k=map.keySet();
		for (Student s : k) {//遍历键的集合
			String v=map.get(s);//通过键找对应的值
			System.out.println(s.toString()+"\t学号:"+v);
		}
	}
	
}
/**
学生:[姓名=李四, 年龄=20]	学号:132004
学生:[姓名=张三, 年龄=23]	学号:132003
学生:[姓名=张三, 年龄=21]	学号:132002
学生:[姓名=王五, 年龄=25]	学号:132006
*/

HashMap的嵌套遍历

HashMap集合的键也为HashMap集合的情况。

import java.util.HashMap;
import java.util.Set;

public class Test3 {
	public static void main(String[] args) {
		// 定义以和HashMap集合,值为HashMap集合
		HashMap<String, HashMap<String, Integer>> gra = new HashMap<String, HashMap<String, Integer>>();
		// 定义一班的学生
		HashMap<String, Integer> cla1 = new HashMap<String, Integer>();
		cla1.put("张三", 18);
		cla1.put("李四", 21);
		gra.put("一班", cla1);
		// 定义二班的学生
		HashMap<String, Integer> cla2 = new HashMap<String, Integer>();
		cla2.put("王五", 22);
		cla2.put("赵六", 24);
		gra.put("二班", cla2);
		// 遍历
		Set<String> gks = gra.keySet();// 获取大集合gra键的集合
		for (String gk : gks) {// 遍历大集合gra键的集合
			System.out.println("班级:" + gk);// 输出班级信息
			HashMap<String, Integer> gv = gra.get(gk);// 通过大集合的键获取值
			Set<String> cks = gv.keySet();// 遍历
			for (String ck : cks) {
				Integer cv = gv.get(ck);
				System.out.println("\t姓名:" + ck + "\t年龄:" + cv);

			}
		}

	}
}
/**结果:
班级:一班
姓名:李四	年龄:21
姓名:张三	年龄:18
班级:二班
姓名:王五	年龄:22
姓名:赵六	年龄:24
*/

LinkedHashMap

有序的HashMap集合

上面HashMap的代码使用LinkHashMap再做一次

import java.util.LinkedHashMap;
import java.util.Set;

public class Test {
	public static void main(String[] args) {
		// 创建LinkedHashMap集合对象
		LinkedHashMap<Student, String> map = new LinkedHashMap<Student, String>();
		// 创建学生对象
		Student s1 = new Student("张三", 21);
		Student s2 = new Student("张三", 21);// 姓名年龄一样算同一个人
		Student s3 = new Student("张三", 23);// 姓名一样年龄不同算两个人
		Student s4 = new Student("李四", 20);
		Student s5 = new Student("王五", 25);
		Student s6 = new Student("王五", 25);
		// 添加到LinkedHashMap集合中
		map.put(s1, "132001");
		map.put(s2, "132002");
		map.put(s3, "132003");
		map.put(s4, "132004");
		map.put(s5, "132005");
		map.put(s6, "132006");
		// 获取键的集合
		Set<Student> k = map.keySet();
		for (Student s : k) {// 遍历键的集合
			String v = map.get(s);// 通过键找对应的值
			System.out.println(s.toString() + "\t学号:" + v);
		}
	}

}
/**
 学生:[姓名=张三, 年龄=21]	学号:132002
学生:[姓名=张三, 年龄=23]	学号:132003
学生:[姓名=李四, 年龄=20]	学号:132004
学生:[姓名=王五, 年龄=25]	学号:132006
 */

可以发现,使用方法和HashMap集合一样但是保证了元素的有序性,存入和取出顺序一致

哈希表

    在说到哈希表前我们需要先回顾数组和链表:

 数组链表
空间复杂度存储区间是连续的,占用内存严重,空间复杂度很大。存储区间离散,占用内存比较宽松,空间复杂度很小
时间复杂度二分查找时间复杂度小,O(1)时间复杂度很大,O(N)
特点查询快,增删慢增删快,查询慢

而哈希表就是基于以上的特点诞生的,他的特点是查询和增删都相对容易。

        哈希表相当于是数组+链表的形式实现的,数组中每个元素存储的是一个链表的头节点。链表按照 元素的哈希值%数组长度 得到的值为该链表存储的数组的下标。如数组长度为16,链表元素的哈希值为171,171%16=11,则该链表对应到数组中下标为11的位置。

HashMap中创建了一个Entry[ ]数组,Entry是一个匿名内部类,在其中存储了键值对关系。所以HashMap底层还是通过数组实现的。存储时通过键K,的哈希码值%Entry数组的长度来在Entry数组中存储。如果不同的k计算出相同的脚标值时,利用链表的方式将后面进来的替换到数组中,然后将前一个通过Entry中的next属性链接到后进来的元素上。

TreeMap<K,V>

    基于红黑树结构的双链集合,会自然排序键,需要实现Comparator接口中的compare方法才能完成排序。

import java.util.Comparator;
import java.util.Set;
import java.util.TreeMap;

public class Test2 {
	public static void main(String[] args) {
		// 创建TreeSet集合对象
		TreeMap<Student, String> map = new TreeMap<Student, String>(new Comparator<Student>() {
			@Override
			public int compare(Student s1, Student s2) {
				int num1 = s1.getName().length() - s2.getName().length();// 按姓名长度排序
				int num2 = num1 == 0 ? s1.getAge() - s2.getAge() : num1;// 长度一样按年龄排序
				return num2;
			}
		});
		// 创建学生对象
		Student s1 = new Student("zhangsan", 21);
		Student s2 = new Student("zhangsan", 21);// 姓名年龄一样算同一个人
		Student s3 = new Student("zhangsan", 23);// 姓名一样年龄不同算两个人
		Student s4 = new Student("lisis", 20);
		Student s5 = new Student("wangwu", 25);
		Student s6 = new Student("zhaoliu", 24);
		Student s7 = new Student("lisis", 22);
		// 添加到LinkedHashMap集合中
		map.put(s1, "132001");
		map.put(s2, "132002");
		map.put(s3, "132003");
		map.put(s4, "132004");
		map.put(s5, "132005");
		map.put(s6, "132006");
		map.put(s7, "132007");
		// 获取键的集合
		Set<Student> k = map.keySet();
		for (Student s : k) {// 遍历键的集合
			String v = map.get(s);// 通过键找对应的值
			System.out.println(s.toString() + "\t学号:" + v);
		}
	}

}
/**
姓名:lisis	年龄:20	学号:132004
姓名:lisis	年龄:22	学号:132007
姓名:wangwu	年龄:25	学号:132005
姓名:zhaoliu	年龄:24	学号:132006
姓名:zhangsan	年龄:21	学号:132002
姓名:zhangsan	年龄:23	学号:132003
 */

Hashtable<K,V>

线程安全的双链集合,使用方式和HashMap集合类似。

    需要注意Hashtable集合不允许键值对中存在null的元素,如果存在null会引发NullPointerException异常。

Collections

    集合的工具类,区别于Collection是集合的根接口。

常用方法

sort(List<T> list)

    升序排序集合,如果集合中的元素是自定义对象需要实现Comparable接口中的compareTo方法,更多情况下使用Comparator匿名内部类的方式,需要重写compare方法。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Test5 {
	public static void main(String[] args) {
		ArrayList<Student> list=new ArrayList<Student>();
		//使用的学生类还是上文之前代码中定义的学生类
		Student s1=new Student("张三", 21);
		Student s2=new Student("李四", 20);
		Student s3=new Student("王五", 25);
		Student s4=new Student("木婉清", 21);
		Student s5=new Student("李清浅", 20);
		Student s6=new Student("言子矜", 20);
		Student s7=new Student("周糖芯", 25);
		list.add(s1);
		list.add(s2);
		list.add(s3);
		list.add(s4);
		list.add(s5);
		list.add(s6);
		list.add(s7);
		Collections.sort(list, new Comparator<Student>() {//需要重写Comparator接口中的compare方法
			@Override
			public int compare(Student s1, Student s2) {
				int num1=s1.getAge()-s2.getAge();//按年龄排序
				int num2=num1==0?s1.getName().length()-s2.getName().length():num1;//年龄一样按姓名长度排序
				return num2;
			}
		} );
		//遍历
		for (Student stu : list) {
			System.out.println(stu.toString());
		}
	}
}
/**
结果为:
姓名:李四	年龄:20
姓名:李清浅	年龄:20
姓名:言子矜	年龄:20
姓名:张三	年龄:21
姓名:木婉清	年龄:21
姓名:王五	年龄:25
姓名:周糖芯	年龄:25
*/

binarySearch(List<T> list, T key)

    集合的二分法查找,前提是集合元素有序

max(Collection coll)

    获取集合中的最大值

reverse(List<?> list)

    将集合中的元素顺序反转

shuffle(List<?> list)

    将集合中的元素打乱

import java.util.ArrayList;
import java.util.Collections;

public class Test4 {
	public static void main(String[] args) {
		ArrayList<Integer> list=new ArrayList<Integer>();
		list.add(10);
		list.add(55);
		list.add(15);
		list.add(45);
		list.add(12);
		list.add(34);
		list.add(24);
		list.add(33);
		System.out.println(list);//[10, 55, 15, 45, 12, 34, 24, 33]
		Collections.sort(list);//升序排列
		System.out.println(list);//[10, 12, 15, 24, 33, 34, 45, 55]
		int i=Collections.binarySearch(list, 24);//二分法查找
		System.out.println(i);//3
		int max=Collections.max(list);//获取最大值
		System.out.println(max);//55
		Collections.reverse(list);//反转
		System.out.println(list);//[55, 45, 34, 33, 24, 15, 12, 10]
		Collections.shuffle(list);//随机打乱
		System.out.println(list);//[34, 33, 55, 24, 45, 10, 12, 15]
	}
}

同步相关方法

synchronizedList(List<T> list)

静态方法,返回一个加同步锁的List集合。可以将线程不安全的List集合变成线程安全的

synchronizedMap(Map<K,V> m)

静态方法,返回一个加同步锁的Map集合。可以将线程不安全的Map集合变成线程安全的

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test2 {
	public static void main(String[] args) {
		List<String> list = Collections.synchronizedList(new ArrayList<String>());
		Map<String, Integer> map = Collections.synchronizedMap(new HashMap<String,Integer>());
	}
}

 

运用实例

 

模拟斗地主的洗牌和发牌

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;

public class Test6 {
	public static void main(String[] args) {
		// 定义花色
		String[] col = { "♣", "♠", "♦", "♥" };
		// 定义点数
		String[] num = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" };
		// 定义扑克牌集合
		HashMap<Integer, String> pk = new HashMap<Integer, String>();
		// 定义扑克牌编号集合
		ArrayList<Integer> arr = new ArrayList<Integer>();
		// 定义计数变量,arr集合存储编号,pk集合存储编号和对应的扑克牌
		int i = 0;
		for (String n : num) {
			for (String c : col) {
				arr.add(i);
				pk.put(i, c + n);
				i++;
			}
		}
		// 装入大小王
		arr.add(i);
		pk.put(i, "小王");
		i++;
		arr.add(i);
		pk.put(i, "大王");
		// 洗牌
		Collections.shuffle(arr);
		// 定义玩家和底牌
		TreeSet<Integer> play1 = new TreeSet<Integer>();
		TreeSet<Integer> play2 = new TreeSet<Integer>();
		TreeSet<Integer> play3 = new TreeSet<Integer>();
		TreeSet<Integer> dipai = new TreeSet<Integer>();
		// 发牌
		for (int j = 0; j < arr.size(); j++) {
			if (j >= arr.size() - 3) {
				dipai.add(arr.get(j));
			} else if (j % 3 == 0) {
				play1.add(arr.get(j));
			} else if (j % 3 == 1) {
				play2.add(arr.get(j));
			} else if (j % 3 == 2) {
				play3.add(arr.get(j));
			}
		}
		//看牌
		//定义一个看牌的方法dela
		dela("玩家1", play1, pk);
		dela("玩家2", play2, pk);
		dela("玩家3", play3, pk);
		dela("底牌", dipai, pk);
	}
	/**
	 * 查看玩家牌的方法
	 * @param play	玩家姓名
	 * @param arr	玩家牌的编号
	 * @param pk	总的扑克集合
	 */
	public static void dela(String play,TreeSet<Integer> arr,HashMap<Integer, String> pk) {
		//输出玩家信息
		System.out.print(play+":");
		//遍历玩家编号
		for (Integer num : arr) {
			//通过编号寻找对应的牌
			System.out.print(pk.get(num)+" ");
		}
		System.out.println();
	}
}
/**
玩家1:♠A ♣2 ♦2 ♥2 ♥3 ♣4 ♦4 ♣6 ♣8 ♦8 ♣10 ♥10 ♦Q ♣K ♦K ♥K 小王 
玩家2:♦A ♠2 ♠3 ♦3 ♠4 ♣5 ♠5 ♠7 ♥7 ♠8 ♠9 ♦9 ♣J ♦J ♥J ♠Q 大王 
玩家3:♣A ♥A ♣3 ♥4 ♦5 ♥5 ♠6 ♦6 ♥6 ♣7 ♦7 ♥8 ♥9 ♦10 ♠J ♣Q ♥Q 
底牌:♣9 ♠10 ♠K 
*/

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值