笔记

笔记13

课程内容
	1、Set集合
	2、HashSet存储自定义元素保证唯一性的原理
	3、Map双列集合的顶层接口
	4、HashMap哈希存储
	5、Collections工具类

一、Set集合

1、set集合是Collection下的一个子接口
2、特点:	
	无序:没有任何前后的区别,存入的顺序和取出的顺序是不一样的,所有的元素在集合中没有位置上的概念
	没有索引
	不能重复,没有位置上的区别,相同的元素没有任何区分,所有不能重复
3、Set的实现类:
	HashSet:使用哈希表的存储方式来存储元素
4、存储特点:
	相同的元素不能存入到set集合中
	集合本身不保证顺序的,存入的顺序和取出的顺序是不一样的
package com.ujiuye.demos;

import java.util.HashSet;
import java.util.Set;

public class Demo_1 {
//Set集合
	public static void main(String[] args) {
		Set<String> set = new HashSet<>();
		set.add("赵丽颖");//不能重复,无序
		set.add("赵丽颖");
		set.add("迪丽热巴");
		set.add("迪丽热巴");
		set.add("杨幂");
		set.add("杨幂");
		set.add("陈乔恩");
		set.add("陈乔恩");
		set.add("王丽坤");
		System.out.println(set);
		
		Set<String> set1 = new HashSet<>();
		set1.add("a");
		set1.add("b");
		set1.add("c");
		System.out.println(set1);
	}
}

Set集合的遍历

1、没有特有的方法,只能使用Collection接口中定义的方法,只能使用Collection的遍历方式
2、第一种:转成数组toArray(),不带泛型的数组,得到的是Object类型的数组
3、第二种: 转成数组 T[] toArray(T[] t),带泛型的数组,得到的是T类型的数组
	(1)自己创建的数组大小,小于集合元素的个数
		在方法中,就会创建一个新的数组,用来存储集合中的元素,将数组返回
	(2)自己创建的数组大小,等于集合元素的个数
		在方法中,就不会创建一个新的数组,使用集合中的元素将传入的数组进行填充,将原数组进行返回
	(3)自己创建的数组大小,大于集合元素的个数
		在方法中,不会创建一个新的数组,直接将集合中的元素填充到数组中的前面的位置,后面的位置用默认值填充
4、第三种:迭代器
5、第四种:增强for循环(foreach)
	格式:for(元素的数据类型 元素名称 :要遍历的集合或者数组){
			使用元素名称代表当前访问的元素;
		 }
	说明:
		元素的数据类型:指的是要遍历集合中元素的数据类型
		元素名称:元素名称虽然是固定的,但是随着循环的执行,每次代表的元素是不同的
		要遍历的集合:可以是数组也可以是集合
	本质:
		底层迭代器,只不过使用这种格式更为简单
	注意事项:使用增强for,没有拿到元素的索引,无法修改集合或者数组中的元素值
		    底层迭代器,所在在遍历集合的时候,使用集合对象添加元素,也会发生并发修改异常
package com.ujiuye.demos;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

//set集合的遍历
public class Demo_2 {
	public static void main(String[] args) {

		Set<String> set = new HashSet<>();
		set.add("赵丽颖");// 不能重复,无序
		set.add("赵丽颖");
		set.add("迪丽热巴");
		set.add("迪丽热巴");
		set.add("杨幂");
		set.add("杨幂");
		set.add("陈乔恩");
		set.add("陈乔恩");
		set.add("王丽坤");
		System.out.println(set);
//		第四种遍历方式
		for(String str : set) {
//			if(str.equals("杨幂")) {
//				set.add("糯米");底层是迭代器,也会发生并发修改异常
//			}
			System.out.println(str);
		}
		
		int[] arr = {1,2,3,4};
		for(int i : arr) {
			System.out.println(i);
		}
	}

	private static void bianLi_3(Set<String> set) {
		//		第三种,迭代器
		//		获取迭代器对象
				Iterator<String> it = set.iterator();
				while(it.hasNext()) {
					System.out.println(it.next());
				}
	}

