Map与Set集合

本文详细介绍了Java中的Set集合特点,包括无序、不允许重复,并以HashSet为例展示了存储和遍历方法。接着讲解了HashSet存储自定义对象时重写equals和hashCode的重要性。此外,还探讨了Collections工具类的常用方法,如二分搜索、列表复制等。然后,转向Map接口,阐述其映射功能、获取、判断、删除以及遍历方法。最后,通过示例展示了Map与Set在处理自定义对象时的去重策略及其遍历方式。
摘要由CSDN通过智能技术生成

一、Set集合的特点
Set集合的特点:
  无序(存储和读取的顺序有可能不一样);
  不允许重复(要求元素唯一);
  没有索引。
利用HashSet存储字符串并遍历(三种遍历方法):

	public static void main(String[] args) {
		//创建集合对象
        Set<String> set = new HashSet<String>();

        //添加元素
        set.add("hello");
        set.add("world");
        set.add("bupt");
        
        //遍历集合对象(分为三种:数组遍历、迭代器遍历、增强for循环)
        
        //数组遍历
        Object[] objs = set.toArray();
        for(int i=0; i < objs.length; i++) {
        	System.out.println(objs[i]);
        }
        
        //迭代器遍历
        Iterator<String> it = set.iterator();
        while(it.hasNext()) {
        	System.out.println(it.next());
        }
        
        //增强for循环遍历
        for(String s : set){
        	System.out.println(s);
        	
        }
      
	}

二、HashSet存储自定义对象并遍历
通过查看源码发现
  HashSet的add方法会使用当前集合中的每一个元素的Hash值与新添加元素的Hash值进行比较:如果Hash值(通过hashCode方法获取)不一样,则直接添加新的元素;如果Hash值一样,则比较比较地址值或者使用元素中重写的equals方法进行比较,若比较结果一样,则认为元素重复,不再添加,若比较结果不一样,则可以添加。

public class test {	
	public static void main(String[] args) {
		//创建集合对象
        HashSet<Student> set = new HashSet<Student>();

        //创建自定义类对象
        Student s0 = new Student("hxf2",20);
        Student s1 = new Student("hxf",18);
        Student s2 = new Student("hxf1",19);
        Student s3 = new Student("hxf2",20);
        
        //将自定义类对象添加到集合中
        set.add(s1);
        set.add(s2);
        set.add(s3);

        for(Student s : set){     //增强for循环遍历集合
        	System.out.println(s);
        	System.out.println(s.hashCode());
        	
        }  
	}	
}
	
class Student{
	private String name;
	private int age;
	
	public Student(String name, int age) {   //构造方法,为了初始化
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString() {   //使用Eclipse自动生成,用于显示自定义类Student的成员变量
		return "Student [name=" + name + ", age=" + age + "]";
	}
	
	@Override
	public boolean equals(Object obj) {
		if(this == obj) {  //提高程序效率
			return true;
		}
		if(obj == null) {   //更加严谨
			return false;
		}
		if(this.getClass() != obj.getClass()) { //提高代码健壮性,如果传进来的类跟Student类不相关,则不能向下转型
			return false;
		}
		Student stu = (Student)obj;   //向下转型
		
		if(this.age != stu.age) {
			return false;
		}
		
		if(!this.name.equals(stu.name)) {
			return false;
		}
		return true;
	}

	@Override
	public int hashCode() {    //使用随着类成员变量变化的的hashCode方法
		return age + name.hashCode();
	}
}

:因为Object类中有equals和hashCode方法,所以在Student自定义类默认继承Object类(但是Object类中的equals方法和hashCode不能满足自定义类的成员比较),可以重写Object类中的方法。
举个例子:String类重写了Object类的equals和hashCode方法,以满足针对不同的字符串,得到不同的hash值,相同的字符串得到相同的hash值,从而来进行“去重”,即去除重复。

三、Collections工具类
  Collections与Collection的区别:
  Collection是集合体系的最顶层,包含了集合体系共性;
  Collections是一个工具类,其中的方法大多为静态方法,用于操作Collection集合。
方法举例:
static int binarySearch(List<? extends Comparable<? super T>> list, T key) : 使用二分搜索法搜索指定列表,以获得指定对象。
static void copy(List<? super T> dest, List<? extends T> src) :将所有元素从一个列表复制到另一个列表。
static void fill(List<? super T> list, T obj) : 使用指定元素替换指定列表中的所有元素。
static void reverse(List<?> list) :反转指定列表中元素的顺序。
static <T extends Comparable<? super T>> void sort(List list) :根据元素的自然顺序 对指定列表按升序进行排序。
static void swap(List<?> list, int i, int j) :在指定列表的指定位置处交换元素。

代码举例:

public class test {	
	public static void main(String[] args) {
		//创建集合对象
        List<Integer> list = new ArrayList<Integer>();
        
        list.add(1);
        list.add(3);
        list.add(4);
        list.add(2);
        list.add(5);
        
        int index = Collections.binarySearch(list, 3);
        System.out.println(index);    
	}	
}

举例:模拟斗地主发牌

