黑马程序员-集合-Set和Map和Collections

第一讲 Set

1.      Set接口的概述

不包含重复的元素,无序(存储和取出的顺序不一样)。和collection的功能是一样的,无特殊。

 

|--HashSet: HashSet底层数据结构是哈希表,保证元素唯一性的原理是:判断元素的hashCode()是否相同,相同就判断equalis()方法是否为true;不保证Set的迭代顺序。

 

|--TreeSet: TreeSet 底层是二叉树结构,元素是唯一,有序的(按照某种规则排序)

 

2.      HashSet

HashSet中和元素唯一性相关的操作都依赖于hashCode()和euqals()方法

如add()方法的源码可知

步骤:比较哈希值

                             相同:比较地址值或equals()

                                                         相同:不添加

                                                         不同:添加到集合中

                             不同:添加到集合中

注意:String重写了hashCode()和equals()方法,所以内容相同的会直接去掉

示例:HashSet存储自定义对象并遍历

//先是声明一个学生类Student.java,两个成员变量,名字和年龄
public class Student {
private String name;
private int age;
 
public Student() {
           super();
}
 
public Student(String name, int age) {
           super();
           this.name = name;
           this.age = 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;
}
 
//重写hashCode和equals
@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;
}
 
@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;
}
}


在HashSetDemo.java中遍历

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

		// 创建学生对象
		Student s1 = new Student("林青霞", 27);
		Student s2 = new Student("柳岩", 22);
		Student s3 = new Student("王祖贤", 30);
		Student s4 = new Student("林青霞", 27);
		Student s5 = new Student("林青霞", 20);
		Student s6 = new Student("范冰冰", 22);

		// 添加元素
		hs.add(s1);
		hs.add(s2);
		hs.add(s3);
		hs.add(s4);
		hs.add(s5);
		hs.add(s6);

		// 遍历集合
		for (Student s : hs) {
			System.out.println(s.getName() + "---" + s.getAge());
		}
	}
}


3.      TreeSet

TreeSet的特点是唯一,有序的,有序是指让元素按照某种规则排序

规则分为两种,自然排序和比较器排序。

TreeSet的底层是依赖于二叉树中的红黑树

3.1   红黑树---一种自平衡的二叉查找树

 



 

3.2   TreeSet的排序规则—自然排序

自然排序是让元素本身具备比较性,所比较的元素的类实现实现Comparable接口,覆盖compareTo()方法。

如果返回值为0,则表示此对象等于指定对象,所以排序后保存其中之一

返回值为正数,则此对象大于指定对象;返回值为负数,则此对象小于指定对象

Student.java

/*
 * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口
 */
public class Student implements Comparable<Student> {
	private String name;
	private int age;

	public Student() {
		super();
	}

	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = 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;
	}

	@Override
	public int compareTo(Student s) {
	        // 这里返回什么,其实应该根据排序规则来做
		// 按照年龄排序,主要条件
		int num = this.age - s.age;
		// 次要条件
		// 年龄相同的时候,还得去看姓名是否也相同
		// 如果年龄和姓名都相同,才是同一个元素
		int num2 = num == 0 ? this.name.compareTo(s.name) : num;
		return num2;
	}
}
TreeSetDemo.java

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

		// 创建元素
		Student s1 = new Student("linqingxia", 27);
		Student s2 = new Student("zhangguorong", 29);
		Student s3 = new Student("wanglihong", 23);
		Student s4 = new Student("linqingxia", 27);
		Student s5 = new Student("liushishi", 22);
		Student s6 = new Student("wuqilong", 40);
		Student s7 = new Student("fengqingy", 22);

		// 添加元素
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		ts.add(s5);
		ts.add(s6);
		ts.add(s7);

		// 遍历
		for (Student s : ts) {
			System.out.println(s.getName() + "---" + s.getAge());
		}
	}
}

显示结果:




3.3  TreeSet的排序规则—比较器排序

 集合自身具备比较性。  在集合初始化时,定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。也可以定义一个类,实现Comparator接口,覆盖compare()方法

