JavaSE 进阶 (6) 集合

泛型-概述

如果在创建集合的时候,不写泛型会怎么样?

/images/java/JavaSE 进阶 (6) 集合/1.png
(图1)
/images/java/JavaSE 进阶 (6) 集合/2.png
(图2)
/images/java/JavaSE 进阶 (6) 集合/3.png
(图3)

泛型概述

泛型:是 JDK5 中引入的特性,它提供了编译时类型安全检测机制

泛型的好处:

  • 把运行时期的问题提前到了编译期间
  • 避免了强制类型转换

Set-概述

集合类体系结构

/images/java/JavaSE 进阶 (6) 集合/4.png
(图4)

Set-基本使用

Set集合概述和特点

Set 集合的特点

  • 可以去除重复
  • 存取顺序 不一致
  • 没有带索引的方法,所以不能使用普通 for 循环遍历,也不能通过索引来获取/删除 set 集合里的元素

Set集合练习

存储字符串并遍历 (所有单列集合都可以使用迭代器进行遍历,所以 set 集合也可以使用)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MySet1 {
	public static void main(string[] args) {
		Set<String> set = new TreeSet();
		set.add("aaa");
		set.add("aaa");
		set.add("bbb");
		set.add("ccc");
	
		//for(int i = 0; i < set.size(); i++){
		//	//Set集合是没有索引的,所以不能使用通过索引获取元素的方法
		//}			
			

		Iterator<string> it = set.iterator();
		while(it.hasNext()){
			String s = it.next();
			System.out.println(s);  //aaa  bbb  ccc
		}
		//---------------------------------------------------
		for (String s : set){
			System.out.println(s);  //aaa  bbb  ccc
		}
	}
}

存储和取出的顺序不一致

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class MySet1 {
	public static void main(string[] args) {
		Set<String> set = new TreeSet();
		set.add("ccc");
		set.add("aaa");
		set.add("aaa");
		set.add("bbb");
		
		Iterator<string> it = set.iterator();
		while(it.hasNext()){
			String s = it.next();
			System.out.println(s);  //aaa  bbb  ccc
		}
		//---------------------------------------------------
		for (String s : set){
			System.out.println(s);  //aaa  bbb  ccc
		}
	}
}

TreeSet-基本使用

TreeSet集合概述和特点

TreeSet:底层是红黑树结构,所以要求元素必须排序


TreeSet 集合特点

  • 不包含重复元素的集合
  • 没有带索引的方法
  • 可以将元素按照规则进行排序 (TreeSet 虽然 不能保证存和取的顺序,但是可以 对内部的元素进行排序)

TreeSet 集合练习

  • 存储 Integer 类型的整数,并遍历
  • 存储学生对象,并遍历
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
/**
 * Treeset集合来存储Integer类型
 */
public class MyTreeSet1 {
	public static void main(string[] args) {
		TreeSet<Integer> ts = new TreeSet<>();
		ts.add(5);
		ts.add(3);
		ts.add(4);
		ts.add(1);
		ts.add(2);
		System.out.println(ts);  //[1, 2, 3, 4, 5]
	}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
/**
 * Treeset集合来存储Student类型
*/
public class MyTreeset2 {
	public static void main(String[] args) {
		TreeSet<Student> ts = new TreeSet<>();
		Student s1 = new Student("小花"27);
		Student s2 = new Student("小花花"28);
		Student s3 = new Student("小小花"28);
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		System.out.println(ts);
		//Exception in thread "main"java.lang.ClassCastException:class com.itheima.mytreeset.Student cannot be cast to class java.lan
		//报错的原因:没有指定排序的规则,是按照身高排,还是按照年龄排...,没有制定规则
	}
}

想要使用 TreeSet,需要制定排序规则

TreeSet-自然排序

自然排序Comparable的使用

  1. 使用 空参构造 创建 TreeSet 集合
  2. 自定义的 Student 类实现 Comparable 接口
  3. 重写里面的 compareTo 方法

public interface Comparable<T>

该接口对实现它的每个类的对象强加一个整体排序。这个排序被称为类的自然排序,类的 compareTo 方法被称为其自然比较方法。

简单来说,一个类实现了 Comparable 接口,那么就可以根据里面 compareTo 方法的返回值,对元素进行排序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Student implements comparable<Student> { //此处的泛型要和集合里边存储的数据类型保持一致
	private String name;
	private int age;

	public student() {
	}

	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	//set/get...
	
	@Override
	public int compareTo(Student o) {
		//按照对象的年龄进行排序
		int result = this.age -o.age;
		return result;
	}
}

/**
 * Treeset集合来存储Student类型
*/
public class MyTreeset2 {
	public static void main(String[] args) {
		TreeSet<Student> ts = new TreeSet<>();
		Student s1 = new Student("小花"28);
		Student s2 = new Student("小花花"27);
		Student s3 = new Student("小小花"29);
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		//[Student{name='小花花',age=27), Student{name='小花',age=28}, Student{name='小小花',age=29}]
		System.out.println(ts);
	}
}

自然排序简单原理图(找中间的比较)

