集合框架能適應數據變化的需求,長度可以改變,集合只能是引用類型,常用的集合類:
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比較器對象