我们使用的是直接将比较器对象作为参数传递给TreeSet集合的构造函数

public class TreeSetDemo {
	public static void main(String[] args) {
		TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {

			@Override
			public int compare(Student s1, Student s2) {
				// 姓名长度
				int num = s1.getName().length() - s2.getName().length();
				// 姓名内容
				int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
						: num;
				// 年龄
				int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
				return num3;
			}
		});

		// 创建元素
		Student s1 = new Student("linqingxia", 27);
		Student s2 = new Student("zhangguorong", 29);
		Student s3 = new Student("wanglihong", 23);
		Student s4 = new Student("linqingxia", 27);
		Student s5 = new Student("liushishi", 22);
		Student s6 = new Student("wuqilong", 40);
		Student s7 = new Student("fengqingy", 22);
		Student s8 = new Student("linqingxia", 29);

		// 添加元素
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		ts.add(s5);
		ts.add(s6);
		ts.add(s7);
		ts.add(s8);

		// 遍历
		for (Student s : ts) {
			System.out.println(s.getName() + "---" + s.getAge());
		}
	}
}

结果显示:符合设定的规定,先比较姓名长度,再比较年龄大小都是按照升序排序

         wuqilong---40

         fengqingy---22

         liushishi---22

         linqingxia---27

         linqingxia---29

         wanglihong---23

    zhangguorong---29

第二讲 Map

1.   Map概述

Map<K,V>接口存储键值对的元素,其中K代表的是键,V代表的是值,K是唯一的,不可重复的。

键与值的关系:

将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到同一个值

注意:Map集合的数据结构针对键有效,跟值无关

2.  Map的功能

1:添加功能

  V put(Kkey,V value):添加元素。

  如果键是第一次存储,就直接存储元素,返回null

  如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值

2:删除功能

 voidclear():移除所有的键值对元素

  Vremove(Object key):根据键删除键值对元素,并把值返回

3:判断功能

  booleancontainsKey(Object key):判断集合是否包含指定的键

 booleancontainsValue(Object value):判断集合是否包含指定的值

  booleanisEmpty():判断集合是否为空

4:获取功能

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

  Vget(Object key):根据键获取值

  Set<K> keySet():获取集合中所有键的集合

  Collection<V> values():获取集合中所有值的集合

5:长度功能

      intsize():返回集合中的键值对的对数

3.   集合的两种遍历方式

3.1   通过键找值:

思路:A:获取所有的键

               B:遍历键的集合,获取得到每一个键

        C:根据键去找值

             

public class MapDemo3 {
	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();

		// 创建元素并添加到集合
		map.put("杨过", "小龙女");
		map.put("郭靖", "黄蓉");
		map.put("杨康", "穆念慈");
		map.put("陈玄风", "梅超风");

		Set<String> set = map.keySet();
		for (String s : set) {
			String value = map.get(s);
			System.out.println(s + "---" + value);
		}
	}
}

注意:为什么通过Set存储键集合,因为Set集合具有唯一性的特点,且Set具备迭代器。所以可以通过迭代方式取出键,再通过get方法,获取每一个键对应的值。

3.2  键值对形式

思路:

A:获取所有键值对对象的集合

B:遍历键值对对象的集合,得到每一个键值对对象

          C:根据键值对对象获取键和值

public class MapDemo4 {
	public static void main(String[] args) {

		// 创建集合对象
		Map<String, String> map = new HashMap<String, String>();

		// 创建元素并添加到集合
		map.put("杨过", "小龙女");
		map.put("郭靖", "黄蓉");
		map.put("杨康", "穆念慈");
		map.put("陈玄风", "梅超风");

		Set<Map.Entry<String, String>> set = map.entrySet();
		for (Map.Entry<String, String> me : set) {
			String key = me.getKey();
			String value = me.getValue();
			System.out.println(key + "---" + value);
		}
	}
}

4.    HashMap:

HashMap是基于哈希表的Map接口实现,哈希表的作用是保证键的唯一性

HashMap<K,V>,如果K为引用类型,需要重写内部的equals()和hashCode()方法