  • 如果返回值为负数,表示当前存入的元素是较小值,存左边
  • 如果返回值为 0,表示当前存入的元素跟集合中元素重复了,不存
  • 如果返回值为正数,表示当前存入的元素是较大值,存右边
/images/java/JavaSE 进阶 (6) 集合/5.png
(图5)

将创建的三个对象存入到我们创建的容器 TreeSet 集合中

第一个是 小花,28,容器中没有内容,他直接就存进去了,第二个要存的是 小花花,27

/images/java/JavaSE 进阶 (6) 集合/6.png
(图6)

This:表示现在正在存的对象,也就是 小花花,27
O:表示已经存到集合中的元素,也就是 小花,28


第三个是 小小花,29,将正在存的元素与集合中的元素一个一个进行比较

/images/java/JavaSE 进阶 (6) 集合/7.png
(图7)
/images/java/JavaSE 进阶 (6) 集合/8.png
(图8)
/images/java/JavaSE 进阶 (6) 集合/9.png
(图9)

自然排序-练习

案例:按照年龄排序

需求:改写刚刚的学生案例

要求:按照年龄从小到大排,如果年龄一样,则按照姓名首字母排序
   如果年龄和姓名都一样,认为是同一个学生对象,不存入


为什么要先按年龄,再按姓名排序呢?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Student implements comparable<Student> { //此处的泛型要和集合里边存储的数据类型保持一致
	private String name;
	private int age;

	public student() {
	}

	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	//set/get...
	
	@Override
	public int compareTo(Student o){
		//按照对象的年龄进行排序
		int result = this.age -o.age;
		return result;
	}
}

/**
 * Treeset集合来存储Student类型
*/
public class MyTreeset2 {
	public static void main(String[] args) {
		TreeSet<Student> ts = new TreeSet<>();
		Student s1 = new Student("小花"28);
		Student s2 = new Student("小花花"27);
		Student s3 = new Student("小小花"29);
		Student s4 = new Student("小黑"28);
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		//[Student{name='小花花Lage=27), Student{name='小花',age=28}, Student{name='小小花',age=29}]
		System.out.println(ts);
	}
}

我们发现 小黑,28 没有存到集合中,这是因为排序规则是按照年龄排序的,小黑的年龄 28 集合中已经有了,于是在添加的时候,就会认为 小花,28小黑,28 是同一个对象,所以 TreeSet 就把第四个对象扔了


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class Student implements comparable<Student> { //此处的泛型要和集合里边存储的数据类型保持一致
	private String name;
	private int age;

	public student() {
	}

	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	//set/get...
	
	@Override
	public int compareTo(Student o) {
		//按照对象的年龄进行排序
		//主要判断条件
		int result = this.age -o.age;
		//次要判断条件
		result = result == 0 ? this.name.compareTo(o.getName()) : result;
		return result;
	}
}

/**
 * Treeset集合来存储Student类型
*/
public class MyTreeset2 {
	public static void main(String[] args) {
		TreeSet<Student> ts = new TreeSet<>();
		Student s1 = new Student("zhangsan"28);
		Student s2 = new Student("lisi"27);
		Student s3 = new Student("wangwu"29);
		Student s4 = new Student("zhaoliu"28);
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		ts.add(s4);
		System.out.println(ts);
	}
}

姓名是中文的,中文无法按照首字母排序,需要将姓名换成英文的

this.name 是一个字符串,this.name.compareTo() 用的是字符串 String 里的 compareTo 方法

int compareTo(String anotherString) 按字典顺序比较两个字符串

对字符串中的 compareTo 方法进行演示

1
2
3
4
5
6
7
8
public static void main(String[] args) {
	String s1 = "aaa";
	String s2 = "ab";
	System.out.println(s1.compareTo(s2)); //-1
	//首先比较第一个字母,如果第一个字母是一样的,那么继续比较后面的字母
	//当不一样的时候,就拿着a对应的码表值97,减去b的码表值98
	//认为a是比b要小的
}

TreeSet-比较器排序

比较器排序Comparator的使用

  1. TreeSet带参 构造方法使用的是 比较器排序 对元素进行排序的 (如果要使用比较器排序,在创建 TreeSet 的时候,就不能使用空参,空参是自然排序)
  2. 比较器排序,就是 让集合构造方法接收Comparator的实现类对象,重写 compare(To1,To2) 方法
  3. 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

练习:

需求:用比较器排序实现下面的需求

要求:自定义 Teacher 老师类,属性为姓名和年龄
   请按照年龄排序,如果年龄一样,则按照姓名进行排序,姓名都使用英文字母表示


构造方法

Constructor 描述
TreeSet() 构造一个新的、空的树组,根据其元素的自然排序进行排序。
TreeSet(Collection<? extends E> c) 构造一个包含指定集合中的元素的新树集,根据其元素的自然排序进行排序。
TreeSet(Comparator<? super E> comparator) 构造一个新的、空的树集,根据指定的比较器进行排序。
TreeSet(Sortedset s) 构造一个包含相同元素的新树,并使用与指定排序集相同的顺序。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class MyTreeset4 {
	public static void main(String[] args) {

		Treeset<Teacher> ts = new Treeset<>(new Comparator<Teacher>() {  //泛型要和集合里存储的元素类型保持一致
			@Override
			public int compare(Teacher o1,Teacher o2){    //匿名内部类
				//o1表示现在要存入的那个元素
				//o2表示已经存入到集合中的元素
				//主要条件
				int result = o1.getAge() - o2.getAge();
				//次要条件
				result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
				return result;
			}
		});
	
		Teacher t1 = new Teacher("zhangsan", 23);
		Teacher t2 = new Teacher("lisi", 22);
		Teacher t3 = new Teacher("wangwu", 24);

		ts.add(t1);
		ts.add(t2);
		ts.add(t3);
	}
}

o1 代表当前要存入的元素,o2 代表集合中的元素,比较的时候先找集合中处于中间位置的元素比较,如果比中间的位置元素小,就继续与左边的元素比较,反之则与右边的元素比较


0%