	private static void bianLi_2(Set<String> set) {
		// 第二种方法
		// 自己创建的数组大小,小于集合元素的个数
		String[] strs1 = new String[3];
		String[] array1 = set.toArray(strs1);
		// 判断一下strs1和array1是不是同一个数组
		System.out.println(strs1 == array1);
		System.out.println(Arrays.toString(array1));
		System.out.println("=========自己创建的数组大小,等集合元素的个数========================");
		// 自己创建的数组大小,等集合元素的个数
		String[] strs2 = new String[set.size()];
		String[] array2 = set.toArray(strs2);
		// 判断一下strs1和array1是不是同一个数组
		System.out.println(strs2 == array2);
		System.out.println(Arrays.toString(array2));
		System.out.println("=========自己创建的数组大小,大于集合元素的个数========================");
		// 自己创建的数组大小,大于集合元素的个数
		String[] strs3 = new String[set.size() + 3];
		String[] array3 = set.toArray(strs3);
		// 判断一下strs1和array1是不是同一个数组
		System.out.println(strs3 == array3);
		System.out.println(Arrays.toString(strs3));
	}

	private static void bianLi_1(Set<String> set) {
		// 第一种,toArray()
		Object[] objs = set.toArray();
		for (int i = 0; i < objs.length; i++) {
			System.out.println(objs[i]);
		}
	}
}

二、HashSet保证元素唯一性的原理

HashSet存储jdk提供的元素的类型

HashSet存储jdk提供的元素的类型,发现直接保证了元素的唯一性,值相同的元素都去掉了

HashSet存储自定义类型元素

1、HashSet存储自定义类型元素发现并没有保证唯一性
2、实验:猜测没有重写equals方法,没有重写之前比较的地址值,如果地址值一样了就不存储,不一样就存储,但是
	重写后equals方法比较的是属性值,发现并没有调用,没有去重成功
3、猜测Hashset集合是哈希实现,有没有可能跟HashCode方法有关,重写HashCode方法
	在重写hashcode方法之前,调用的Object中的hashcode方法,不同的对象(对象的地址值不同)生成的hashcode值就是不同的。
	重写hashcode方法之后,让Person中hashcode方法生成的值都为0(实现的效果,不同的对象对象的地址值不同的时候)生成的hashCode值一样的,发现确实hashCode方法执行了,equals方法也执行了。
4、发现了,HashSet存储自定义类型元素的时候,确实要调用自定义元素类型中的hashCode方法,根据hashCode方法的值判断是否将自定义元素存入到集合中。发现不同的对象(地址值不同)调用Object类中的hashCode方法生成的是不同的的hashcode值,就直接存储,不能实现去重,equals方法也不调用
	重写hashcode方法之后,让Person中hashcode方法生成的值都为0,发现调用equals方法,根据equasl方法比较的结果判断是否添加重复的元素

HashCode方法

1、Object类型中的方法
2、根据对象,生成一个整数,就是哈希吗值,生成数字的方法的就是hashCode()
3、生成数字的原则:
	(1)同一个对象,多次调用hashCode()方法【必须】返回的是相同的数字(程序多次运行不要求hashCode码值一致)
	(2)使用equals(Object) 方法判断相同的两个对象【必须】返回相同的整数(equals是Object类型中的,比较的是地址值)
	(3)使用equals(Object) 方法判断不相同的两个对象【尽量】生成不相同的整数(不做强制要求)
	(4)Object类型中的HashCode方法,确实会根据不同的对象生成不同的整数。
package com.ujiuye.demos;

//hashCode()方法
public class Demo_4 {
	public static void main(String[] args) {
		Object obj = new Object();
		Object obj2 = new Object();
		System.out.println(obj.hashCode());
		System.out.println(obj.hashCode());
		System.out.println(obj.hashCode());
		System.out.println(obj.hashCode());
		System.out.println(obj2.hashCode());
		Object obj1 = obj;
		System.out.println(obj1.hashCode());
		System.out.println(obj2.hashCode());
	}
}

HashSet保证唯一性原理的总结

1、HashSet 集合存储一个obj对象的时候,首先计算obj对象的hashcode值
2、在集合中的所有的元素的哈希值,都和obj的hashcode值,说明集合中不存在Obj,可以直接将obj存储到集合中
3、在集合中有若干个元素的哈希值,和obj的哈希值相同,并不能说明obj已经存在于集合中,需要使用equals方法判断obj时候和那些与自己相同的哈希值的元素是否相等
4、如果在equals方法和obj元素比较之后,发现都不相等,那么就说明obj不存在与这个集合,可以将obj存储到hashset中
5、如果在equals方法和obj元素比较之后,发现相等,obj已经存在于集合中,obj就不存储了

