Java的集合Set和Map的简单精辟讲解

Java的集合Set和Map的简单精辟讲解

set - - - 接口

  1. **解释:**存储的数据是无序的,不可以重复。
  2. 分类:
    • HashSet - - - 类: 底层是hash表,线程不安全。
    • TreeSet - - - 类: 底层是二叉树,线程不安全。
  3. HashSet:
    • 去重的原理: 是通过调用元素内部的hashcode和equals方法实现去重,首先调用hashcode方法,比较两个元素的哈稀值,如果不同的时候,直接认为是两个对象,停止比较,如果相同,再去调用equals比较。
    • 注意的点:hashset本身不能排序,对于自定义的类,要想按照自己自定义的规则去重,必须重写hashcode和equals方法。
    • 实例:使用hashset实现对person1类对象的去重
	class Person1 {
		String name;
		int age;
		public Person1() {
			// TODO Auto-generated constructor stub
		}
		public Person1(String name, int age) {
			super();
			this.name = name;
			this.age = age;
		}
		@Override
		public String toString() {
			return "Person [name=" + name + ", age=" + age + "]";
		}
		//重写hashCode方法
		@Override
		public int hashCode() {
			// TODO Auto-generated method stub
			return (this.name + this.age * 1000) .hashCode();
		}
		@Override
		public boolean equals(Object obj) {
			if( !(obj instanceof Person1)) {
				throw new ClassCastException();
			}
			Person1 person = (Person1) obj;
			return person.age == this.age && person.name.equals(this.name);
		}
	}
	public class Demo7 {
		public static void main(String[] args) {
			HashSet<String> set = new HashSet<>();
			//在string中重写了hashCode和equals方法。
			//在add内部实现了去重的功能,默认调用的是字符串的hashCode和equals方法,实现去重
			set.add("java1");
			set.add("java2");
			set.add("java2");
			set.add("java5");
			set.add("java3");
			set.add("java4");
			System.out.println(set);
			HashSet<Person1> set1 = new HashSet<>();
			//在string中重写了hashCode和equals方法。
			//在add内部实现了去重的功能,默认调用的是字符串的hashCode和equals方法,实现去重
			set1.add(new Person1("小明", 20));
			set1.add(new Person1("小明", 20));
			set1.add(new Person1("小红", 20));
			set1.add(new Person1("小李", 20));
			set1.add(new Person1("小花", 20));
			set1.add(new Person1("小白", 20));
			System.out.println(set1);
		}
	}
	* 分析**<font color=#FF0000>(重点)</font>**:要重写Person1的HashCode和equals方法,按照自己定义的规则来重写,比较规则是按照年龄和性别比较。先是用hashcode方法来比较年龄,来确定它是不是同一个年龄,如果年龄相同了,那么则判定他们的姓名,相同则是同一个对象,否则,就不是同一个对象。
  1. TreeSet:
    • 说明:可以实现去重和排序,使用TreeSet存储字符串的时候,自动实现了排序。
    • 能够排序的原因:在add:方法中调用了字符串的 compareTo方法,compareTo方法是来自于Comparable接口。
    • 排序规则:按字典顺序比较两个字符串
	public class Demo8 {
		public static void main(String[] args) {
			//默认是升序并且是按照字典排序
			set.add("java2");
			set.add("java8");
			set.add("java3");
			set.add("java4");
			set.add("java4");
			System.out.println(set);
			
			//实例:将Person2的对象存储入TreeSet,实现排序和去重
			TreeSet<Person2> set1 = new TreeSet<>();
			set1.add(new Person2("bobo", 20));
			set1.add(new Person2("bobo", 18));
			set1.add(new Person2("bobo3", 200));
			set1.add(new Person2("bobo5", 20));
			set1.add(new Person2("bobo", 20));
			System.out.println(set1);
		}
	}
	
	class Person2 implements Comparable<Object>{
		String name;
		int age;
		public Person2(String name, int age) {
			super();
			this.name = name;
			this.age = age;
		}
		@Override
		public String toString() {
			return "Person2 [name=" + name + ", age=" + age + "]";
		}
		
		//重写compareTo方法
		//按照姓名和年龄比较,只要姓名和年龄相同就认为是一个人
		@Override
		public int compareTo(Object o) {
			//容错处理
			if (!(o instanceof Person2)) {
				throw new ClassCastException();
			}
			//向下转型
			Person2 person2 = (Person2)o;
			//先按照年龄比,年龄相同再按照姓名比
			int num = age - person2.age;
			return num==0?name.compareTo(person2.name):num;
		}
	}

