Set集合概述及特点
A:Set集合概述及特点: 通过API查看即可
B: 案例演示: 无序(存储和取出的顺序)和唯一
案例一:
import java.util.Collection;
import java.util.HashSet;
public class SetDemo {
public static void main(String[] args) {
//Collection List 元素有序,允许元素重复
//Set 元素唯一 一个不包含重复元素的 collection
//HashSet 元素唯一,无序(存取顺序不一致)
//HashSet 底层数据结构是哈希表:是元素为链表的数组,具有链表和数组的特点 像新华字典(JDK1.7)
//HashSet()
//构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。
HashSet<String> set = new HashSet<>();
set.add("林心如");
set.add("杨超越");
set.add("黎姿");
set.add("黎姿");
set.add("刘亦菲");
set.add("李易峰");
for (String s : set) {
System.out.println(s);
}
}
}
黎姿
林心如
杨超越
刘亦菲
李易峰
HashSet的使用
案例一:
import java.util.HashSet;
public class SetDemo2 {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<>();
set.add(100);
// public HashSet() {
// map = new HashMap<>();
//}
//public boolean add (E e){
// return map.put(e, PRESENT) == null;
//}
//public V put (K key, V value){
// return putVal(hash(key), key, value, false, true);
//}
//static final int hash (Object key){
// int h;
// return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
//}
set.add(200);
set.add(100);
set.add(300);
set.add(90);
set.add(109);
for (Integer integer : set) {
System.out.println(integer);
}
}
}
结果:
100
200
90
300
109
HashSet保证元素唯一性
- HashSet 底层数据结构是哈希表. HashSet 不是线程安全的 集合元素可以是 null
- 哈希表:是一个元素为链表的数组,综合了数组和链表的优点 (像新华字典一样) (JDK1.7之前)
- 当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,
然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。
HashSet 集合判断两个元素相等的标准:
两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。
结论:HashSet 保证元素唯一性是靠元素重写hashCode()和equals()方法来保证的,如果不重写则无法保证。
案例一:
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//@Override
//public int hashCode() {
// //张三 23 4+23*11
// //张三 23 4+23*11
// //张三 23 4+24
// //李四 24 3+24*11
//
// return this.name.hashCode() + this.age * 11;
//}
//
//@Override
//public boolean equals(Object obj) {
//
// System.out.println(this + "===" + obj);
// if (this == obj) {
// return true;
// }
// if (!(obj instanceof Student)) {
// return false;
// }
// Student student = (Student) obj;
//
// return this.name.equals(student.name) && this.age == student.age;
//}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
import java.util.HashMap;
import java.util.HashSet;
public class MyTest {
public static void main(String[] args) {
//HashSet集合能够保证元素的唯一性,是靠元素重写hashCode()方法和equals方法来保证的,如果元素不重写则无法保证
//HashSet 底层用的是HashMap来存的
Student s1 = new Student("王五", 25);
Student s2 = new Student("王五", 25);
Student s3 = new Student("王五", 25);
Student s4 = new Student("王五", 252);
Student s5 = new Student("王五2", 235);
Student s6 = new Student("王五3", 25);
Student s7 = new Student("王五4", 2665);
Student s8 = new Student("王五5", 285);
Student s9 = new Student("王五6", 285);
Student s10 = new Student("王五7", 255);
HashSet<Student> hashSet = new HashSet<>();
hashSet.add(s1);
hashSet.add(s2);
hashSet.add(s3);
hashSet.add(s4);
hashSet.add(s5);
hashSet.add(s6);
hashSet.add(s7);
hashSet.add(s8);
hashSet.add(s9);
hashSet.add(s10);
for (Student student : hashSet) {
System.out.println(student.getName() + "==" + student.getAge());
}
}
}
LinkedHashSet的概述和使用
数据结构 有两个 链表和哈希表
链表保证有序 哈希表保证元素唯一
A:LinkedHashSet的概述: 元素有序 , 并且唯一
B:案例演示: LinkedHashSet的特点
案例一:
// LinkedHashSet 底层数据结构是链表和哈希表,元素有序且唯一 ,链表保证了元素有序,哈希表保证了元素
import java.util.LinkedHashSet;
public class MyTest {
public static void main(String[] args) {
// LinkedHashSet 底层数据结构是链表和哈希表,元素有序且唯一 ,链表保证了元素有序,哈希表保证了元素
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("A");
linkedHashSet.add("B");
linkedHashSet.add("D");
linkedHashSet.add("E");
linkedHashSet.add("C");
linkedHashSet.add("E");
linkedHashSet.add("C");
linkedHashSet.add("E");
linkedHashSet.add("C");
for (String s : linkedHashSet) {
System.out.println(s);
}
}
}
结果:
A
B
D
E
C
TreeSet概述及使用
A: TreeSet集合的特点: 元素唯一,并且可以对元素进行排序
排序:
a: 自然排序
b: 使用比较器排序
到底使用的是哪一种的排序取决于,构造方法.
TreeSet 排序方式分为 自然排序和比较器排序
具体用哪种排序,根据你使用的构造方法,用空参构造,那么就使用的是自然排序
有参构造,可以使用比较器来排序
B:案例演示: TreeSet存储Integer类型的元素并遍历
存储下列元素: 20 , 18 , 23 , 22 , 17 , 24, 19 , 18 , 24
注意:使用TreeSet集合进行元素的自然排序,那么对元素有要求,要求这个元素必须实现*Comparable接口 否则无法进行自然排序
保证元素的唯一性是靠compareTo方法的返回值来确定如果返回0 表示两个元素相等则不重复存储
案例一:
import java.util.TreeSet;
public class MyTest {
public static void main(String[] args) {
// TreeSet 底层数据结构是二叉树,元素唯一,他最大的特点是能够对元素进行排序
//20, 18, 23, 22, 17, 24, 19, 18, 24
TreeSet<Integer> treeSet = new TreeSet<>();
//public static int compare ( int x, int y){
// return (x < y) ? -1 : ((x == y) ? 0 : 1);
//}
treeSet.add(20);
treeSet.add(18);
treeSet.add(23);
treeSet.add(22);
treeSet.add(17);
treeSet.add(24);
treeSet.add(19);
treeSet.add(18);
treeSet.add(24);
for (Integer integer : treeSet) {
System.out.println(integer);
}
}
}
结果:
17
18
19
20
22
23
24
TreeSet自然排序的原理和图解
A:画图演示: TreeSet保证元素唯一和自然排序的原理和图解
二叉树的数据结构 先存入一个树根 分两个叉
存储元素时 跟树根比较 小的放在左边 大的放在右边
如果相等就不存储
取的时候按照 左中右的顺序来取
案例一:
import java.util.Objects;
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;
}
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 "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student s) {
//比较逻辑是按照年龄大小来排序
int num = this.age - s.age;
//当年龄相同不能说明他是同一个对象,还得比较姓名
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
//if(num==0){
// num=this.name.compareTo(s.name);
//}
return num2;
}
}
import sun.reflect.generics.tree.Tree;
import java.util.TreeSet;
public class MyTest {
public static void main(String[] args) {
//按照学生的年龄大小来排序
Student s1 = new Student("王五", 21);
Student s11 = new Student("王五", 21);
Student s123 = new Student("王五3333333333", 21);
Student s2 = new Student("王五", 22);
Student s3 = new Student("王五111", 25);
Student s4 = new Student("王五3333", 252);
Student s5 = new Student("王五22222222222", 235);
Student s6 = new Student("王五3", 25);
Student s7 = new Student("王五2222222224", 2665);
Student s8 = new Student("王五5", 288);
Student s9 = new Student("王五22226", 285);
Student s10 = new Student("王五7", 255);
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(s1);
treeSet.add(s11);
treeSet.add(s2);
treeSet.add(s3);
treeSet.add(s4);
treeSet.add(s5);
treeSet.add(s6);
treeSet.add(s7);
treeSet.add(s8);
treeSet.add(s9);
treeSet.add(s10);
treeSet.add(s123);
//如果我们使用的是自然排序:那么对元素是有要求的,要求元素必须实现一个Comparable接口重写里面的comPareTo方法,根据此方法的返回值的正负0 来决定元素在二叉树的位置
// System.out.println(treeSet);
for (Student student : treeSet) {
System.out.println(student);
//Student {
// name = '王五', age = 21
//}
//Student {
// name = '王五', age = 21
//}
//Student {
// name = '王五', age = 22
//}
//Student {
// name = '王五111', age = 25
//}
//Student {
// name = '王五3333', age = 252
//}
//Student {
// name = '王五2', age = 235
//}
//Student {
// name = '王五3', age = 25
//}
//Student {
// name = '王五4', age = 2665
//}
//Student {
// name = '王五5', age = 288
//}
//Student {
// name = '王五6', age = 285
//}
//Student {
// name = '王五7', age = 255
//}
}
}
}
结果:
Student{name=‘王五’, age=21}
Student{name=‘王五3333333333’, age=21}
Student{name=‘王五’, age=22}
Student{name=‘王五111’, age=25}
Student{name=‘王五3’, age=25}
Student{name=‘王五22222222222’, age=235}
Student{name=‘王五3333’, age=252}
Student{name=‘王五7’, age=255}
Student{name=‘王五22226’, age=285}
Student{name=‘王五5’, age=288}
Student{name=‘王五2222222224’, age=2665}
案例二:
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;
}
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 "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student s) {
//比较姓名的长度
int num = this.name.length() - s.name.length();
//姓名长度一样后,还得比较姓名的内容
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
//姓名长度一样,姓名内容一样,还得比较年龄
int num3 = num2 == 0 ? this.age - s.age : num2;
return -num3;
}
}
import java.util.HashSet;
import java.util.TreeSet;
public class MyTest {
public static void main(String[] args) {
//按照学生的年龄大小来排序
Student s1 = new Student("王五", 21);
Student s222222 = new Student("李四", 21);
Student s11 = new Student("王五", 22);
Student s123 = new Student("王五3333333333", 21);
Student s2 = new Student("王五", 22);
Student s3 = new Student("王五111", 25);
Student s4 = new Student("王五3333", 252);
Student s5 = new Student("王五22222222222", 235);
Student s6 = new Student("王五3", 25);
Student s7 = new Student("王五2222222224", 2665);
Student s8 = new Student("王五5", 288);
Student s9 = new Student("王五22226", 285);
Student s10 = new Student("王五7", 255);
//使用的是自然排序:
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(s1);
treeSet.add(s11);
treeSet.add(s2);
treeSet.add(s3);
treeSet.add(s4);
treeSet.add(s5);
treeSet.add(s6);
treeSet.add(s7);
treeSet.add(s8);
treeSet.add(s9);
treeSet.add(s10);
treeSet.add(s123);
treeSet.add(s222222);
// treeSet.add(null); 不允许存null值
//如果我们使用的是自然排序:那么对元素是有要求的,要求元素必须实现一个Comparable接口重写里面的comPareTo方法,根据此方法的返回值的正负0 来决定元素在二叉树的位置
// System.out.println(treeSet);
for (Student student : treeSet) {
System.out.println(student);
//Student {
// name = '王五', age = 21
//}
//Student {
// name = '王五', age = 21
//}
//Student {
// name = '王五', age = 22
//}
//Student {
// name = '王五111', age = 25
//}
//Student {
// name = '王五3333', age = 252
//}
//Student {
// name = '王五2', age = 235
//}
//Student {
// name = '王五3', age = 25
//}
//Student {
// name = '王五4', age = 2665
//}
//Student {
// name = '王五5', age = 288
//}
//Student {
// name = '王五6', age = 285
//}
//Student {
// name = '王五7', age = 255
//}
}
}
}
结果:
Student{name=‘王五22222222222’, age=235}
Student{name=‘王五3333333333’, age=21}
Student{name=‘王五2222222224’, age=2665}
Student{name=‘王五22226’, age=285}
Student{name=‘王五3333’, age=252}
Student{name=‘王五111’, age=25}
Student{name=‘王五7’, age=255}
Student{name=‘王五5’, age=288}
Student{name=‘王五3’, age=25}
Student{name=‘王五’, age=22}
Student{name=‘王五’, age=21}
Student{name=‘李四’, age=21}
TreeSet比较器排序的原理及代码实现
A:案例演示: TreeSet保证元素唯一和比较器排序的原理及代码实现
在创建TreeSet对象的时候,传递一个比较器对象
B: 按照年龄进行排序
案例一:
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.util.Comparator;
public class MyComparator implements 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;
}
}
import java.util.TreeSet;
public class MyTest2 {
public static void main(String[] args) {
//TreeSet:可以使用比较器排序,你采用有参构造,给他传入一个比较器
//构造方法摘要
//TreeSet()
//构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。
//TreeSet(Comparator < ? super E > comparator)
//构造一个新的空 TreeSet,它根据指定比较器进行排序。
//接口 Comparator<T >
//int compare (T o1, T o2)
//比较用来排序的两个参数。
MyComparator myComparator = new MyComparator();
TreeSet<Student> treeSet = new TreeSet<>(myComparator);
treeSet.add(new Student("王五", 21));
treeSet.add(new Student("王五1", 212));
treeSet.add(new Student("王五2", 241));
treeSet.add(new Student("王五3", 2771));
treeSet.add(new Student("王五4", 251));
treeSet.add(new Student("王五5", 2661));
treeSet.add(new Student("王五6", 2661));
treeSet.add(new Student("王五7", 217));
for (Student student : treeSet) {
System.out.println(student);
}
}
}
结果:
Student{name=‘王五’, age=21}
Student{name=‘王五1’, age=212}
Student{name=‘王五7’, age=217}
Student{name=‘王五2’, age=241}
Student{name=‘王五4’, age=251}
Student{name=‘王五5’, age=2661}
Student{name=‘王五6’, age=2661}
Student{name=‘王五3’, age=2771}
案例二:
import java.util.Comparator;
import java.util.TreeSet;
public class MyTest3 {
public static void main(String[] args) {
//TreeSet:可以使用比较器排序,你采用有参构造,给他传入一个比较器
//构造方法摘要
//TreeSet()
//构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。
//TreeSet(Comparator < ? super E > comparator)
//构造一个新的空 TreeSet,它根据指定比较器进行排序。
//接口 Comparator<T >
//int compare (T o1, T o2)
//比较用来排序的两个参数。
Comparator comparator = 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;
}
};
TreeSet<Student> treeSet = new TreeSet<>(comparator);
treeSet.add(new Student("王五", 21));
treeSet.add(new Student("王五1111", 212));
treeSet.add(new Student("王五21111", 241));
treeSet.add(new Student("王五3111", 2771));
treeSet.add(new Student("王五4111", 251));
treeSet.add(new Student("王五5111", 2661));
treeSet.add(new Student("王五611111", 2661));
treeSet.add(new Student("王五7", 21733));
treeSet.add(new Student("王五7", 21733));
treeSet.add(new Student("王五7", 21337));
treeSet.add(new Student("王五7", 217));
treeSet.add(new Student("王五7", 217));
for (Student student : treeSet) {
System.out.println(student);
}
}
}
结果:
Student{name=‘王五’, age=21}
Student{name=‘王五7’, age=217}
Student{name=‘王五7’, age=21337}
Student{name=‘王五7’, age=21733}
Student{name=‘王五1111’, age=212}
Student{name=‘王五3111’, age=2771}
Student{name=‘王五4111’, age=251}
Student{name=‘王五5111’, age=2661}
Student{name=‘王五21111’, age=241}
Student{name=‘王五611111’, age=2661}
案例三:
import java.util.ArrayList;
import java.util.Comparator;
public class MyTest {
public static void main(String[] args) {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(21000000);
integers.add(2210);
integers.add(2130);
integers.add(2150);
integers.add(2150);
integers.add(21770);
integers.add(21550);
integers.sort(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a-b;
}
});
System.out.println(integers);
}
}
结果:
[2130, 2150, 2150, 2210, 21550, 21770, 21000000]
案例三:
import java.util.Arrays;
import java.util.Comparator;
public class MyTest2 {
public static void main(String[] args) {
Integer[] arr = {2, 4, 0, 1, 40, 24};
// Arrays.sort(arr);
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return -(a - b);
}
});
System.out.println(Arrays.toString(arr));
}
}
结果:
[40, 24, 4, 2, 1, 0]
产生10个1-20之间的随机数要求随机数不能重复
A:案例演示
需求:编写一个程序,获取10个1至20的随机数,要求随机数不能重复。
并把最终的随机数输出到控制台。
选HashSet 可以不重复
选TreeSet 不重复还可以排序
分析:
a: 定义一个HashSet集合
b: 产生随机数,把随机数添加到集合中
c: 判断集合的长度,使用while循环实现
案例:
//A:
//案例演示
//需求:编写一个程序,获取10个1至20的随机数,要求随机数不能重复。
import java.util.LinkedHashSet;
import java.util.Random;
public class MyTest3 {
public static void main(String[] args) {
//A:
//案例演示
//需求:编写一个程序,获取10个1至20的随机数,要求随机数不能重复。
Random random = new Random();
//int num = random.nextInt(20) + 1;
//System.out.println(num);
LinkedHashSet<Integer> set = new LinkedHashSet<>();
while (set.size()<10){
int num = random.nextInt(20) + 1;
set.add(num);
}
System.out.println(set);
}
}
键盘录入学生信息按照总分排序后输出在控制台
A:案例演示: 需求:键盘录入3个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台。
/**
* 步骤:
* a: 自定义一个学生类
* b: 创建一个TreeSet集合对象(使用比较器进行排序)
* c: 键盘录入学生的数据,然后把学生的数据封装成一个学生对象,把学生对象添加到集合中
* d: 遍历集合
*/
案例:
public class Student {
private String name;
private int chineseScore;
private int mathScore;
private int englishScore;
public Student() {
}
public Student(String name, int chineseScore, int mathScore, int englishScore) {
this.name = name;
this.chineseScore = chineseScore;
this.mathScore = mathScore;
this.englishScore = englishScore;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getChineseScore() {
return chineseScore;
}
public void setChineseScore(int chineseScore) {
this.chineseScore = chineseScore;
}
public int getMathScore() {
return mathScore;
}
public void setMathScore(int mathScore) {
this.mathScore = mathScore;
}
public int getEnglishScore() {
return englishScore;
}
public void setEnglishScore(int englishScore) {
this.englishScore = englishScore;
}
//获取总分的方法
public int getTotalScore() {
return this.chineseScore + mathScore + englishScore;
}
}
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;
public class MyTest2 {
public static void main(String[] args) {
//A:
//案例演示:
//需求:键盘录入3个学生信息(姓名, 语文成绩, 数学成绩, 英语成绩), 按照总分从高到低输出到控制台。
TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//按照总分高低来进行排序
int num = s1.getTotalScore() - s2.getTotalScore();
//总分一样,还得比较一下名字
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
return -num2;
}
});
for (int i = 1; i <= 3; i++) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入第" + i + "个学生的姓名");
String name = sc.nextLine();
Student student = new Student();
student.setName(name);
System.out.println("请输入" + name + "的语文成绩");
int yw = sc.nextInt();
student.setChineseScore(yw);
System.out.println("请输入" + name + "的数学成绩");
int sx = sc.nextInt();
student.setMathScore(sx);
System.out.println("请输入" + name + "的英语成绩");
int yy = sc.nextInt();
student.setMathScore(yy);
//将学生存到容器中
set.add(student);
}
//遍历集合展示
System.out.println("序号 姓名 语文成绩 数学成绩 英语成绩 总分");
int index = 1;
for (Student student : set) {
System.out.println(index + " " + student.getName() + " " + student.getChineseScore() + " " + student.getMathScore() + " " + student.getEnglishScore() + " " + student.getTotalScore());
index++;
}
}
}
set集合总结
//Set :元素唯一
// HashSet 底层数据结构是哈希表(数组+链表JDK1.7 JDK 数组+链表+二叉树) 元素无序(存取顺序不一致) 元素唯一
//唯一性要靠元素重写hashCode方法和equals方法来保证的
//重写hashCode是为了确定该元素在哈希表中的位置,我们合理重写hashCode可以减少碰撞
//重写equals是为了比较内容
// LinkedHashSet 底层数据结构是链表和哈希表 ,元素有序且唯一,链表保证了有序,哈希表保证了唯一
//TreeSet 底层数据结构是二叉树 他的特点能够对元素进行排序
//排序方式:自然排序和比较器排序
//如果用的空的构造,那么就使用自然排序,使用自然排序,对元素有要求,要求元素实现 Comparable接口重写compareTo方法
//根据此方法返回值的正负 0 来决定元素的排列位置
//使用有参构造,用的就是比较器,需要传入一个比较器 Comparator 重写里面的 compare 这个比较方法,根据此方法返回值的正负 0 来决定元素的排列位置 Comparator比较器,其他一些类在调用sort()方法时也可以用