在这里插入图片描述

保证唯一性的操作

1、重写HashCode()方法
	根据属性值,生成哈希值
	不同的属性值,尽量生成不同的整数
	相同的属性值,一定会生成相同的整数
2、重写equals方法
	比较的就是属性值
3、操作
	alt+shift + s
		h
	生成hashcode方法和equals方法
package com.ujiuye.demos;

public class Person {
	private String name;
	private int age;
	public Person() {
	}
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	
	@Override
	public int hashCode() {
		System.out.println("hashCode方法执行了");
		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) {
		System.out.println("equals方法执行了");
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) 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 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;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
}

package com.ujiuye.demos;
import java.util.HashSet;
public class Demo_3 {
	public static void main(String[] args) {
//		HashSet存储自定义类型的元素
		HashSet<Person> hs = new HashSet<>();
		hs.add(new Person("张三丰", 90));
		hs.add(new Person("张三丰", 90));
		hs.add(new Person("张无忌", 30));
		hs.add(new Person("赵敏", 20));
		hs.add(new Person("赵敏", 20));
		hs.add(new Person("灭绝师太", 190));
		System.out.println(hs);
		HashSet存储jdk提供的元素的类型
//		HashSet<Integer> hs = new HashSet<Integer>();
//		hs.add(123);
//		hs.add(123);
//		hs.add(234);
//		hs.add(234);
//		System.out.println(hs);
	}
} 

LinkedHashSet

1、是HashSet的一个子类,和HashSet保证元素唯一性的原理相同
2、将来每个元素在存储的时候,都记录了前后元素的地址
3、效果:
	可以根据存储元素的顺序,将元素取出
4、应用:
	既需要保证元素的唯一,又需要保证原来的顺序,就可以考虑LinedHashSet
package com.ujiuye.demos;

import java.util.LinkedHashSet;

public class Demo_5 {
	public static void main(String[] args) {
//		LinkedHashSet
		LinkedHashSet<String> lhs = new LinkedHashSet<String>()	;
		lhs.add("java");
		lhs.add("java");
		lhs.add("C");
		lhs.add("C++");
		lhs.add("C++");
		lhs.add("C#");
		System.out.println(lhs);
//		存储自定义元素
		LinkedHashSet<Person> lhs1 = new LinkedHashSet<>()	;
		lhs1.add(new Person("王思聪",31));
		lhs1.add(new Person("王健林",31));
		lhs1.add(new Person("郭美美",31));
		lhs1.add(new Person("郭美美",31));
		lhs1.add(new Person("凤姐",31));
		lhs1.add(new Person("凤姐",31));
		System.out.println(lhs1);
	}
}

三、Map

1、是双列集合的顶层接口
2、Map:地图
3、Map:映射,描述的就是将一个数据(key)到另一个数据(value)的映射关系(对应关系)
	     一个数据(key):容易记忆的,有规律的,简单的数据
	     另一个数据(value):没有规律,不容易记忆的,复杂的数据
	     大多数都是通过key操作value
4、映射:对应关系
	函数:y = x * x      特点:x是不会重复的                      key
			    平方          y会重复的                         value
    		x  ----->   y
     		1           1
     		2           4
     		3           9
     		4           16
5、java中map就是使用穷举罗列的方式描述映射关系
6、map的特点
	key(键)  是唯一的,不能重复的
	value(值)不是唯一的,可以重复
7、Map和Collection的区别
	Map是双列集合,Collection单列集合
	Map的键是唯一的,Collection中set子接口中的元素是唯一的
	Map中大多数方法都是操作键的,Collection中set子接口中的操作对元素有效

Map集合中的方法

1、增加键值对(向map集合中添加数据)
	put(K key,V value)
2、删除方法
	根据给定的值,删除对应的键值对:remove(k key)
	clear(); 清空
3、获取方法
	get(k key)获取键所对应的的value值
	size()返回map集合中所有的键值对的个数
