Java入門——(6)集合
阿新 • • 發佈:2017-07-03
最值 二分 集合框架 except 索引 string 類名 素數 blog
關鍵詞:Collection接口、Map接口、Iterator接口、泛型、Collections工具類、Arrays工具類
一、集合概述
當數據多了需要存儲,需要容器,而數據的個數不確定,無法使用數組,這時可以使用Java中另一個容器——集合,位於java.util 。
1、集合和數組的區別?
① 數組的長度是固定的。
集合的長度是可變的。
②數組中存儲的是同一類型的元素,可以存儲基本數據類型值。
集合存儲的都是對象。而且對象的類型可以不一致。
2、什麽時候使用集合呢?
當對象多的時候,先進行存儲。
3、集合體系框架圖
二、Collection接口
Collection接口:單列集合類的根接口
1、List接口:有序的,帶索引的,通過索引就可以精確的操作集合中的元素,允許出現重復的元素。
使用List解決插入元素的問題,因為add方法追加。
List接口的特有方法,全部是圍繞索引來定義的。
List獲取元素的方式有兩種:一種是叠代,一種是遍歷+get方法。
List接口是支持對元素進行curd增刪改查動作的。
①Vector:可以增長的數組結構。同步的。效率非常低,已被ArrayList替代。
②ArrayList:是數組結構,長度是可變的(原理創建新數組+復制數組),查詢速度很快,增刪較慢,不同步的。(應用廣)。
示例:
1 public class Example01 {
2 public static void main(String[] args) {
3 ArrayList list = new ArrayList(); //創建ArrayList集合
4 list.add("stu1");
5 list.add("stu2");
6 list.add("stu3");
7 list.add("stu4");
8 System.out.println("集合的長度:"+list.size());//獲得集合中元素的個數
9 System.out.println("集合的第二個元素:"+list.get(1));//取出並打印指定位置的元素
10 }
11 }
運行結果:
集合的長度:4
集合的第二個元素:stu2
③LinktedList:是鏈接結構,增刪速度快,查詢速度慢。可用於實現堆棧,隊列。特有:圍繞頭和為展開定義的。
堆棧:先進後出First in Last Out FILO 可以理解為手槍彈夾
隊列:先進先出First in First Out FILO 可以理解為排隊買票
常用方法示例:
1 public class Example02 {
2 public static void main(String[] args) {
3 LinkedList link = new LinkedList();//創建LinkedList集合
4 link.add("stu1");
5 link.add("stu2");
6 link.add("stu3");
7 link.add("stu4");
8 System.out.println(link.toString());//取出元素並打印該集合中的元素
9 link.add(3,"Student"); //向該集合中的指定位置插入元素
10 link.addFirst("First"); //向該集合第一個位置插入元素
11 link.addLast("Last"); //向該集合第一個位置插入元素
12 System.out.println(link);
13 System.out.println(link.getFirst()); //取出該集合第一個元素
14 System.out.println(link.getLast()); //取出該集合最後一個個元素
15 link.remove(3); //移除該集合中指定位置的元素
16 link.removeFirst(); //移除該集合中第一個元素
17 link.removeLast(); //移除該集合中最後一個個元素
18 System.out.println(link);
19 }
20 }
運行結果:
[stu1, stu2, stu3, stu4]
[First, stu1, stu2, stu3, Student, stu4, Last]
First
Last
[stu1, stu2, Student, stu4]
2、Iterator接口
集合的取出方式:
①創建集合對象
Collection coll = new ArrayList();②獲取容器的叠代器對象,通過iterator方法;
Iterator it = coll.iterator();③使用具體的叠代器對象獲取集合中的元素;
while (it.hasNext()){
System.out.println(it.next());
}
實際開發建議使用以下方法(隨著叠代完成,叠代器隨之變成垃圾被清除,可以減少所占內存):
for(Iterator it = coll.iterator();it.hasNext();){
System.out.println(it.next());
}
該叠代器無法再叠代的過程中修改數組元素,否則會發生並發修改異常(ConcurrentModificationException)。
3、foreach:
其實就是增強for循環,用於遍歷Collection和數組通常只能遍歷元素,不要在遍歷的過程中做對集合元素的操作。
格式:for(元素數據類型 變量 :collection集合or數組()){執行語句}和老式for循環的區別? 註意:新for循環必須有被遍歷的目標。目標只能是Collection或者是數組。 建議:遍歷數組時,如果僅為遍歷,可以使用增強for,如果要對數組的元素進行操作,使用老式for循環可以通過角標操作。 示例:
1 public class Foreach {
2 static String [] strs = {"aaa","bbb","ccc"};
3 public static void main(String[] args) {
4 //foreach循環遍歷數組
5 for(Object obj : strs){
6 System.out.println(obj);
7 }
8 System.out.println("______________");
9 //foreach循環遍歷數組並修改(修改失敗)
10 for (String str : strs){
11 str="ddd";
12 }
13 System.out.println("foreach循環修改後的數組:"+strs[0]+","+strs[1]+","+strs[2]);
14 //for循環遍歷數組
15 for(int i = 0;i<strs.length;i++){
16 strs[i]="ddd";
17 }
18 System.out.println("普通for循環修改後的數組:"+strs[0]+","+strs[1]+","+strs[2]);
19 }
20 }
運行結果:
1 aaa
2 bbb
3 ccc
4 ______________
5 foreach循環修改後的數組:aaa,bbb,ccc
6 普通for循環修改後的數組:ddd,ddd,ddd
4、ListIterator叠代器
Iterator的子類,該列表叠代只有List接口有,而且這個叠代器可以完成在叠代過程中的增刪改查動作。
add方法示例:
1 public class AddDemo {
2 public static void main(String[] args) {
3
4 //在最前面添加
5 List<String> list1 = new LinkedList<String>(Arrays.asList(
6 new String[] { "a", "b", "c" }));
7 ListIterator<String> listIterator1 = list1.listIterator();
8 listIterator1.add("D");
9 listIterator1.add("E");
10 System.out.println(list1);//[D, E, a, b, c]
11 //在最後面添加
12 List<String> list2 = new LinkedList<String>(Arrays.asList(
13 new String[] { "a", "b", "c" }));
14 ListIterator<String> listIterator2 = list2.listIterator();
15 while (listIterator2.hasNext()) {
16 listIterator2.next();
17 }
18 listIterator2.add("D");
19 listIterator2.add("E");
20 System.out.println(list2);//[a, b, c, D, E]
21 //在每個元素的前面和後面都添加
22 List<String> list3 = new LinkedList<String>(Arrays.asList(
23 new String[] { "a", "b", "c" }));
24 ListIterator<String> listIterator3 = list3.listIterator();
25 while (listIterator3.hasNext()) {
26 listIterator3.add("前面");
27 listIterator3.next();
28 listIterator3.add("後面");
29 }
30 System.out.println(list3);//[前面, a, 後面, 前面, b, 後面, 前面, c, 後面]
31 //在指定元素的前面和後面添加
32 List<String> list4 = new LinkedList<String>(Arrays.asList(
33 new String[] { "a", "b", "c" }));
34 ListIterator<String> listIterator4 = list4.listIterator();
35 while (listIterator4.hasNext()) {
36 if (listIterator4.next().equals("a")) {//現在指向的是a的後面
37 listIterator4.previous();//先重新指向a的前面,這裏不用擔心NoSuchElementException
38 listIterator4.add("前面");//在前面添加元素,添加後還是指向的a的前面
39 listIterator4.next();//向後【再】移動一位,現在指向的是a的後面
40 listIterator4.add("後面");//在a的後面添加元素
41 }
42 }
43 System.out.println(list4);//[前面, a, 後面, b, c]
44 }
45 }
remove方法示例:
1 public class RemoveDemo {
2 public static void main(String[] args) {
3
4 // 執行next()或previous()後不能先執行了 add()方法。
5 // 因為add()方法執行以後,叠代器已經移動了,這樣所要刪除的目標元素指向不明,會報異常。
6 //標準的做法:在next之後才能remove
7 List<String> list2 = new LinkedList<String>(Arrays.asList(
8 new String[] { "b", "a", "b", "c", "b", }));
9 ListIterator<String> listIterator2 = list2.listIterator();
10 while (listIterator2.hasNext()) {
11 if (listIterator2.next().equals("b")) {listIterator2.remove();}
12 }
13 System.out.println(list2);//[a, c]
14
15 //移除指定範圍內的所有元素
16 List<String> list3 = new LinkedList<String>(Arrays.asList(
17 new String[] { "a", "開始", "b", "c", "d", "結束", "e" }));
18 ListIterator<String> listIterator3 = list3.listIterator();
19 while (listIterator3.hasNext()) {
20 if (listIterator3.next().equals("開始")) {
21 listIterator3.remove();//註釋掉這行代碼則不移除"開始"
22 while (listIterator3.hasNext()) {
23 if (!listIterator3.next().equals("結束")) {
24 listIterator3.remove();//remove之後必須再調用next方法後才能再remove
25 } else {
26 listIterator3.remove();//註釋掉這行代碼則不移除"結束"
27 break;//結束while循環
28 }
29 }
30 }
31 }
32 System.out.println(list3);//[a, e]
33 //替換指定元素
34 List<String> list5 = new LinkedList<String>(Arrays.asList(
35 new String[] { "a", "b", "c" }));
36 ListIterator<String> listIterator5 = list5.listIterator();
37 while (listIterator5.hasNext()) {
38 if (listIterator5.next().equals("b")) {
39 listIterator5.remove();
40 listIterator5.add("替換");
41 }
42 }
43 System.out.println(list5);//[a, 替換, c]
44 }
45 }
5、Set接口
不包含重復元素的集合,不保證順序。而且方法和Collection一致。Set集合取出元素的方式只有一種:叠代器。
①HashSet:哈希表結構,不同步,保證元素唯一性的方式依賴於: hashCode(),equals()方法。查詢速度快。哈希值是根據存儲位置來計算。
1 class Student{
2 private String id;
3 private String name;
4 public Student(String id,String name){
5 this.id = id;
6 this.name = name;
7 }
8 // 重寫toString方法
9 public String toString(){
10 return id+":"+name;
11 }
12 // 重寫hashCode方法
13 public int hashCode(){
14 return id.hashCode();//返回id屬性的哈希值
15 }
16 // 重寫equals方法
17 public boolean equals(Object obj){
18 if(this==obj){ //判斷是否為同一個對象
19 return true; //如果是,直接返回true
20 }
21 if (!(obj instanceof Student)){ //判斷對象是否Student類型
22 return false; //如果對象不是Student類型,返回false
23 }
24 Student stu = (Student)obj; //將對象強轉為Student類型
25 boolean b= this.id.equals(stu.id); //判斷id值是否相同
26 return b; //返回判斷結果
27 }
28 }
29 public class HashSetDemo {
30 public static void main(String[] args) {
31 HashSet set = new HashSet();
32 Student stu1= new Student("1","Jack");
33 Student stu2= new Student("2","Rose");
34 Student stu3= new Student("2","Rose");
35 set.add(stu1);
36 set.add(stu2);
37 set.add(stu3);
38 System.out.println(set);
39 }
40 }
運行結果:
[1:Jack, 2:Rose]
若不重寫hashCode()和equals()方法,則輸出結果是:
[2:Rose,1:Jack, 2:Rose]
②TreeSet:可以對Set集合中的元素進行排序。使用的是二叉樹結構。如何保證元素唯一性的?使用的是對象比較方法的結果是否為0,是0,視為相同元素不存。 元素的排序比較有兩種方式:
- 元素自身具備自然排序,其實就是實現了Comparable接口重寫compareTo方法。如果元素自身不具備自然排序,或具備的自然排序不是所需要的,這時只能用第二種方式。
- 比較器,其實就是在創建TreeSet集合時,在構造函數中指定具體的比較方式。需要定義一個類實現Comparator接口,重寫compare方法。
-
1 class Student implements Comparable{ //定義Student類實現Comparable接口 2 String name; 3 int age; 4 public Student(String name,int age){ //創建構造方法 5 this.name = name; 6 this.age = age; 7 } 8 public String toString(){ //重寫Object類toString()方法,返回描述信息 9 return name+":"+age; 10 } 11 public int compareTo(Object obj){ //重寫Comparable接口compareTo方法 12 Student s =(Student) obj; //將比較對象強轉為Student類型 13 if (this.age -s.age>0){ //定義比較方法 14 return 1; 15 } 16 if (this.age-s.age==0){ 17 return this.name.compareTo(s.name);//將比較結果返回 18 } 19 return -1; 20 } 21 } 22 public class TreeSetDemo { 23 public static void main(String[] args) { 24 TreeSet ts = new TreeSet(); 25 ts.add(new Student("Jack",19)); 26 ts.add(new Student("Rose",18)); 27 ts.add(new Student("Tom",19)); 28 ts.add(new Student("Rose",18)); 29 Iterator it = ts.iterator(); 30 while (it.hasNext()){ 31 System.out.println(it.next()); 32 } 33 } 34 }
運行結果:
Rose:18
Jack:19
Tom:19到此為止:在往集合中存儲對象時,通常該對象都需要覆蓋hashCode,equals,同時實現Comparable接口,建立對象的自然排序。通常還有一個方法也會復寫toString();
1 public class Example15 {
2 public static void main(String[] args){
3 Map map = new HashMap(); //創建Map對象
4 map.put("1","Jack"); //存儲鍵和值,鍵相同,值覆蓋
5 map.put("2","Rose");
6 map.put("3","Lucy");
7 map.put("3","Mary");
8 System.out.println("1:"+map.get("1"));//根據鍵獲取值
9 System.out.println("2:"+map.get("2"));
10 System.out.println("3:"+map.get("3"));
11 }
12 }
Map集合的兩種遍歷方式:
1 public class Example16 {
2 public static void main(String[] args){
3 //第一種先遍歷Map集合中所有的鍵,再跟據鍵獲取相應的值。
4 Map map1 = new HashMap(); //創建Map對象
5 map1.put("1","Jack"); //存儲鍵和值
6 map1.put("2","Rose");
7 map1.put("3","Lucy");
8 Set keySet1 = map1.keySet(); //獲取鍵的集合
9 Iterator it1 = keySet1.iterator();
10 while (keySet1.iterator().hasNext()){ // 叠代鍵的集合
11 Object key = it1.next();
12 Object value = map1.get(key); //獲得每個鍵所對應的值
13 System.out.println(key+":"+value);
14 }
15
16 //第二種先獲取集合中的所有映射關系,然後從映射關系中取出鍵和值
17 Map map2 = new HashMap();
18 map2.put("1","Jack"); //存儲鍵和值
19 map2.put("2","Rose");
20 map2.put("3","Lucy");
21 Set entrySet = map2.entrySet();
22 Iterator it = entrySet.iterator(); //獲取Iterator對象
23 while (it.hasNext()){
24 Map.Entry entry = (Map.Entry)(it.next()); //獲取集合中鍵值對映射關系
25 Object key = entry.getKey(); //獲取Entry中的鍵
26 Object value = entry.getValue(); //獲取Entry中的值
27 System.out.println(key+":"+value);
28 }
29 }
30 }
運行結果:
1:Jack
2:Rose
3:Lucy
LinkedHashMap:基於鏈表+哈希表。可以保證map集合有序(存入和取出的順序一致)。
③TreeMap---數據結構:二叉樹,保證鍵的唯一性,同步的,可以對map集合中的鍵進行排序。 1 //按學號從大排到小
2 public class Example20 {
3 public static void main(String[] args) {
4 TreeMap tm = new TreeMap(new MyCompartor()); //傳入一個自定義比較器
5 tm.put("1","Jack"); //存儲鍵和值
6 tm.put("2","Rose");
7 tm.put("3","Lucy");
8 Set keySet = tm.keySet(); //獲取鍵的集合
9 Iterator it = keySet.iterator(); // 叠代鍵的集合
10 while (it.hasNext()){
11 Object key = it.next();
12 Object value = tm.get(key); //獲得每個鍵所對應的值
13 System.out.println(key+":"+value);
14 }
15 }
16 }
17 class MyCompartor implements Comparator{ //自定義比較器
18 public int compare(Object o1, Object o2) { //實現比較方法
19 String id1 = (String) o1; //將Object類型的參數強轉為String類型
20 String id2 = (String) o2;
21 return id2.compareTo(id1); //將比較結果之後的值返回,按字典相反順序進行排序
22 }
23 }
運行結果:
3:Lucy
2:Rose
1:Jack
四、 泛型(parameterized type) 1、泛型的使用 體現<數據類型>,<>也是括號,往括號裏寫都寫其實就是在傳遞參數。 格式:ArrayList<參數化類型> list = new ArrayList<參數化類型>();
泛型的優點:安全機制;將運行時期的ClassCastExecption轉移到了編譯時期變成了編譯失敗。泛型技術,是給編譯器使用的技術。避免了強轉的麻煩。
示例: 1 public class Example23 {
2 public static void main(String[] args) {
3 ArrayList<String> list = new ArrayList<String>();
4 list.add("String");
5 list.add("Collection");
6 for(String str:list){
7 System.out.println(str);
8 }
9 }
10 }
2、自定義泛型:
需求:請自己提供一個容器類。
分析:你要做一個容器類,你就應該知道容器類具備什麽基本功能?
添加功能 save()
獲取功能 get()
要做這樣的方法,save是不是應該有參數呢?肯定的。
get()應該有參數嗎?這裏我們可以不給形式參數,但是一定要有返回值類型。
基本格式:
void save (參數類型 參數){…}
返回值類型 get(){…..}
為了讓我們的容器類能夠存儲任意類型的對象,我就應該給save()方法中的參數定義為object類型。
當然,get()方法的返回值類型應該是object類型。
出現問題:A 不兼容類型 B 類型轉換異常
需求:自己定義一個泛型類並使用
如何定義一個泛型類呢?
就是把泛型安裝其格式加在類上。
格式:
<參數化類型>可以是E、T這樣有意義的單詞。
使用泛型後,我們可以不用再做類型轉換了。
//在創建類時,聲明參數類型為T
class 類名<T>{
T temp;
//在創建save()方法時,指定參數類型為T
public void save (T temp){this.temp = temp}
//在創建get()方法時,指定返回值類型為T
public T get(){
return temp;
}
}
示例:
1 class CachePool<T>{
2 T temp;
3 public void save(T temp){
4 this.temp=temp;
5 }
6 public T get() {
7 return temp;
8 }
9 }
10 public class Example26 {
11 public static void main(String[] args) {
12 CachePool<Integer> pool = new CachePool<Integer>();
13 pool.save(new Integer(1));
14 Integer temp = pool.get();
15 System.out.println(temp);
16 }
17 }
五、Collections工具類
Collections:集合框架中的用於操作集合對象工具類。都是靜態方法。- 獲取Collection最值。
- 對List集合排序,也可以用二分查找。
- 對排序逆序。
- 可以將非同步的集合轉變成同步的集合。如:Xxx synchronizedXxx(Xxx) -------List synchronizedList (List)
//排序操作
1 public class Example27 { 2 public static void main(String[] args) { 3 ArrayList list = new ArrayList(); 4 Collections.addAll(list,"c","z","B","K"); 5 System.out.println("排序前:"+list); 6 Collections.reverse(list); 7 System.out.println("反轉後:"+list); 8 Collections.shuffle(list); 9 System.out.println("按自然順序排序後:"+list); 10 Collections.sort(list); 11 System.out.println("洗牌後:"+list); 12 } 13 }
運行結果:
排序前:[c, z, B, K]
反轉後:[K, B, z, c]
按自然順序排序後:[c, B, K, z]
洗牌後:[B, K, c, z]
//查找、替換操作
1 public class Example28 {
2 public static void main(String[] args) {
3 ArrayList list = new ArrayList();
4 Collections.addAll(list,-3,2,9,5,8);
5 System.out.println("集合中的元素:"+list);
6 System.out.println("集合中的最大元素:"+Collections.max(list));
7 System.out.println("集合中的最小元素:"+Collections.min(list));
8 Collections.replaceAll(list,8,0); //將集合中的8用0替換掉
9 System.out.println("替換後的集合:"+list);
10 }
11 }
運行結果:
集合中的元素:[-3, 2, 9, 5, 8]
集合中的最大元素:9
集合中的最小元素:-3
替換後的集合:[-3, 2, 9, 5, 0]
六、Arrays:用於操作數組的工具類。類中定義的都是靜態工具方法。
- 對數組排序。
- 二分查找。
- 數組復制。
- 對兩個數組進行元素的比較,判斷兩個數組是否相同。
- 將數組轉成字符串。
1 //使用Arrays的sort()方法排序 2 public class Example29 { 3 public static void main(String[] args) { 4 int[] arr={9,8,3,5,2}; 5 System.out.print("排序前:"); 6 printArray(arr); 7 Arrays.sort(arr); 8 System.out.print("排序後:"); 9 printArray(arr); 10 } 11 public static void printArray(int[] arr) { 12 System.out.print("["); 13 for (int x=0;x<arr.length;x++){ 14 if (x!=arr.length-1){ 15 System.out.print(arr[x]+","); 16 }else { 17 System.out.println(arr[x]+"]"); 18 19 } 20 } 21 } 22 }
排序前:[9,8,3,5,2]
排序後:[2,3,5,8,9] -
1 //使用Arrays的binarySearch(Object[] a,Object key)方法查找元素 2 class Example { 3 public void run() { 4 int[] arr={9,8,3,5,2}; 5 Arrays.sort(arr);//調用排序方法,對數組排序 6 int index = Arrays.binarySearch(arr,3);//查找指定元素3 7 System.out.println("數組排序後元素3的索引是:"+index);//輸出打印元素所在的索引位置 8 } 9 }
數組排序後元素3的索引是:1 -
1 //使用Arrays的copyOfRange(int[] original,int from,int to)方法拷貝元素 2 class Example31 { 3 public void run() { 4 int[] arr={9,8,3,5,2}; 5 int[] copies=Arrays.copyOfRange(arr,1,7); 6 for (int i =0;i<arr.length;i++){ 7 System.out.print(copies[i]+","); 8 } 9 } 10 }
【8,3,5,2,0,0】1 //使用Arrays的fill(Object[] a,Object val)方法填充元素 2 class Example{ 3 public void run() { 4 int[] arr={1,2,3,4}; 5 Arrays.fill(arr,8); 6 for (int i =0;i<arr.length;i++){ 7 System.out.print(i+":"+arr[i]+“---”); 8 } 9 } 10 }
0:8---1:8---2:8---3:81 //使用Arrays的toString(int [] ,arr)方法把數組轉換為字符串 2 class Example{ 3 public void run() { 4 int[] arr={9,8,3,5,2}; 5 String arrString=Arrays.toString(arr); //使用toString()方法將數組轉換為字符串 6 System.out.println(arrString); 7 } 8 }
[9, 8, 3, 5, 2]
Java入門——(6)集合