第8天_面向對象(List、Set、數據結構、Collections)
一.數據結構
1.什麼是數據結構
容器中存放組織數據的一種結構
2.常見的4+1中數據結構
堆棧結構
可以看作只有一端開口的容器,先進後出(FILO)
隊列結構
可以看成兩端開口的容器。一端進,一端出,先進先出(FIFO)
數組結構
在內存中是一塊連續的區域,查詢快(通過索引),增刪慢(長度固定)。(垃圾回收機制)
鏈表結構
在內存中可以分散,鏈表中的元素我們一般成爲節點,一般有兩個屬性,數據域和指針域
查詢慢,增刪快
紅黑樹結構
查詢速度非常恐怖O(log(n))
增刪速度包括創建時都是非常慢的
哈希表結構底層就是數組和鏈表,jdk8之後加入紅黑樹優化。
二.List接口
1.List接口的特點
a.有序的collection(也成爲序列)。
b.有索引
c.元素可重複
API的描述:
有序的 collection(也稱爲序列)。此接口的用戶可以對列表中每個元素的插入位置進行精確地控制。用戶可以根據元素的整數索引(在列表中的位置)訪問元素,並搜索列表中的元素。
2.List接口中常用的方法以及常用實現類
a.擁有Collection接口中的方法和迭代器
b.還有四個和索引相關的增刪改查方法
public void add(int index, E e):插入元素
public E remove(int index):根據索引刪除元素
public E set(int index, E e):修改指定索引的元素
public E get(int index):根據索引獲取元素
c.List接口的實現類
ArrayList
LinkedList
Vector
3.ArrayList的數據結構以及使用
ArrayList底層是數組結構,特點是查詢快,增刪慢!!!
特有方法:無
4.LinkedList的數據結構以及使用
LinkedList底層是鏈表結構,特點是查詢慢,增刪快!!!
特有方法(8個):8個和首尾操作相關的方法
public void addFirst(E e):添加首
public void addLast(E e):添加尾
public E removeFirst():刪除首
public E removeLast():刪除尾
public E getFirst():返回首
public E getLast():返回尾 public E pop():刪除首,就是跟removeFirst一樣的
public void push(E e):添加首,就是跟addFirst一樣的
addFirst和removeFirst是1.2就有的,java是1.5開始火的,這兩個方法是jdk1.6之後添加的,商業需要,爲了吸引更多的開發者(別的語言中增添方法名就是push和pop)
public class TestLinkedList {
public static void main(String[] args) {
//1.創建一個LinkedList
LinkedList<String> list = new LinkedList<String>();
//2.添加首尾
list.addLast("劉巖");
list.addFirst("賈乃亮");
list.addLast("蔡徐坤");
list.addFirst("馬蓉");
list.addLast("王寶強");
list.addFirst("宋吉吉");
list.addLast("李小璐");
list.addFirst("PGOne");
//3.打印
//"PGOne" "宋吉吉" "馬蓉" "賈乃亮" "劉巖" "蔡徐坤" 王寶強" "李小璐"
System.out.println(list);
//3.刪除首尾
String first = list.removeFirst();
System.out.println(first);
System.out.println(list);
String last = list.removeLast();
System.out.println(last);
System.out.println(list);
//[宋吉吉, 馬蓉, 賈乃亮, 劉巖, 蔡徐坤, 王寶強]
//4.獲取首尾
String first1 = list.getFirst();
System.out.println(first1);
System.out.println(list);
String last1 = list.getLast();
System.out.println(last1);
System.out.println(list);
//[宋吉吉, 馬蓉, 賈乃亮, 劉巖, 蔡徐坤, 王寶強]
//5.push和pop
list.push("666");
System.out.println(list);
String pop = list.pop();
System.out.println(pop);
System.out.println(list);
}
}
三.Set接口
1.Set接口的特點
a.無序的(是指存的和取的順序是不一定一致的,LinkedHashSet除外,它是有序的)
b.無索引
c.元素唯一
2.Set接口的常用方法以及常用子類
a.擁有Collection接口中的方法和迭代器
b.特有方法:無
c.Set接口常見的實現類
HashSet(無序)
LinkedHashSet(有序)
TreeSet
3.HashSet的數據結構以及使用
HashSet底層採用哈希表結構
特有方法:無
public class TestHashSet {
public static void main(String[] args) {
//1.創建一個HashSet
HashSet<String> set = new HashSet<String>();
//2.添加
set.add("jack");
set.add("jack");
set.add("jack");
set.add("rose");
set.add("rose");
set.add("lilei");
set.add("hanmeimei");
set.add("hanmeimei");
set.add("lucy");
set.add("lucy");
set.add("lucy");
System.out.println(set);
//[lilei, hanmeimei, rose, lucy, jack]
}
}
4.哈希表結構的介紹[擴展]
哈希表結構 = 數組(默認長度16) + 鏈表 + 紅黑樹(jdk1.8)
i.對象的哈希值(對象的“數字指紋”)
我們怎麼獲取到對象的哈希值?
只要調用對象的hashCode方法即可獲取到對象的哈希值
Java中的地址值是假的!而是哈希值轉成了16進制而已
Java中有沒有真正的地址值?
有!!!對象名中保存就是真正的地址值
但是我們打印不出來,因爲我們打印對象名的時候,會默認調用toString方法,屏蔽了真正的地址值,是一 種內存保護機制,因此Java的安全性很高
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}//返回值爲包名.類名@hashCode的十六進制值
不同對象的Hash值可能一樣的
"abc"和"acD"都是96354(hashCode方法在String類重寫了)
*************結論:哈希表結構如何保證元素的唯一性??***************
哈希表會比較新舊元素的哈希值,以及調用equals方法,
只有哈希值一致的情況下,並且equals返回true,才判定元素重複
*******************************************************************
注意:桶的長度爲8,當桶中的元素超過8時,結構自動變成紅黑樹
5.LinkedHashSet的數據結構以及使用
LinkedHashSet底層採用鏈式哈希表
特有方法:無
public class TestLinkedHashSet {
public static void main(String[] args) {
//1.創建一個HashSet
LinkedHashSet<String> set = new LinkedHashSet<String>();
//2.添加
set.add("lucy");
set.add("hanmeimei");
set.add("rose");
set.add("rose");
set.add("rose");
set.add("lilei");
set.add("jack");
System.out.println(set);
//[lucy, hanmeimei, rose, lilei, jack]
}
}
練習:使用哈希表結構保存自定義類型的元素******************
******************************************************************************
使用哈希表結構保存自定義類型時,
爲了保證元素是唯一,需要重寫自定義類型中的hashCode和equals方法(工具自動生成)
******************************************************************************
public class Cat {
int age;
String name;
public Cat() {
}
public Cat(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Cat{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
//爲了保證元素的唯一性,自定義類型必須重寫hashCode和equals方法
//alt+insert
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Cat cat = (Cat) o;
return age == cat.age &&
Objects.equals(name, cat.name);
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
}
//練習:使用哈希表結構保存自定義類型的元素*********************
public class HashCodeTestDemo {
public static void main(String[] args) {
//1.LinkedHashSet
LinkedHashSet<Cat> cats = new LinkedHashSet<Cat>();
//2.保存貓
cats.add(new Cat(1, "小貓咪"));
cats.add(new Cat(2, "中貓咪"));
cats.add(new Cat(3, "大貓咪"));
cats.add(new Cat(3, "大貓咪"));
cats.add(new Cat(4, "老貓咪"));
cats.add(new Cat(5, "死貓咪"));
//3.打印
System.out.println(cats);
}
}
6.可變參數
可變參數是指參數的個數可以變化
格式:
數據類型... 變量名
本質:
實際上可變參數就是數組(語法糖)
注意:
a.一個方法最多只能有一個可變參數
b.如果既有可變參數,也有正常參數,正常參數要寫在可變參數的前面
public class TestDemo {
public static void main(String[] args) {
//調用方法
System.out.println(getSum());
System.out.println(getSum(1));
System.out.println(getSum(1, 2));
System.out.println(getSum(1, 2, 3, 4, 5, 6, 7, 8, 9,10));
}
//使用可變參數
public static int getSum(int... a) {
//數組求和
int sum = 0;
for (int i : a) {
sum+=i;
}
return sum;
}
}
四.Collections
1.Collections的介紹
Collections是一個工具類(方法都是靜態的)
2.常用功能方法
public static void shuffle(List<?> list):打亂集合順序
public static void sort(List<?> list):升序排列集合
public class CollectionsDemo01 {
public static void main(String[] args) {
//1.sort方法
ArrayList<Integer> nums = new ArrayList<Integer>();
//2.數據
nums.add(80);
nums.add(20);
nums.add(70);
nums.add(40);
nums.add(10);
nums.add(50);
nums.add(100);
nums.add(60);
nums.add(30);
nums.add(90);
//3.打印
System.out.println(nums);
//4.排序
Collections.sort(nums);
//5.打印
System.out.println(nums);
}
}
關於sort方法的排序規則:
如果元素是數值類型,按照大小升序
如果元素是字符類型,按照ASCII碼值升序
如果元素是字符串類型,首先按照首字母的ASCII碼值升序,首字母一樣按照次字母ASCII碼值升序,依次類推
3.擴展1:Comparator<T>比較器接口******************
public class CollectionsDemo02 {
public static void main(String[] args) {
//1.sort方法
ArrayList<Integer> nums = new ArrayList<Integer>();
//2.數據
nums.add(80);
nums.add(20);
nums.add(70);
nums.add(40);
nums.add(10);
nums.add(50);
nums.add(100);
nums.add(60);
nums.add(30);
nums.add(90);
//4.排序
Collections.sort(nums,new Comparator<Integer>(){
//此方法稱爲比較方法
//返回值表示
//正數 表示前者大於後者
//0 表示前者等於後者
//負數 表示前者小於後者
@Override
public int compare(Integer o1, Integer o2) {
//升序 前-後
// return o1-o2;
return o2-o1;
}
});
//5.打印
System.out.println(nums);
}
}
4.排序練習(代碼實現)
/**
* 使用集合保存學生對象,對集合進行排序
*/
public class CollectionsDemo03 {
public static void main(String[] args) {
//1.創建一個ArrayList
ArrayList<Student> ss = new ArrayList<Student>();
//2.添加學生
ss.add(new Student(20,"haneimei",50));
ss.add(new Student(10,"jack",90));
ss.add(new Student(8,"ady",95));
ss.add(new Student(9,"tonny",100));
ss.add(new Student(25,"yy",30));
//3.遍歷
for (Student s : ss) {
System.out.println(s);
}
System.out.println("===========================");
Collections.sort(ss, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//口訣:升序 前減後
//a.按照年齡降序
// return o2.age-o1.age;
//b.按照分數升序
// return o1.score-o2.score;
//c.按照名字的長度降序
// return o2.name.length()-o1.name.length();
//d.按照姓名的第二個字母降序
return o2.name.charAt(1)-o1.name.charAt(1);
}
});
for (Student s : ss) {
System.out.println(s);
}
}
}
總結:
-[] 能夠說出List集合特點
有序,有索引,可重複
-[] 能夠說出常見的數據結構
-[] 能夠說出常見的數據結構
-[] 能夠說出數組結構特點
-[] 能夠說出棧結構特點
-[] 能夠說出隊列結構特點
-[] 能夠說出單向鏈表結構特點
-[] 能夠說出Set集合的特點
無序,無索引,唯一
-[] 能夠說出哈希表的特點
哈希表中的元素是唯一的
哈希表通過哈希值和equals共同保證元素的唯一性
-[] 使用HashSet/LinkedHashSet集合存儲自定義元素
自定義類型需要重寫hashCode和equals
-[] 能夠使用集合工具類的常用方法
public static void shuffle(List<?> list):打亂集合順序
public staitc void sort(List<?> list):升序排序集合 -[] 能夠使用Comparator比較器進行排序
Collections.sort(集合<E>, new Comparator<E>{
public int compare(E e1, E e2){
升序 前減後
}
});