4、判断方法
	containsKey(Object key)     判断集合中是否包含key这个键
	containsValue(Object value) 判断集合中是否包含value这个值
5、修改方法
	根据给定的键,修改对应的值:put(k key,v value)
	如果在集合中已经存在key这个键,那么使用put方法,就是修改这个键对应的value值
	如果在集合中不存在key这个键,那么使用put方法,就是向map集合重添加数据
package com.ujiuye.demos;

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

public class Demo_6 {
	public static void main(String[] args) {
		Map<String,String> map = new HashMap<>();
//		添加方法
		map.put("瞎子", "李青");
		map.put("瞎子", "李青");
		map.put("盲僧", "李青");
		map.put("托儿索", "亚索");
		map.put("快乐风男", "亚索");
		map.put("望远烬", "烬");
		map.put("望远烬", "烬");
		System.out.println(map);
//		删除方法
		map.remove("望远烬");
		System.out.println(map);
//		map.clear();
//		System.out.println(map);
//		获取方法
		System.out.println(map.size());
		System.out.println(map.get("盲僧"));
//		判断方法
		System.out.println(map.containsKey("李青"));
		System.out.println(map.containsKey("盲僧"));
		System.out.println(map.containsValue("李青"));
//		修改方法
		map.put("奥斑马","卢锡安");
		System.out.println(map);
		map.put("瞎子","李青2号");
		System.out.println(map);
	}
}

Map集合的第一种遍历思路(熟练掌握)

1、获取Map集合中所有的键,放到一个set集合中,遍历set集合,获取每一个键,根据键再来获取对应的值【根据键获取对应的值】
2、获取Map集合中所有的键
	keySet()
3、遍历Set集合拿到map集合中所有的键了
	遍历Set集合:
	增强for
	迭代器
4、拿到每个键之后,通过get(K key)获取键对应的值
5、特点;
	获取了所有键的set集合后,要依赖于原来的map集合

在这里插入图片描述

Map集合的第二种遍历思路

1、获取的是Map集合中所有的键值对对象(Entry), 到set集合中,遍历set集合,拿到的是每一个键值对对象(Entry),从这个对象中获取键和值
2、根据Map集合方法可以获取所有键值对对象到一个Set集合中
	Set<Map.Entry<K,V>>   entrySet()
3、遍历Set集合
	迭代器
	增强for
4、获取到的就是一个键值对对象
	Entry是Map接口中的内部接口,访问方式:Map.Entry
	Entry常用的方法
		getKey()获取的是键值对中的键
		getValue()获取的是键值对中的值

在这里插入图片描述

package com.ujiuye.demos;

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

public class Demo_8 {
//	map集合遍历的第二种思路
	public static void main(String[] args) {
		Map<String, Integer> map = new HashMap<>();
		map.put("林青霞", 70);
		map.put("张慧敏", 59);
		map.put("王祖贤", 60);
		map.put("朱茵", 50);
		map.put("刘德华", 60);
		System.out.println(map);
//		首先要获取map集合中键值对的一个set集合
		Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
//		迭代器
//		Iterator<Entry<String, Integer>> it = entrySet.iterator();
//		while (it.hasNext()) {
//			Entry<String, Integer> entry = it.next();
//			System.out.println(entry.getKey() + " = " + entry.getValue());
//		}
//	   增强for
		for (Map.Entry<String, Integer> entry : entrySet) {
			System.out.println(entry.getKey() + " = " + entry.getValue());
		}
	}
}

HashMap

1、就是Map集合中使用哈希表存储方式的一种实现类
2、HashMap存储jdk中提供的元素类型的键,直接保证元素的唯一性
3、HashMap存储的键值对中的键是自定义类型元素的时候,无法保证元素的唯一性,要保证自定义元素的唯一性也需要重写hashCode和equals方法
	保证键的唯一性和HashSet保证元素唯一性的原理是一样的
4、HashMap和HashSet的关系
	HashSet是HashMap实现出来的,HashSet就是HashMap键的那一列
	将HashMap值的那一列隐藏掉就成HashSet
package com.ujiuye.demos;

import java.util.HashMap;
import java.util.HashSet;