示例:一个引用类型的遍历

public class Student {
//省略部分代码
@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;
	}

	@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 class HashMapDemo4 {
	public static void main(String[] args) {

		// 创建集合对象
		HashMap<Student, String> hm = new HashMap<Student, String>();

		// 创建学生对象
		Student s1 = new Student("貂蝉", 27);
		Student s2 = new Student("王昭君", 30);
		Student s3 = new Student("西施", 33);
		Student s4 = new Student("杨玉环", 35);
		Student s5 = new Student("貂蝉", 27);
		// 添加元素
		hm.put(s1, "8888");
		hm.put(s2, "6666");
		hm.put(s3, "5555");
		hm.put(s4, "7777");
		hm.put(s5, "9999");

		Set<Student> set = hm.keySet();
		for (Student key : set) {
			String value = hm.get(key);
			System.out.println(key.getName() + "---" + key.getAge() + "---"
					+ value);
		}

	}
}

测试结果:重复的值根本就没有保存在map中

 

 

5.  TreeMap

TreeMap的键是红黑树结构,保证键的排序性和唯一性

依旧是两种排序方式:自然排序和比较器排序

示例:比较器排序

public class TreeMapDemo2 {
	public static void main(String[] args) {
		TreeMap<Student, String> tm = new TreeMap<Student, String>(
				new Comparator<Student>() {

					@Override
					public int compare(Student s1, Student s2) {
						// 主要条件
						int num = s1.getAge() - s2.getAge();
						// 次要条件
						int num2 = num == 0 ? s1.getName().compareTo(
								s2.getName()) : num;
						return num2;
					}

				});
		// 创建学生对象
		Student s1 = new Student("潘安", 30);
		Student s2 = new Student("柳下惠", 35);
		Student s3 = new Student("唐伯虎", 33);
		Student s4 = new Student("燕青", 32);
		Student s5 = new Student("唐伯虎", 33);

		// 存储元素
		tm.put(s1, "宋朝");
		tm.put(s2, "元朝");
		tm.put(s3, "明朝");
		tm.put(s4, "清朝");
		tm.put(s5, "汉朝");
		
		Set<Student> set = tm.keySet();
		for(Student key:set){
			String value = tm.get(key);
			System.out.println(key.getName() + "---" + key.getAge() + "---"
					+ value);
		}
	}
}
测试结果:可以看出“唐伯虎--33”元素并没有重复


第三讲 Collections

1. Collections类概述

针对集合操作的工具类,都是静态方法

2. 需要掌握的方法

  要知道的方法
  public static <T> void sort(List<T> list):排序 默认情况下是自然顺序。
  public static <T> int binarySearch(List<?> list,T key):二分查找
  public static <T> T max(Collection<?> coll):最大值
  public static void reverse(List<?> list):反转
  public static void shuffle(List<?> list):随机置换,每调一次,元素的位置随机换一次

示例:Collections类针对自定义对象的排序

/*
 * Collections可以针对ArrayList存储自定义对象的元素排序
 */
public class CollectionsDemo {
	public static void main(String[] args) {
		// 创建集合对象
		List<Student> list = new ArrayList<Student>();

		// 创建学生对象
		Student s1 = new Student("林青霞", 27);
		Student s2 = new Student("风清扬", 30);
		Student s3 = new Student("刘晓曲", 28);
		Student s4 = new Student("武鑫", 29);
		Student s5 = new Student("林青霞", 27);

		// 添加元素对象
		list.add(s1);
		list.add(s2);
		list.add(s3);
		list.add(s4);
		list.add(s5);

		// 排序
		// 自然排序
		// Collections.sort(list);
		// 比较器排序
		// 如果同时有自然排序和比较器排序,以比较器排序为主
		Collections.sort(list, new Comparator<Student>() {
			@Override
			public int compare(Student s1, Student s2) {
				int num = s2.getAge() - s1.getAge();
				int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
						: num;
				return num2;
			}
		});

		// 遍历集合
		for (Student s : list) {
			System.out.println(s.getName() + "---" + s.getAge());
		}
	}
}





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值