1. 程式人生 > 實用技巧 >Java學習之集合篇

Java學習之集合篇

Java學習之集合篇

0x00 前言

上篇文章的常用類,其實就已經講到了,這個ArrayList集合,但是ArrayList只是集合中的其中一種,那這篇文章就來講講關於集合的一些物件。

0x01 集合概念

先來了解一些什麼是集合,
下面來貼一段集合的描述。

集合:java中的一種容器,可以用來儲存多個數據。

在這裡要理清楚的一個概念,陣列的長度是固定的,一旦定義了就無法改名,而集合是可以改變的。

集合儲存的都是物件,物件的型別可以不一樣,但是陣列只能儲存基本資料型別。

集合架構

集合按照儲存的結構可以分為兩類,分別是單列集合(java.util.Collection)和雙列集合(java.util.Map),這裡就先來講講collection集合。

collection是單列集合類的根介面,用於儲存符合某種規則的元素,他有兩個主要的子介面,分別是java.util.Listjava.util.Set

來說說這兩個子介面的區別,List的特點是儲存的元素有序,元素可以重複。而set的特點是元素無序、儲存的元素不可重複。List的介面主要實現類有ArrayList 和LinkedList,Set介面的主要實現類有HashSet和TreeSet

0x02 Collection

Collection是所有單列集合的父介面,也就是說collection是所有單列集合的最頂層的。因此在Collection中定義了單列集合(List和Set)通用的一些方法,這些方法可用於操作所有的單列集合。

* `public boolean add(E e)`:  把給定的物件新增到當前集合中 。
* `public void clear()` :清空集合中所有的元素。
* `public boolean remove(E e)`: 把給定的物件在當前集合中刪除。
* `public boolean contains(E e)`: 判斷當前集合中是否包含給定的物件。
* `public boolean isEmpty()`: 判斷當前集合是否為空。
* `public int size()`: 返回集合中元素的個數。
* `public Object[] toArray()`: 把集合中的元素,儲存到陣列中。

這裡使用一下這幾個方法


public class Input {

    public static void main(String[] args) {
        Collection<String> list = new ArrayList<>();
        list.add("123");
        list.add("321");
        list.remove("123");
        boolean a = list.isEmpty();
        System.out.println(a);
        System.out.println(list);

        
    }
}


0x03 迭代器

在我們想要遍歷的時候,通常都會用到for迴圈。但是這裡遍歷集合,java給我們提供了Iterator介面,也就是迭代器,該介面也是集合的一種。

首先來了解迭代的概念:

Collection集合元素的通用獲取方式。在取元素之前先要判斷集合中有沒有元素,如果有,就把這個元素取出來,繼續在判斷,如果還有就再取出出來。一直把集合中的所有元素全部取出。這種取出方式專業術語稱為迭代。

常用方法:

public E next():返回迭代的下一個元素。
public boolean hasNext():如果仍有元素可以迭代,則返回 true。

程式碼例項:

public static void main(String[] args) {
        Collection<String> list = new ArrayList<>();

        list.add("123");
        list.add("321");
        list.add("baidu");
        list.add("google");
        Iterator<String> is = list.iterator();

        while (is.hasNext()){
            String i = is.next();
            System.out.println(i);
        }
    }

這裡使用while迴圈的條件是判斷集裡面是否有值,然後再讀取值賦值給i。程式碼的整體還是比較簡單的。

0x04 增強for迴圈

增強for迴圈是我們在遍歷集合裡面,用的最多的,語法簡單。他的他的內部原理其實也是個Iterator迭代器。

格式:

for(元素的資料型別  變數 : Collection集合or陣列){ 
  	...
}

通常只進行遍歷元素,增強for裡面不能做增刪的操作。

public static void main(String[] args) {
        Collection<String> list = new ArrayList<>();

        list.add("123");
        list.add("321");
        list.add("baidu");
        list.add("google");

        for (String s : list) {
            System.out.println(s);
            
        }

    }

在使用IDEA編寫的時候普遍會有提示。

0x05 泛型

泛型是一種未知的資料型別,如果我們不知道什麼資料型別的時候就可以使用泛型。

程式碼格式:

修飾符 class 類名<代表泛型的變數> { }

含有泛型的類:

public class Demo11<R> {
    private R r;


    public R getR() {
        return r;
    }

    public void setR(R r) {
        this.r = r;
    }
}

main方法程式碼:

public class DemoMain {
    public static void main(String[] args) {
        Demo11<String> str = new Demo11<>();
        str.setR("123");
        System.out.println(str.getR());
    }

}

含有泛型的方法:

類:

    public <R> void method(R r){
        System.out.println(r);

    }
}


main方法程式碼:

    public static void main(String[] args) {

        Demo11 abc = new Demo11();
        abc.method("abc");

    }

呼叫方法時,確定泛型的型別

含有泛型的介面:

程式碼例項:

定義格式:

修飾符 interface介面名<代表泛型的變數> { }


public interface MyInterface<R> {
    public abstract void add(R r);
    public abstract R getR();

}

實現介面類:

public class MyInterfaceimpl implements MyInterface<String> {
    @Override
    public void add(String s) {
        System.out.println(s);
    }

    @Override
    public String getR() {
        return null;
    }
}

這裡是在實現接口裡面,確定泛型型別。

如果說始終無法確定型別,也可以在建立物件的時候來確定該型別。

實現類:

public class MyInterfaceimpl<R> implements MyInterface<R>  {

    @Override
    public void add(R r) {
        System.out.println(r);
    }

    @Override
    public R getR() {
        return null;
    }
}

main方法程式碼:

  public static void main(String[] args) {
        MyInterfaceimpl<String> str = new MyInterfaceimpl<>();
        str.add("123");


    }

在建立物件的時候,確定了型別為string型別。

0x06 List 介面

List介面是Collection的子介面,
List接口裡面允許出現重複元素得,在程式中可以通過索引來訪問。
List介面儲存的資料是有序的。

public class DemoMain {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("狗子");
        list.add("二狗");
        list.add("狗蛋");

        list.add(1,"狗蛋子");
        list.remove(1);
        System.out.println(list);
    }
}

0x07 set介面

set介面也是繼承了Collection介面,也是單列集合。
set介面中元素無序,並且都會以某種規則保證存入的元素不出現重複。

set介面的實現類有:

AbstractList、 AbstractSequentialList、 ArrayList, AttributeList、 CopyOnWriteArrayList、 LinkedList, RoleList、 RoleUnresolvedList、Stack、 Vector。

Hashset

Hashset所儲存的元素是不可重複的,並且元素都是無序的(即存取順序不一致)。
這就來用hashset這個實現類來演示

    public static void main(String[] args) {
        HashSet<String> list = new HashSet<>();

        list.add("123");
        list.add("785");
        list.add(new String("23"));
        for (String s : list) {   System.out.println(s);
        }
    }

LinkHashSet

hashset是為了保證元素唯一性,如果想要有序這時候就需要用到LinkedHashSet。

public static void main(String[] args) {

        Set<String> set = new LinkedHashSet<>();

        set.add("123");
        set.add("12");
        set.add("12999");
        set.add("1453");
        set.add("543");
        for (String s : set) {
            System.out.println(s);
        }
    }

可變引數

這裡來穿插一點關於可變引數的小知識點。

如果我們定義一個方法需要接受多個引數,並且多個引數型別一致。

定義格式:

修飾符 返回值型別 方法名(引數型別... 形參名){ }

 public static void main(String[] args) {
        int[] arr = {1,2,3,4};

        method(1,1,1,1);//使用可變引數方法
        method1(arr);//不使用可變引數方法
    }

    private static void method1(int[] args) {
        for (int arg : args) {
            System.out.println(arg);

        }

    }

    private static void method(int... args) {
        System.out.println(args);
    }

這裡可以看到2種定義方式,一個是使用了可變引數的方式,這裡就可以直接省去先定義一個數組再對其傳入的麻煩。

注意:如果在方法書寫時,這個方法擁有多引數,引數中包含可變引數,可變引數一定要寫在引數列表的末尾位置。

0x08 collections 類

這個和前面講到的collection的是2個東西,conetcion是一個單列集合的介面,而conections是集合的工具類。

該類是個靜態類,可以直接使用類名來呼叫。

常用方法:

- public static <T> boolean addAll(Collection<T> c, T... elements)  `:往集合中新增一些元素。
- `public static void shuffle(List<?> list) 打亂順序`:打亂集合順序。
- `public static <T> void sort(List<T> list)`:將集合中元素按照預設規則排序。
- `public static <T> void sort(List<T> list,Comparator<? super T> )`:將集合中元素按照指定規則排序。

程式碼示例:

    public static void main(String[] args) {

        ArrayList<Integer> list = new ArrayList<>();

        Collections.addAll(list, 123, 1243, 1354, 123);
        System.out.println(list);
        Collections.sort(list);
        System.out.println(list);
    }

以往的集合都是通過add一個一個的去新增資料,但是collections可以一次新增多個數據。

0x09 Map集合

在collection的一些協和,元素都是單獨存在的,想集合儲存一個個元素的方式存在。
而map中的集合,元素是成對存在的。每個元素都由鍵和值組成,通過鍵可以找到對應的值。

已知實現類:

AbstractMap, Attributes, AuthProvider, ConcurrentHashMap, ConcurrentSkipListMap, EnumMap, HashMap, Hashtable, IdentityHashMap, LinkedHashMap, PrinterStateReasons, Properties, Provider, RenderingHints, SimpleBindings, TabularDataSupport, TreeMap, UIDefaults, WeakHashMap 

下面就來看最常用的幾個實現類

Hashmap

HashMap:儲存資料採用的雜湊表結構,元素的存取順序不能保證一致。由於要保證鍵的唯一、不重複,需
要重寫鍵的hashCode()方法、equals()方法。

map介面中的方法:

public V put(K key, V value) : 把指定的鍵與指定的值新增到Map集合中。
public V remove(Object key) : 把指定的鍵 所對應的鍵值對元素 在Map集合中刪除,返回被刪除元素的
值。
public V get(Object key) 根據指定的鍵,在Map集合中獲取對應的值。
public Set<K> keySet() : 獲取Map集合中所有的鍵,儲存到Set集合中。
public Set<Map.Entry<K,V>> entrySet() : 獲取到Map集合中所有的鍵值對物件的集合(Set集合)

Map介面中的集合都有兩個泛型變數,在使用時,要為兩個泛型變數賦予資料型別。兩個泛型變數的數
據型別可以相同,也可以不同。

程式碼:

public static void main(String[] args) {

        HashMap<String, String> map = new HashMap<>();
        map.put("小明","18");
        map.put("小j","48");
        map.put("小x","88");
        map.put("小g","98");
        System.out.println(map.get("小明"));

    }

使用put方法時,若指定的鍵(key)在集合中沒有,則沒有這個鍵對應的值,返回null,並把指定的鍵值新增到集合中。指定的鍵(key)在集合中存在,則返回值為集合中鍵對應的值(該值為替換前的值),並把指定鍵所對應的值,替換成指定的新值。

map集合遍歷

map裡面提供了一個獲取所以鍵值的方法keyset。供我們遍歷使用。

public static void main(String[] args) {
    HashMap<String,Integer> map = new HashMap<>();
    map.put("狗子",18);
    map.put("二狗",17);
    map.put("狗蛋",16);


    Set<String> keys = map.keySet();
        for (String key : keys) {
            Integer value = map.get(key);
            System.out.println(value);
        }
    }

遍歷鍵值對

Entry將鍵值對的對應關係封裝成了物件。即鍵值對物件,這樣我們在遍歷Map集合時,就可以從每一個鍵值對(Entry)物件中獲取對應的鍵與對應的值。

既然是鍵值的物件,那麼肯定會提供獲取的方法。

public K getKey():獲取Entry物件中的鍵。

public V getValue()`:獲取Entry物件中的值。

程式碼:

public static void main(String[] args) {
        // 建立Map集合物件
        HashMap<String, String> map = new HashMap<String,String>();
        // 新增元素到集合
        map.put("狗子", "18");
        map.put("狗蛋", "17");
        map.put("二狗", "16");

        // 獲取 所有的 entry物件  entrySet
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            System.out.println(entry); //遍歷

            System.out.println("key"+entry.getKey());
            System.out.println("value"+entry.getValue());
        }
    }

LinkedHashMap

Hashmap的存放是無序的,如果需要有序儲存資料的話,就需要用到LinkedHashMap。

public static void main(String[] args) {

        LinkedHashMap<String,String> list = new LinkedHashMap<>();
        list.put("狗子","18");
        list.put("二狗","17");
        list.put("狗蛋","16");
        Set<Map.Entry<String, String>> entries = list.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            System.out.println(entry);
        }
    }

0x10 結尾

關於集合的一些東西也寫完了,其實當中還有集合的一些資料結構沒有寫進去,打算把資料結構這個東西單獨提取出來寫一篇文章。