public class Demo_9 {
	public static void main(String[] args) {
//		HashMap
		HashMap<Person,String> hm = new HashMap<Person, String>();
		hm.put(new Person("张三",13),"成都");
		hm.put(new Person("张三",13),"成都");
		hm.put(new Person("李四",103),"北京");
		hm.put(new Person("李四",103),"北京");
		hm.put(new Person("王五",25),"武汉");
		System.out.println(hm);
	}
}

LinkedHashMap

1、是HashMap的一个子类
2、和HashMap的不同之处,具有可预知的迭代顺序,存储键值对的顺序和遍历集合时取出的顺序时的键值对的顺序一致。
package com.ujiuye.demos;

import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.Set;

public class Demo_10 {
	public static void main(String[] args) {
//		 LinkedHashMap
		LinkedHashMap<Person,String> lhm = new LinkedHashMap<>();
		lhm.put(new Person("张三",13),"成都");
		lhm.put(new Person("张三",13),"成都");
		lhm.put(new Person("李四",103),"北京");
		lhm.put(new Person("李四",103),"北京");
		lhm.put(new Person("王五",25),"武汉");
		System.out.println(lhm);
//		第二种遍历思路遍历
//		获取lhm的键值对的Set集合
		Set<Entry<Person, String>> entrySet = lhm.entrySet();
//		遍历Set集合
		for(Entry<Person, String> entry : entrySet) {
			System.out.println(entry.getKey());
			System.out.println(entry.getValue());
		}
	}
}

四、Collections工具类

1、binarySearch(List<? extends Comparable<? super T>> list, T key) 
在一个升序的List集合中,通过二分查找寻找Key对应的索引
2、frequency(Collection<?> c, Object o) 
   返回指定 collection 中等于指定对象的元素数。
3、replaceAll(List<T> list, T oldVal, T newVal) 
          使用另一个值替换列表中出现的所有某一指定值。
4、reverse(List<?> list) 
   反转指定列表中元素的顺序
5、shuffle(List<?> list)将list集合中的元素进行随机置换,打乱
6、sort(List<T> list) 将list集合中的元素进行自然排序
7、synchronizedxxx方法系列:将一个线程不安全的集合传入方法,返回一个线程安全的集合
8、unmodifiablexxx方法系列:将一个可修改的集合传入方法,返回一个只可读的集合
package com.ujiuye.demos;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class Demo_11 {
	public static void main(String[] args) {
//		Collections工具类
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(2);
		list.add(2);
		list.add(2);
		list.add(3);
		list.add(3);
		list.add(3);
		list.add(4);
		List<String> list1 = new ArrayList<String>();
		list1.add("a");
		list1.add("b");
		list1.add("c");
		list1.add("d");
		System.out.println(list1);
//		binarySearch(List<? extends Comparable<? super T>> list, T key) 
//		在一个升序的List集合中,通过二分查找寻找Key对应的索引
		int binarySearch = Collections.binarySearch(list, 2);
		System.out.println(binarySearch);
//		frequency(Collection<?> c, Object o) 
//		   返回指定 collection 中等于指定对象的元素数。
		int frequency = Collections.frequency(list, 3);
		System.out.println(frequency);
//		max min
		System.out.println(Collections.max(list1));

		System.out.println("----------------------------------");
		List<String> list2 = new ArrayList<String>();
		list2.add("a");
		list2.add("b");
		list2.add("c");
		list2.add("c");
		list2.add("c");
		list2.add("d");
//		replaceAll(List<T> list, T oldVal, T newVal) 
//        使用另一个值替换列表中出现的所有某一指定值。
		Collections.replaceAll(list2, "c", "java");
		System.out.println(list2);
//		reverse(List<?> list) 
//        反转指定列表中元素的顺序
		Collections.reverse(list1);
		System.out.println(list1);
//		shuffle(List<?> list)将list集合中的元素进行随机置换,打乱
		Collections.shuffle(list2);
		System.out.println(list2);
//		sort(List<E> list)将list集合中的元素进行自然排序
		Collections.shuffle(list1);
		System.out.println(list1);
		Collections.sort(list1);
		System.out.println(list1);
//		
//		unmodifiablexxx
		List<Integer> newList = Collections.unmodifiableList(list);
		System.out.println("newList: " + newList);
//		newList.add(5);不能对newList中的数据进行修改
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值