分析 (重点):能够实现排序的原因是方法中调用了字符串的 compareTo方法,compareTo方法是来自于Comparable接口。有时候我们需要按照自己定义的规则去实现TreeSet的排序规则的话,就得实现comparator接口,并且重写compare方法,也就是重新定义一个比较器。

  • 比较器的创建

    	class ComWithLength implements Comparator<Object> {
    		@Override
    		public int compare(Object o1, Object o2) {
    			// TODO Auto-generated method stub
    			if(!(o1 instanceof String)) throw new ClassCastException("类型转换错误");
    			if(!(o2 instanceof String)) throw new ClassCastException("类型转换错误");
    			//向下转型
    			String string1 = (String) o1;
    			String string2 = (String) o2;
    			//字符串按照从短到长排序,长度相同按照字典排序
    			int num = string1.length() - string2.length();
    			return num == 0 ? string1.compareTo(string2) : num;
    		}
    		
    	}
    
    
    • 说明:要是用的时候需要将这个比较器传给这个集合实现自己的排序规则。
  • 比较器的使用

    	public class Demo9 {
    		public static void main(String[] args) {
    			//创建一个比较器对象
    			ComWithLength comWithLength = new ComWithLength();
    			//将比较器对象指定给当前的TreeSet对象。
    			TreeSet<Object> treeSet = new TreeSet<>(comWithLength);
    			treeSet.add("java1");
    			treeSet.add("java2");
    			treeSet.add("java1");
    			treeSet.add("java");
    			System.out.println(treeSet);
    		}
    	}
    
    • 说明:要传入一个比较器才能够实现自定义比较,因为人工的比较器优先级高于系统的。

