【JAVA學習筆記】16 ArrayList集合 、HashCode和equals判斷對象相同、linklist、list接口

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
    [魚辣子, 變蛋, 麻辣小龍蝦, 湖南紅燒肉, 麻辣小龍蝦]
    [魚辣子, 變蛋, 麻辣小龍蝦, 湖南紅燒肉, 麻辣小龍蝦, 沙蟹汁, 長沙臭豆腐, 活蛆奶酪]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章