	public static void main(String[] args) {
		//创建扑克牌
		String arr1[] = {"黑桃","红桃","方片","梅花"};
		String arr2[] = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
		ArrayList<String> box = new ArrayList<String>();
		for(int i=0; i < arr1.length; i++) {
			for(int j=0; j < arr2.length; j++) {
				box.add(arr1[i] + arr2[j]);
			}
		}
		box.add("大王");
		box.add("小王");
		
		
		//洗牌,调用Collections工具类,将集合内的字符串对象打乱
		Collections.shuffle(box);
		
		//给三个同学发牌
		ArrayList<String> person1 = new ArrayList<String>();
		ArrayList<String> person2 = new ArrayList<String>();
		ArrayList<String> person3 = new ArrayList<String>();
		for(int i=0; i < box.size()-3; i++) {
			if(i%3 == 0) {
				person1.add(box.get(i));
			}
			else if(i%3 == 1) {
				person2.add(box.get(i));
			}
			else if(i%3 == 2) {
				person3.add(box.get(i));
			}
		}

        for(int i=box.size()-3; i < box.size(); i++) {
        	System.out.println("底牌"+box.get(i));
        }
        
        System.out.println(person1);
        System.out.println(person2);
        System.out.println(person3); 
	}	
}

四、Map接口
Map接口概述:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
Map和Collection的区别
  Map:是一个双列集合,常用于处理有对应关系的数据,键key是不可以重复的,我们也称之为“夫妻对集合”
  Collection:是单列集合,Collection接口有不同的子体系,有的允许重复并且有索引有序(比如:ArrayList和LinkedList),有的不允许重复并且无序(比如:HashSet),我们也称之为“单身汉集合”;

Map的常用功能
映射功能:
V put(K key, V value) :就是将key映射到value,如果key存在,则覆盖value,并将原来的value值返回;如果key不存在,则添加key以及相应的value;
获取功能:
V get(Object key) :根据键key的值,返回对应value;
int size() :返回对应关系的个数;
判断功能:
boolean containsKey(Object key) :判断指定key是否存在;
boolean containsValue(Object value) :判断指定的value是否存在;
boolean isEmpty() :判断是否有对应关系;
删除功能:
void clear() :清空所有的对应关系;
V remove(Object key) :根据指定的key删除对应关系,并返回key所对应的值;
遍历功能:
Set<Map.Entry<K,V>> entrySet() : 返回此映射中包含的映射关系的 Set 视图。

Map获取所有的key和value方法:

//Set<K> keySet()   以Set的形式返回所有的key
Set<String> keys = map.keySet();
for(String key:keys){   //遍历Set集合
    System.out.println(key);
}

//Collection<V> values():   以Collection的形式返回所有的value
Collection<String> values = map.values();
for(String value:values){   //遍历Collection集合
    System.out.println(value);
}

Map的第一种遍历方式
获取所有元素的key值,再根据key值找到value值;

	public static void main(String[] args) {
		//创建一个Map对象
		Map<String,String> map = new HashMap<String,String>(); 
		
		//添加映射关系
		map.put("邓超","孙俪");
		map.put("李晨","范冰冰");
		map.put("黄晓明", "杨颖");
		
		//遍历Map对象
		Set<String> keys = map.keySet();
		for(String key:keys) {
			String value = map.get(key);
			System.out.println("丈夫:"+key+"  "+"妻子:"+value);
		}
	}	

Map的第二种遍历方式
通过内部类对象来获取key和value的值(举例:这里的内部类可认为是结婚证类,来获取丈夫和妻子的值);
我们写的内部类如下:

class Entry<K,V> {
    K key;
    V value;

    public Entry(K key, V value){
        this.key = key;
        this.value = value;
    }

    public K getKey(){
        return key;
    }
    public V getValue(){
        return value;
    }
}

实际在Map接口中,Entry<K,V>是一个子接口,其在Map的实现子类AbstractMap类中被重写,重写形式与上述代码类似,利用Entry<K,V>内部类实现Map的遍历方式代码为:
利用 Map接口中的Set<Map.Entry<K,V>> entrySet() 函数。

	public static void main(String[] args) {
		//创建一个Map对象
		Map<String,String> map = new HashMap<String,String>(); 
		
		//添加映射关系
		map.put("邓超","孙俪");
		map.put("李晨","范冰冰");
		map.put("黄晓明", "杨颖");
		
		//遍历Map对象
		Set<Map.Entry<String, String>> entrys = map.entrySet();
		for(Map.Entry<String, String> entry:entrys) {
			String key = entry.getKey();
			String value = entry.getValue();
			System.out.println("丈夫:"+key+"  "+"妻子:"+value);
		}	
	}	

五、综合实例
key值为自定义对象实例(包含两种遍历方法和去重)
自定义对象为:

public class Student {
	public String name;
	public int age;
	
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString() {   //用于显示
		return "Student [name=" + name + ", age=" + age + "]";
	}

	@Override
	public int hashCode() {     //与equals方法一起,去重复
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@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;
	}

}

主函数为:

	public static void main(String[] args) {
		//创建一个Map对象
		Map<Student,String> map = new HashMap<Student,String>(); 
		
		//创建学生对象
		Student s1 = new Student("张三丰",18);
		Student s2 = new Student("郭靖",30);
		Student s3 = new Student("郭靖",30);
		
		//添加映射关系
		map.put(s1,"abc01");
		map.put(s2,"abc02");
		map.put(s3,"abc03");
		
		//第一种遍历方式
		Set<Student> keys = map.keySet();
		for(Student key:keys) {
			String value = map.get(key);
			System.out.println(key+"学号:"+value);
		}
		System.out.println("----------------");
		//第二种遍历方式
		Set<Map.Entry<Student, String>> entrys = map.entrySet();
		for(Map.Entry<Student, String> entry:entrys) {
			Student key = entry.getKey();
			String value = entry.getValue();
			System.out.println(key+"学号:"+value);
		}	
	}	

:若这里直接使用Map<String,String>,则直接有去重功能,因为hashCode()函数、equals()函数都被重写过了,而Student类继承的是Object类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值