Map - - - 接口

  1. **解释:**本身是一个接口,存储的是键值对,一个元素就是一个键(key)值(value)对,key必须是唯一。的.value可以相同
  2. 分类:
    • HashMap - - - 类: 底层是hash表,线程不安全。
    • TreeMap - - - 类: 底层是二叉树,线程不安全。
  3. Map接口的一些方法(用代码来看):
	public class Demo8 {
		public static void main(String[] args) {
			//介绍Map接口的方法
			Map<String, String> map = new HashMap<>();
			//1.增加
			//V put(K key,V value)  增加一个键值对
			//关于返回值:如果当前的key没有对应值,返回null.如果已经有值了,会将原来被替换的值返回.
			map.put("01", "java");
			map.put("02", "iOS");
			map.put("03", "html");
			map.put("04", "python");
			System.out.println(map.put("01", "php"));
			System.out.println(map);
			//void putAll(Map<? extends K,? extends V> map)  增加多个
			//2.删除
			//V remove(Object key)  根据key删除元素
			map.remove("01");
			System.out.println(map);
			//void clear()  删除全部
			//3.获取
			//V get(Object key)  根据key查找元素
			System.out.println(map.get("02"));
			//int size()  获取键值对的个数
			System.out.println(map.size());
			//Set<K> keySet()   遍历方法一
			//Set<Map.Entry<K,V>> entrySet() 遍历方法二
			//4.常用的判断
			//boolean isEmpty()
			System.out.println(map.isEmpty());//false
			//boolean containsKey(K key) 是否包含当前的key
			System.out.println(map.containsKey("02"));//true
			//boolean containsValue(V value) 是否包含当前的value
			System.out.println(map.containsValue("html"));//true
		}
	}
  1. Map的遍历:

    • 方法一:得到所有的key,存放在一个Set中.利用set的迭代器遍历得到key,在利用key得到value。
    public class Demo9 {
        public static void main(String[] args) {
    		Map<String, String> map = new HashMap<>();
    		map.put("01", "java");
    		map.put("03", "php");
    		map.put("05", "BigData");
    		map.put("02", "python");
    		System.out.println(map);
    		//通过Set<K> keySet()   遍历方法一
    		Set<String> set1 = map.keySet();
    		//获取迭代器
    		Iterator<String> iterator = set1.iterator();
    		while (iterator.hasNext()) {
    			String key =  iterator.next();
    			
    			//再去获取value
    			System.out.println("key:"+key+"   value:"+map.get(key));
    		}
    	}
    }
    
    • 方法二:得到每个键值对对应的映射关系类型的对象(entry/实体),存放在一个Set中,利用set的迭代器遍历得到entry,再利用entry的方法得到value和key。
    public class Demo9 {
        public static void main(String[] args) {
    		Map<String, String> map = new HashMap<>();
    		map.put("01", "java");
    		map.put("03", "php");
    		map.put("05", "BigData");
    		map.put("02", "python");
    		System.out.println(map);
    		//Set<Map.Entry<K,V>> entrySet() 遍历方法二
    		//先得到装着entry的set
    		Set<Map.Entry<String, String>> set = map.entrySet();
    		//获取迭代器
    		Iterator<Map.Entry<String, String>> iterator2 = set.iterator();
    		while (iterator2.hasNext()) {
    			Map.Entry<String, String> entry = iterator2.next();
    			//entry.setValue("hah");
    			//再去获取key,value
    			System.out.println("key:"+entry.getKey()+"   value:"+entry.getValue());
    		}
    		System.out.println(map);
    	}
    }
    
    • 说明:Entry是Map内的一个静态接口。因为有了集合中的键值对才有映射关系.而当前的映射关系又是对集合内部的描述,所以要将Entry映射关系接口放入Map接口中。
  2. HashMap:

    • 去重的原理:是通过调用元素内部的hashcode和equals方法实现去重,首先调用hashcode方法,比较两个元素的哈稀值,如果不同的时候,直接认为是两个对象,停止比较,如果相同,再去调用equals比较。
    • 注意的点:hashMap本身不能排序,对于自定义的类,要想按照自己自定义的规则去重,必须重写hashcode和equals方法。
    • 实例:将Animal类的对象存入HashMap,名字和年龄相同的认为是同一条狗。
    class Animal{
    	String name;
    	int age;
    	public Animal(String name, int age) {
    		super();
    		this.name = name;
    		this.age = age;
    	}
    	@Override
    	public String toString() {
    		return "Animal [name=" + name + ", age=" + age + "]";
    	}
    	//重写hashCode
    	@Override
    	public int hashCode() {
    		
    		return name.hashCode()+age*1000;
    	}
    	//重写equals
    	@Override
    	public boolean equals(Object obj) {
    		if (!(obj instanceof Animal)) {
    			throw new ClassCastException("类型转化错误");
    		}
    		Animal animal = (Animal)obj;
    		return age==animal.age  && name.equals(animal.name);
    	}
    }
    
    public class Demo10 {
    	public static void main(String[] args) {
    		HashMap<String, String> map = new HashMap<>();
    		//在put方法中调用了作为key的String的hashCode和equals方法
    		map.put("01", "java");
    		map.put("03", "java2");
    		map.put("05", "java4");
    		map.put("02", "java6");
    		map.put("01", "java9");
    		System.out.println(map);
    		//实例:将Animal类的对象存入HashMap,名字和年龄相同的认为是同一条狗
    		HashMap<Animal, String> map1 = new HashMap<>();
    		//在put方法中调用了作为key的Animla的hashCode和equals方法
    		map1.put(new Animal("拉布拉多", 20), "java");
    		map1.put(new Animal("柯基", 10), "java2");
    		map1.put(new Animal("黑贝", 2), "java4");
    		map1.put(new Animal("茶杯犬", 21), "java6");
    		map1.put(new Animal("藏獒", 12), "java9");
    		map1.put(new Animal("藏獒", 12), "java9");
    		System.out.println(map1);
    	}
    }
    
  3. TreeMap:

    • 说明:可以实现去重和排序,实现排序,去重,类似于TreeSet。
    • 方法一:让key去实现Comparable接口。
	class Animal1 implements Comparable<Animal1>{
		String name;
		int age;
		public Animal1(String name, int age) {
			super();
			this.name = name;
			this.age = age;
		}
		@Override
		public String toString() {
			return "Animal1 [name=" + name + ", age=" + age + "]";
		}
	
		//重写compareTo方法
		@Override
		public int compareTo(Animal1 o) {
			int num = age-o.age;
			return num==0?name.compareTo(o.name):num;
		}
	}

	public class Demo11 {
		public static void main(String[] args) {
			TreeMap<String, String> map = new TreeMap<>(); 
			//String实现了Comparable接口的compareTo方法,所以实现了排序和去重
			map.put("01", "java");
			map.put("03", "java2");
			map.put("05", "java4");
			map.put("02", "java6");
			map.put("01", "java9");
			System.out.println(map);
			TreeMap<Animal1, String> map1 = new TreeMap<>(); 
			map1.put(new Animal1("labu", 20), "java");
			map1.put(new Animal1("keji", 20), "java2");
			map1.put(new Animal1("zangao", 12), "java9");
			map1.put(new Animal1("zangao", 12), "java9");
			System.out.println(map1);
		}
	}
  • 分析**(重点)**:能够实现排序的原因是方法中调用了字符串的 compareTo方法,compareTo方法是来自于Comparable接口。
  • 方法二:创建自己的比较器
    • 比较器的创建
	class MyCompera implements Comparator<Now2>{
			@Override
			public int compare(Now2 o1, Now2 o2) {
				int num = o1.age - o2.age;
				return num == 0 ? o1.name.compareTo(o2.name):num;
			}
		}
		class Now2  {
			public String name;
			public int age;
			public Now2() {
				super();
				// TODO Auto-generated constructor stub
			}
			public Now2(String name, int age) {
				super();
				this.name = name;
				this.age = age;
			}
		}
  • 说明:要是用的时候需要将这个比较器传给这个集合实现自己的排序规则。
  • 比较器的使用
		public class Three {
			public static void main(String[] args) {
				TreeMap<Now2, String> treeMap = new TreeMap<>(new MyCompera());
			}
		}
  • 说明:要传入一个比较器才能够实现自定义比较,因为人工的比较器优先级高于系统的。

总结:集合是java中很重要的一个知识点,学好这个知识点就是攻下java中较为难的一块儿阵地了,也说明java知识又上了一个台阶了。为追梦路上的你说句“有梦就勇敢去追吧。”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值