2018.4.18
---| Collection 集合的總接口
------| List 接口 有序 可重複
---------| ArrayList [重點]
ArrayList 是底層維護了一個Object類型的數組,這樣的話這個ArrayList既可以保持任意類型
的數據
特徵:
當調用無參構造方法ArrayList,這裏創建的底層Object類型的數組元素個數默認爲10
DEFAULT-CAPACITY 10
查詢快(有了下標基本確定找到元素),增刪慢。
開發中使用ArrayList比較多的情景:
圖書館,人員管理
------| Set 接口 無序 不可重複
ArrayList特有方法:
//確定容量
ensureCapacity(int minCapacity); 不常用 返回值是boolean
判斷當前ArrayList裏面保存元素內容Object數組,元素個數是否大於minCapacity
//截斷底層維護的Object類型的數組,讓數組的容量變成當前ArrayList的size值【有效元素個數】
trimToSize(); 不太常用 eg:擴容時右移一位10W->15W,只增加一個元素。
Size();//拿出有效元素個數
【查詢快,增刪慢的原理】
查詢快:
ArrayList底層維護的是一個Object類型的數組,可以完全使用數組的下標機制來訪問數據,
這種訪問形式是非常快的。
增加慢:
是因爲在添加數據的時候,有可能導致ArrayList底層的Object的元素個數不會用,那麼會調用數組
的擴容方法grow,而擴容方法是創建了一個新的數組,數組的元素個數大約是老數組的1.5倍,這裏會
利用一些方法,把老數組裏面的元素完完整整的拷貝到新數組,這個拷貝過程很佔時間和內存。
刪除慢:
因爲刪除某一個元素,會導致數組中該元素之後的數據,做一個整體的左移,這裏也是一個數組的拷貝
過程,整個過程非常
面試題:
1.如果調用了ArrayList的無參構造方法,那麼請問底層維護的Object數組默認的元素個數是多少?
如果是調用這個方法呢 new ArrayList(8);
答:默認元素個數爲10,另一個爲8.
2.ArrayList是一個可以自增長的空間,請問,增長的原理是什麼?增長的長度是多少?
ArrayList底層維護的是一個Object數組,默認元素爲10,如果添加元素時,當前需求的元素空間
超出了Object數組的元素個數,會調用底層的grow,進行數組元素的擴容和拷貝,擴容量是大約1.5倍
擴容是:
新元素個數 = 老元素個數 + (老元素個數 >> 1);
newCapacity = oldCapacity + (oldCapacity >> 1);
public class Demo1 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
}
}
HashCode 和 equals 判斷對象是否相同。
contains, containsAll, equals方法
發現:
java語言中,默認判斷兩個對象是否相同的方式是,判斷這兩個對象的首地址是否相同,
在這裏stu1和new Student(1,"梅西");是兩個完全不同的對象,
問題:
但是Stu1和new Student(1,"梅西")裏面保存的數據是一樣的,也是符合業務邏輯
或者說生活邏輯的判斷。
讓判斷符合語法的前提下也符合生活邏輯。
重寫:
equals和hashCode方法。
默認情況下:
hashCode方法在系統默認的情況下,是當前類對象在內存地址的十進制數
equals方法是兩個對象相互比較的法則。
class Student {
private int id;
private String name;
public Student() {}
public Student(int id,String name) {
this.id = id;
this.name = name;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
//描述當前類對象,當通過打印方法,打印該類對象的時候會自動調用。
public String toString() {
return "[ID:"+id+"name:"+name+"]";
}
/**
* equals和hashCode重寫時一起重寫。
*/
@Override
public boolean equals(Object obj) {
//這裏equals方法是Student類重寫的方法,當集合調用contains,containsAll和equals方法的時候
//都會來調用Student類裏面的equals方法,進行比較,比較的的對象是Student對象。
System.out.println("equals方法");
//原本的比較方式是不符合生活邏輯的,只是判斷兩個對象的地址是否相同,不判斷裏面的內容是否一致
//期望,判斷的是對象裏面的數據是否一致。
//1.強制類型轉換。
Student stu = (Student) obj;
System.out.println(this.name+"和"+stu.name+"進行比較");
//this.name.equals(stu.name);這裏的equals方法是調用的String類型的equals方法,和重寫的equals沒關係。
return this.id == stu.id && this.name.equals(stu.name);
}
@Override
public int hashCode() {
System.out.println("hashCode方法");
//重寫了equals方法,同時也要重寫hashCode方法。
//hashCode值要確定【唯一性】,只要滿足你自己的邏輯就可以了。
//這裏認爲Id是唯一的。
return this.id;
}
}
public class Demo1 {
public static void main(String[] args) {
Collection c = new ArrayList();
Student stu1 = new Student(1,"梅西");
Student stu2 = new Student(2,"C羅");
Student stu3 = new Student(3,"內馬爾");
c.add(stu1);
c.add(stu2);
c.add(stu3);
boolean ret = c.contains(new Student(1,"伊布"));
System.out.println(c);
System.out.println("ret:"+ret);
}
}
結果:
equals方法
伊布和梅西進行比較
equals方法
伊布和C羅進行比較
equals方法
伊布和內馬爾進行比較
[[ID:1name:梅西], [ID:2name:C羅], [ID:3name:內馬爾]]
ret:false
iterator迭代器
iterator();迭代器
循環,作用是循環遍歷整個集合,
public class Demo2 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("棧橋");
c.add("八大關");
c.add("情人壩");
c.add("中山公園");
//第一種遍歷方式:將集合轉換成數組進行遍歷
/*Object[] array = c.toArray();
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
*/
/*
LOW
會導致內存資源的浪費,會拷貝一份完整的集合數據,如果集合數據過大,甚至於會超過內存的最大致
Iterator 迭代器的方法
boolean hasNext();判斷當前迭代器是否有下一個元素
Object next();獲取當前迭代器指向的元素,並且獲取之後,指向下一個元素。 object爲迭代器對象。
void remove();刪除當前迭代器通過的next獲取到的對象。
[要求]:
在通過迭代器調用remove方法的時候,之前必須調用過next()方法。
否則報異常: java.lang.IllegalStateException
*/
Iterator it = c.iterator();//返回當前集合的一個迭代器
/*
System.out.println("當前元素中有沒有下一個元素:"+it.hasNext());
System.out.println("當前迭代器指向的元素:"+it.next());
System.out.println("當前迭代器指向的元素:"+it.next());
System.out.println("調用了刪除的方法");
it.remove();
*/
//利用迭代器,藉助於hasNext和next方法,完成對整個集合的遍歷。
while(it.hasNext()) {
System.out.println("迭代器操作:"+it.next());
//it.remove();這裏可以調用remove方法,用來清空集合。
//it.next();(獲取當前元素,並指向下一個元素)
}
System.out.println(c);
}
}
結果:
迭代器操作:棧橋
迭代器操作:八大關
迭代器操作:情人壩
迭代器操作:中山公園
[棧橋, 八大關, 情人壩, 中山公園]
LinkedList
LinkedList 底層維護的是一個鏈表。
特徵:
增刪快,查找慢。
LinkedList特有方法:
addFirst(Object o);
addLast(Object o)
getFirst();
getLast();
removeFist();
removeLast();
*/
public class Demo1 {
public static void main(String[] args) {
LinkedList list = new LinkedList();
}
}
List接口
List接口中【特有的方法】:
添加:
add(index,Object o);在指定位置上放入元素 addAll(int index, Collection c);在指定位置上添加一個集合
獲取:
object get(int index);獲取指定下標的元素 obejct---list int indexOf(Object o);獲取某個元素的下表位置 int lastIndex(Object o);找出指定元素最後一次出現在集合中的位置。(在元素相同時) List sublist(int fromIndex,int toIndex);獲取一個子List集合
修改:
set(int index, Object o);設置指定下標上的元素 get(int in)
迭代:
ListItrator(); public class Demo1 { public static void main(String[] args) { List list = new ArrayList(); list.add("魚辣子"); list.add("沙蟹汁"); list.add("鯡魚罐頭"); list.add("活蛆奶酪"); System.out.println(list); list.add(1,"變蛋"); System.out.println(list); List list2 = new ArrayList(); list2.add("麻辣小龍蝦"); list2.add("湖南紅燒肉"); list2.add("麻辣小龍蝦"); list.addAll(2,list2); System.out.println(list); System.out.println(list.get(5)); System.out.println(list.indexOf("沙蟹汁")); System.out.println(list.lastIndexOf("麻辣小龍蝦")); //subList(int fromIndex,int toIndex);
在JAVA中所有用到區間範圍的操作 都是要頭不要尾。
List subList = list.subList(0, 5);
System.out.println(subList);
list.set(list.indexOf("鯡魚罐頭"),"長沙臭豆腐");
System.out.println(list);
結果:
[魚辣子, 沙蟹汁, 鯡魚罐頭, 活蛆奶酪]
[魚辣子, 變蛋, 沙蟹汁, 鯡魚罐頭, 活蛆奶酪]
[魚辣子, 變蛋, 麻辣小龍蝦, 湖南紅燒肉, 麻辣小龍蝦, 沙蟹汁, 鯡魚罐頭, 活蛆奶酪]
沙蟹汁
5
4
[魚辣子, 變蛋, 麻辣小龍蝦, 湖南紅燒肉, 麻辣小龍蝦]
[魚辣子, 變蛋, 麻辣小龍蝦, 湖南紅燒肉, 麻辣小龍蝦, 沙蟹汁, 長沙臭豆腐, 活蛆奶酪]