JAVA 數組與集合

目錄

 

數組

一維數組

 多維數組

 數組的enhance for loop

集合Collection

List

ArrayList

LinkedList

Set

HashSet

TreeSet


數組

數組也是一個對象,所以它被存放在堆(heap)中。

一維數組

數組的聲明

int[] array;

這只是聲明瞭一個數組的引用,只是在堆中建立起了一個可以用來指向一個整數數組的引用,並沒有真正分配數組的內存。

真正創建對象數組要用new

數組的創建

array = new new int[4];

或直接   int[] array = {1,2,3,4,5}; 

數組的初始化

1. 基本數據類型數組

語句 int[] ints = new int[4]; 

執行完後,因爲int類型數組初始化的缺省值爲0,因此內存中現在就已經有了4個int(即0)

語句  char[] chars = new char[4]; 

char類型數組初始化的元素缺省值爲‘\0’,是一個不可見字符。現在內存裏面已經有4個char(即‘\0’)

語句   bool[] bools new bool[4]; 

bool類型數組的元素缺省值爲false。現在內存裏面已經有4個bool值(即false)

2. 對象類型數組

語句  String[] str = new String[4];

因爲在string這種對象類型數組中存放的是一個對象的引用。所以在該語句執行完後,內存中一個String都沒有。這一點與基本數據類型數組不同。

 多維數組

多維數組在java內存中的存放

多維數組在C/C++的內存中,都是以整行優先連續排列的(內存都是一維的)。

而在Java中,多維數組在內存中的存放如上圖所示。內存不是連續的,每一維都指出來了。相當於是一維數組的一維數組。

多維數組的創建與聲明

int[][] ints = new int[4][3];

或者

int[][] ints = new int[4][];                              //jagged array 鋸齒數組

ints[0] = new int[4];

ints[1] = new int[3];

這裏的第二種聲明創建方法,就是先只創建了第一維的那個數組,然後再爲每一維創建被指出來的第二維數組。

由此可見,在Java中,每一維數組的維數可以不一樣。這種數組被稱爲jagged array(鋸齒數組)。Java只支持這一種數組,只是這種數組也可以實現類似於regular array的每一維大小相等的特殊情況。而C/C++只支持regular array。

數組的初始化

int[][] ints = {{1,2,3}, {4,5}};

 數組的enhance for loop

一維數組

for(int i : ints){

      system.out.println(ints[i]);

}

多維數組 

for(int ii : ints){                            //這一維取出的仍是一個一維數組

      for(int i : ii){                               //所以還需要用 i 遍歷這個一維數組 ii

             system.out.println(ints[i]);

      }

}

但是,數組有個很大的缺點:一旦創建大小就不能更改————解決方法:集合Collection

集合Collection

集合Collection是一個泛型接口:public interface Collection<E>,可通過E來指定數據類型。

Collection主要分爲兩大類:List,Set

數組是協變的,即:若A -> B,則List(A) -> List(B)    (A與B爲父類與子類的關係)

而集合是不變的,即不存在上述父類與子類的List 間的關係。List(A) 與 List(B) 沒有任何關係。

List

也是一個接口。有點像向量/序列:(x, y, z, ...)

每個元素都有自己的順序,即都有position。因此,x和y可以同時爲1,即(1, 1, 1, ...)是可以存在的。

ArrayList

import java.util.List;

import java.util.ArrayList;

 list的創建

List list = new ArrayList(); 

後面的括號中當然也可以填上數值,如1。但由於這裏是一個 initial capacity,爲初始容量,而List的大小可以動態更改,所以沒有必要,一般不在後面寫。

創建的時候,前面要寫List而不寫ArrayList(雖然當然也是對的)。這樣會方便很多(同時有着父類List與子類ArrayList的功能)

如上這樣寫時,也會出現警告:原因是E沒有給參數。若只希望這個List放Integer,則:

List<Integer> intList = new ArrayList<>();              //<>也可以省略 

並且如果這樣的話,若傳一個非Integer的給這個list,編譯器會在編譯階段就報錯,這是很方便與編程的。

注意,ArrayList長度動態更改的實質

ArrayList在底層實際上仍是使用數組來存取元素。只是在要超過數組capacity時,會同普通array一樣複製原有元素到一個更大的新的數組中。只是它是自動幹了這件事。

取list中的元素

list.get(2);

即獲取類似於數組中下標爲2的位的數值。

LinkedList

是用鏈表,即指針把集合中的各個元素串起來的。

ArrayList的好處:可以通過位置隨機訪問;而LInkedList需要一個指針一個指針移動着來查找。

ArrayList的缺點:插入元素時(數據結構);而LInkedList就會很簡單。

建議以後都寫爲:

Person sp = new Student();                  //向上類型轉換

而少寫爲  Student s = new Student(); 

這樣寫的好處:

若有: public f(Person p ){...},則此時也可以傳入Student類對象sp,即 f(new Student())。

若要向下類型轉換,則必須強制(可能會出錯):Student s = (Student)p;  

Set

與數學上的集合類似,既不能有重複的元素。有兩種類型的實現:HashSet 和 TreeSet。

HashSet

判斷是否有重複元素的方法(不是遍歷與每一個元素比較):

兩個不同的對象經過hash函數之後,會算出兩個散列值。不同對象的散列值可能相同(散列值有限),但散列值不同的對象一定不相同。

因此在添加元素時,若此元素算出的散列值與原有元素的都不相同,則可直接加入set;若相同,則只用將該元素與與其散列值相同的那些元素進行比較。(可以把散列值看作一個一個的桶,若桶爲空,則可直接放入;若不爲空,則與桶內已有的元素進行比較即可。)

hashCode()方法 —— 獲取hash值,應與equals()方法同時進行重寫,原因:

hash值不同的兩個對象必須(一定)是不同的,所以不應該存在兩個hashcode()結果不同的對象,經過equals()方法,反而是相同的。所以hashCode()方法應與equals()方法配套進行重寫。

在equals()方法自動生成的代碼中,有一個if語句:

public boolean equals(Person obj){

       ...

       if(getClass() != obj.getClass())

              return flase;

       ...

}

 而有時它並不是我們需要的,因爲我們有時會需要將子類對象與父類對象相比。如Person類的p和Student類的s:p.equals(s),有時是需要的。

TreeSet

TreeSet是二叉樹的實現,不允許放入null值,是自動排序的。

在放入新元素(add)的時候,會比較元素誰大誰小,才能往樹中放,小的在左,大的在右。

TreeSet也是爲了加速search的過程(add是要檢查(search)是否有重複值),時間複雜度爲對數結構。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章