集合框架能适应数据变化的需求,长度可以改变,集合只能是引用类型,常用的集合类:
Collection
|--List
|--ArrayList
|--LinkedList
|--Set
|--HashSet
|--LinkedHashSet
|--TreeSet
HashSet
在List的集合中可以存储重复的值,Set集合正好相反,不能存储相同的值。
HashSet的add()方法依赖HashMap的put()方法。
在put()方法中会依赖 hashCode()和equals()这两个方法。
所以add()在添加元素时会走的逻辑是:
先看hashCode()值是否相同
相同:继续走equals()方法
返回true:说明元素重复,就不添加
返回false:说明元素不重复,就添加到集合
不同:就直接把元素添加到集合
add()方法的底层操作第一步比较hash值的时候是相同的,那下面每新添加一个元素时,都要和目前集合中的元素进行equals()的比较,这样效率低下。另外,返回hash值一样,这些添加的元素会在哈希表的同一个位置,保存方式类似一个链表的结构。
如果类没有重写这两个方法,默认使用的Object的。
String类重写了hashCode()和equals()方法,Set集合在添加String类型的元素时,它就可以把内容相同的字符串去掉,只留下一个。
public class Student {
private String name;
private int age;
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;
}
// 保证对象的hashCode()值不一样
@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 instanceof Student)) {
return false;
}
Student s = (Student) obj;
return this.name.equals(s.name) && this.age == s.age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
上面的Student类重写了equals()和hashCode()方法。
在使用Set时:
HashSet<Student> hs = new HashSet<Student>();
Student s1 = new Student("jiaobuchong", 22);
hs.add(s1);
保证不会添加进去重复的Student类。
LinkedHashSet
底层数据结构由哈希表和链表组成。
哈希表保证元素的唯一, 链表保证元素有序, 存储和取出一致.
TreeSet
元素会排好序,并唯一。
TreeSet的add()方法依赖于TreeMap()的put()方法。底层数据结构是红黑树(是一个自平衡的二叉树)。根据比较的返回值是否是0来决定元素的唯一性。
- 排序方法
- 自然排序(按自然数从小到大的排序)
- 自定义排序
自定义排序
- 实现Comparable接口
public class Student implements Comparable<Student>{
private String name;
private int age;
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 int compareTo(Student s) {
// return 0; 只加入了一个元素,程序认为加入的都是同一个元素,所以只add了一个元素
// return 1; 表示后面添加的元素比前面的大
// return -1; 表示后面添加的元素比前面的小
// 按照年龄排序,主要条件
int num = this.age - s.age;
// 次要条件
// 年龄相同的时候,还得去看姓名是否也相同
// 如果年龄和姓名都相同,才是同一个元素
int num1 = (num == 0) ? this.name.compareTo(s.name) : num;
return num1;
}
}
//--------------------------------------------------
TreeSet<Student> ts = new TreeSet<>();
Student s1 = new Student("jiaobuchong", 22);
Student s2 = new Student("jack", 23);
ts.add(s1);
ts.add(s2);
ts中的Student元素按照年龄排序,通过compareTo()方法比较返回值是0的元素不会添加到TreeSet中。
-
自定义比较器 Comparator
// 匿名内部内灵活性较高 TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() { //new 后面是类名或接口名,使用一次,这种实现较好 @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; } }); // 使用lambda表达式 TreeSet<Student2> ts = new TreeSet<>((o1, o2) -> { int num = o1.getName().length() - o2.getName().length(); // 姓名的长度相同,不代表姓名的内容相同 int num2 = num == 0 ? o1.getName().compareTo(o2.getName()) : num; // 姓名的长度和内容相同,不代表年龄相同,所以还得继续判断年龄 int num3 = num2 == 0 ? o1.getAge() - o2.getAge() : num2; return num3; });
使用操作集合的工具类Collections排序:
// list是一个保存Student对象的List,传一个比较器Comparator
// 可以使用lambda表达式
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;
}
});
Map
Map常用的类:
Map
|--HashMap
|--TreeMap
|--LinkedHashMap
Map集合的数据结构仅仅针对键有效,与值无关。
存储的是键值对形式的元素,键唯一,值可重复。
HashMap
底层数据结构是哈希表,线程不安全的,效率高
哈希表依赖两个方法:HashCode()和equals()方法
执行顺序和(前面叙述的Set集合是依赖于Map的):
首先判断hashCode()值是否相同
是:继续执行equals(),看其返回值
true:说明元素重复,不添加
false:就直接添加到集合
否:直接添加到集合中
// 一般做法:自动生成这两个方法即可
LinkedHashMap
- 底层数据结构是链表和哈希表组成。
- 链表保证存储有序
- 哈希表保证元素唯一性
TreeMap
底层数据结构是红黑树(是一种自平衡的二叉树)
- 如何保证元素唯一性?
- 根据比较的返回值是否是0来决定
- 如何保证元素排序?
- 两种方式
- 自然排序(元素局部比较性)
- 让元素所属的类实现Comparable接口
- 比较器排序(集合具备比较性)
* 让集合接收一个Comparator比较器对象
网友评论