主頁 > 後端開發 > Java集合類詳解

Java集合類詳解

2022-06-20 10:29:20 後端開發

集合

集合類的特點:提供一種存盤空間可變的存盤模型,存盤的資料容量可以隨時發生改變,

Collection:單列(介面)

概述:

是單列集合的頂層介面,表示一組物件,這些物件也成為Cpllection的元素

JDK不提供此介面的任何直接實作,它提供更具體的子介面(如List和Set)實作

實作方法

 //創建Collection集合的物件
        Collection<String> c = new ArrayList<String>();

        //添加元素:boolean add (E e)
        c.add("hello");
        c.add("My");
        c.add("java");

        //輸出集合物件
        System.out.println(c);

常用方法

方法名 說明
boolean add(E e) 添加元素
boolean remove(Object o) 從集合中移除指定的元素
void clear() 清空集合中的元素
boolean contains(Object o) 判斷集合中是否存在指定的元素
boolean isEmpty() 判斷集合是否為空
int size() 集合的長度,也就是集合中元素的個數
		Collection<String> c=new ArrayList<>();

        //添加元素
        /*System.out.println(c.add("Hello"));
        System.out.println(c.add("World"));
        System.out.println(c.add("World"));
        */

        /*選擇關鍵字 ctrl+B查看原始碼
          alt+7 打開一個視窗,查看該類的所有資訊
        ArrayList原始碼:
        public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
        }
        永遠回傳true */
        c.add("hello");
        c.add("World");
        c.add("World");

        //移除指定元素
        System.out.println(c.remove("World"));//true
        System.out.println(c.remove("world"));//false

        //清空集合所有元素
        c.clear();

        //判斷集合中是否存在指定元素
        System.out.println(c.contains("World"));//true
        System.out.println(c.contains("javaSE"));//false

        //判斷集合是否為空
        System.out.println(c.isEmpty());

        //查看集合長度
        System.out.println(c.size());//3

        //輸出集合物件
        System.out.println(c);

遍歷

Iterator:迭代器,集合的專用遍歷方式

  • Iterator<E> iterator():回傳此集合中的迭代器,通過集合的iterator方法得到

  • 迭代器是通過集合的iterator()方法得到的,所以我們說他是依賴集合而存在的

    常用方法

    E next():回傳迭代中的下一個元素

    boolean hasNext():如果迭代器具有更多的元素,回傳true

    	    Collection<String> c=new ArrayList<>();
    
            c.add("hello");
            c.add("World");
            c.add("World");
    
            //回傳此集合中的迭代器,通過集合的iterator方法得到
            Iterator<String> it = c.iterator();
    
            //原始碼:
            public Iterator<E> iterator() {
                return new Itr();
            }
            
            private class Itr implements Iterator<E>{
                ...
            }
    
            
            System.out.println(it.next());
            System.out.println(it.next());
            System.out.println(it.next());
            System.out.println(it.next());//拋出例外:NoSuchElementException 元素不存在
     //判斷是否還有元素;hasNext()
          if (it.hasNext()){
              System.out.println(it.next());
          }
          if (it.hasNext()){
              System.out.println(it.next());
          }
          if (it.hasNext()){
              System.out.println(it.next());
          }
          if (it.hasNext()){
              System.out.println(it.next());
          }
          
           //用while改進判斷
          while(it.hasNext()){
              //System.out.println(it.next());
              String s=it.next();
              System.out.println(s);
          }  
    
    @Description TODO 創建一個存盤學生物件的集合,存盤3個學生物件,使用程式實作在控制臺遍歷該集合
    
     		Collection<Student> students=new ArrayList<>();
    
            Student s1=new Student("鐘無艷",201,21,"男",80.99);
            Student s2=new Student("諸葛亮",202,22,"男",99.99);
            Student s3=new Student("伽羅",203,23,"女",80.80);
    
            students.add(s1);
            students.add(s2);
            students.add(s3);
    
            Iterator<Student> it = students.iterator();
    
            while (it.hasNext()) {
                Student s =it.next();
                System.out.println(s.getName() + ',' + s.getId() + ',' + s.getAge() + ',' + s.getSex() + ',' + s.getGrade());
            }
    

    ?

List:可重復(介面)

概述

  • 有序集合(也稱為序列),用戶可以精確控制串列中每個元素的插入位置,用戶可以通過整數索引訪問元素,并搜索串列中的元素
  • 與Set集合不同,串列通常允許重復的元素
		List<String> l=new ArrayList<>();

        l.add("hello");
        l.add("world");
        l.add("java");
        l.add("world");

        System.out.println(l);

        Iterator<String> it = l.iterator();
        while (it.hasNext()){
            String s=it.next();
            System.out.println(s);
        }

特有方法:

方法名 說明
void add(int index,E element) 在此集合中的指定位置插入指定的元素
E remove(int index) 洗掉指定索引處的元素,回傳被洗掉的元素
E set(int index,E element) 修改指定索引處的元素,回傳被修改的元素
E get(int index) 回傳指定索引處的元素
        List<String> list=new ArrayList<>();

        list.add("hello");
        list.add("world");
        list.add("java");

        list.add(1,"javaee");//[hello, javaee, world, java]
        list.add(11,"javaee");//[hello, javaee, world, java] //越界例外IndexOutOfBoundsException

        list.remove(1); //[hello, world, java]

        list.set(1,"javaee");   //[hello, javaee, java]

        System.out.println(list.get(1));    //javaee

        System.out.println(list);

		//用for回圈使用get()方法遍歷集合
        for (int i = 0; i<list.size(); i++)
        {
            String s=list.get(i);
            System.out.println(s);
        }
@Description TODO 創建一個存盤學生物件的集合,存盤3個學生物件,使用程式實作在控制臺遍歷該集合

        List<Student> list = new ArrayList<>();

        Student s1 = new Student("鐘無艷", 201, 21, "男", 80.99);
        Student s2 = new Student("諸葛亮", 202, 22, "男", 80.99);
        Student s3 = new Student("伽羅", 203, 23, "男", 80.99);

        list.add(s1);
        list.add(s2);
        list.add(s3);

        Iterator<Student> it = list.iterator();

        while (it.hasNext()) {
            Student s =it.next();
            System.out.println(s.getName() + ',' + s.getId() + ',' + s.getAge() + ',' + s.getSex() + ',' + s.getGrade());
        }
        System.out.println("--------------------");

        for (int i = 0; i < list.size(); i++) {
            Student s = list.get(i);
            System.out.println(s.getName() + ',' + s.getId() + ',' + s.getAge() + ',' + s.getSex() + ',' + s.getGrade());
        }

并發修改例外

@Description TODO 遍歷集合,得到每一個元素,檢查是否有“world”這個元素,如果有,就添加一個“javaee”元素		
        List<String> list = new ArrayList<>();

        list.add("hello");
        list.add("world");
        list.add("java");

        Iterator<String> it = list.iterator();

        while (it.hasNext()) {
            String s=it.next();//拋出例外:ConcurrentModificationException:并發修改例外
            if (s.equals("world")){
                list.add("javaee");
            }
        }

		for (int i = 0; i < list.size() ; i++) {
            String s=list.get(i);
            if (s.equals("world")){
                list.add("javaee");
            }
        }//succeed
        System.out.println(list);

原始碼如下:

public interface List<E>{
    Iterator<E> iterator();
    boolean add(E e);
}

public abstract class AbstractList<E>{
    protected int modCount = 0;
}

public class ArrayList<E> extends AbstractList<E> implements List<E>{
    public E get(int index) {
        Objects.checkIndex(index, size);
        return elementData(index);
    }//沒有實際修改集合的次數和預期修改集合的次數的判斷

    public boolean add(E e) {
            modCount++;//實際修改集合次數++
            add(e, elementData, size);
            return true;
    }

    public Iterator<E> iterator() {
        return new Itr();
    }

    private class Itr implements Iterator<E> {
        int expectedModCount = modCount;
        /*
            modCount:實際修改集合的次數
            expectedModCount:預期修改集合的次數
            開始都為0
        */

        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = https://www.cnblogs.com/hackertyper/archive/2022/06/19/ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)//判斷是否相等,modCount++,與expectedModCount不相等
                throw new ConcurrentModificationException();
        }
    }

}

ListIterator :串列迭代器

  • 通過List集合的listIterator()方法得到,所以說它是List集合特有的迭代器

  • 繼承于Iterator,用于程式員沿任意方向遍歷串列的迭代器,在迭代期間修改串列,并獲取串列中迭代器的當前位置,

  • 常用方法

    E next() :回傳迭代中的下一個元素

    boolean hasNext() :如果迭代具有更多元素,回傳true

    E previus :回傳串列中上一個元素

    bookean hasPrevious() :如果串列迭代器在相反方向遍歷串列時具有更多元素,則回傳true

    void add(E e) :將指定的元素插入串列

List<String> list = new ArrayList<>();

        list.add("hello");
        list.add("world");
        list.add("java");

        ListIterator<String> lit = list.listIterator();

        while (lit.hasNext()){
            String s = lit.next();
            System.out.println(s);
        }

        System.out.println("-----------");

        while(lit.hasPrevious()){
            String s =lit.previous();
            System.out.println(s);
        }

        System.out.println("-------------");
        

        ListIterator<String> lit = list.listIterator();

        while (lit.hasNext()) {
            String s= lit.next();
            if(s.equals("world")){
                lit.add("javaee");  //success
            }
        }
        //使用串列迭代器實作添加元素,并無例外
        System.out.println(list);


  • 增強for回圈 :簡化陣列和Collection集合的遍歷

    實作Iterable介面的類允許其物件稱為增強型for陳述句的目標

    內部原理是一個Iterator迭代器

    • 格式:

      for(元素資料型別 變數名:陣列或Collection集合){
      	//在此處使用變數即可,該變數就是元素
      }
      
      int[] arr={1,2,3,4,5};
      for(int i:arr){
        System.out.println(i);
      }
      
      int[] arr = {1, 2, 3, 4, 5};
      
              for (int i : arr) {
                  System.out.println(i);
              }
      
          System.out.println("--------");
      
          String[] stArray = {"hello", "world", "java"};
          for (String s : stArray) {
              System.out.println(s);
          }
      
          System.out.println("-----------");
          List<String> list=new ArrayList<>();
      
          list.add("hello");
          list.add("world");
          list.add("java");
      
          for (String s:list){
              System.out.println(s);
          }
      
          System.out.println("-----------");
          //內部是一個Iterator迭代器
      
          for (String s:list){
              if (s.equals("world")){
                  list.add("javaee"); //并發修改例外:ConcurrentModificationException;因此內部是一個Iterator迭代器
              }
          }
      

      ?```

至此,共有三種方式遍歷集合:①迭代器—集合特有的遍歷方式,②普通for—帶有索引的遍歷方式,③增強for—最方便的遍歷方式,

  • 若只為了遍歷,選擇增強for的方式
  • 若使用到了索引,則選擇普通for的方式

資料結構:

? 堆疊:先進后出

? 佇列:先進先出

? 陣列:查詢快、增刪慢的模型

? 鏈表:增刪快、查詢慢的模型

?ArrayList(實作類)

? ArrayList的底層資料結構是陣列 ,查詢快、增刪慢

LinkedList(實作類)

? LinkedList的底層資料結構是鏈表,查詢慢,增刪快

? LinkedList集合的特有方法

方法名 說明
public void addFirst(E e) 在該串列開頭插入指定元素
public void addLast(E e) 將指定的元素追加到此串列的末尾
public E getFirst() 回傳此串列中的第一個元素
public E getLast() 回傳此串列中的最后一個元素
public E removeFirst() 從此串列中洗掉并回傳第一個元素
public E removeLast() 從此串列中洗掉并回傳最后一個元素
LinkedList<String> linkedList =new LinkedList<>();

        linkedList.add("hello");
        linkedList.add("world");
        linkedList.add("java");

        System.out.println(linkedList);

        //在該串列開頭插入指定元素
        linkedList.addFirst("javaee");
        //將指定的元素追加到此串列的末尾
        linkedList.addLast("javaee");
        //回傳此串列中的第一個元素
        System.out.println(linkedList.getFirst());
        //回傳此串列中的最后一個元素
        System.out.println(linkedList.getLast());
        //從此串列中洗掉并回傳第一個元素
        System.out.println(linkedList.removeFirst());
        //從此串列中洗掉并回傳最后一個元素
        System.out.println(linkedList.removeLast());

        System.out.println(linkedList);
        //分別使用ArrayList和LinkedList完成存盤字串遍歷
		//創建集合物件ArrayList
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("hello");
        arrayList.add("world");
        arrayList.add("java");

        Iterator<String> it = arrayList.iterator();

        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("---------------");
        for (int i = 0; i < arrayList.size(); i++) {
            String s = arrayList.get(i);
            System.out.println(s);
        }
        System.out.println("---------------");
        for (String s : arrayList) {
            System.out.println(s);
        }
        System.out.println("---------------");

        //創建集合物件LinkedList
        LinkedList<String> linkedList = new LinkedList<>();

        linkedList.add("Hello");
        linkedList.add("World");
        linkedList.add("Java");

        Iterator<String> it1 = linkedList.iterator();

        while(it1.hasNext()){
            String s= it1.next();
            System.out.println(s);
        }
        System.out.println("---------------");
        for (int i =0;i<linkedList.size();i++){
            String s= linkedList.get(i);
            System.out.println(s);
        }
        System.out.println("---------------");
        for(String s:linkedList){
            System.out.println(s);
        }
        System.out.println("---------------");
    }

Set:不可重復(介面)

特點:

  • 不包含重復元素的集合
  • 沒有帶索引的方法,所以不能使用普通for回圈遍歷

HashSet:實作Set介面,對集合的迭代順序不作任何保證

        //創建集合物件
        Set<String> set= new HashSet<>();

        set.add("hello");
        set.add("world");
        set.add("java");
        set.add("world");//最終只會添加一個world

        for (String s:set){
            System.out.println(s);//world java hello
        }

哈希值

哈希值是JDK根據物件的地址或者字串或者數字算出來的int型別的數值

Object類中的public int hashCode()可以獲取物件的哈希值

物件的哈希值的特點

  • 同一個物件多次呼叫hashCode()方法回傳的哈希值是相同的

  • 默認情況下,不同物件的哈希值是不相同的

  • 通過方法重寫,可以實作讓不同物件的哈希值相同

HashSet(實作類)

特點

  • 底層資料結構是哈希表
  • 對集合的迭代順序不做任何保證,也就是說不保證存盤和去除的元素順序一致
  • 沒有帶索引的方法,所以不能使用普通for回圈遍歷
  • 由于是Set集合,所以是不包含重復元素的集合
HashSet<String> hashSet=new HashSet<>();

        hashSet.add("hallo");
        hashSet.add("world");
        hashSet.add("java");

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

HashSet集合保證元素唯一性原始碼分析

HashSet<String> hashSet=new HashSet<>();

hashSet.add("hallo");
hashSet.add("world");
hashSet.add("java");

-------------------------------------------------

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

//hash值和元素的hashCode()方法相關
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    //如果哈希表美亞由初始化,就對其初始化
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    //根據物件的哈希值計算物件的存盤位置,如果該位置沒有元素就存盤元素
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        /*
            存入的元素和以前的元素比較哈希值
                如果哈希值不同,會繼續向下執行,把元素添加到集合
                如果哈希值相同,會呼叫物件的equals()方法進行比較
                    如果回傳false,說明元素重復,不存盤
        */
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = https://www.cnblogs.com/hackertyper/archive/2022/06/19/e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}
LinkedHashSet(實作類)
  • 繼承于HashSet
  • 由哈希表和鏈表實作的Set介面,具有可預測的迭代次序
  • 由鏈表保證元素有序,也就是說元素的存盤和取出順序是一致的
  • 由哈希表保證元素唯一,也就是說沒有重復的元素
        LinkedHashSet<String> linkedHashSet=new LinkedHashSet<>();

        linkedHashSet.add("hello");
        linkedHashSet.add("world");
        linkedHashSet.add("java");
        linkedHashSet.add("world");

        for (String s:linkedHashSet){
            System.out.println(s);//hello world java
        }

TreeSet(實作類)

特點:

  • 元素有序,這里的順序不是指存盤和去除的順序,而是按照一定的規則進行排序,具體排序方式取決于構造方法
    • TreeSet():根據其元素的自然排序進行排序
    • TreeSet(Comparator comparator):根據指定的比較器進行排序
  • 沒有帶索引的方法,所以不能使用for回圈遍歷
  • 由于是Set集合,所以不包含重復元素的集合
        //創建集合
        TreeSet<Integer> treeSet=new TreeSet<>();

        treeSet.add(15);
        treeSet.add(44);
        treeSet.add(55);
        treeSet.add(40);
        treeSet.add(10);
        treeSet.add(15);

        for (Integer i:treeSet){
            System.out.print(i+" "); //10 15 40 44 55 自然排序
        }
自然排序Comparable的使用
  • 用TreeSet集合存盤自定義物件,無參構造方法使用的是自然排序對元素進行排序的
  • 自然排序,就是讓元素所屬的類實作Comparable介面,重寫compareTo(To)方法
  • 重寫方法時,一定要注意排序規則必須按照要求的主要條件和次要條件來寫
public class Student implements Comparable<Student> {
  @Override
    public int compareTo(Student s) {
        //return 0;
        //return 1;
        //return -1;
        int num = this.age - s.age;

        int num2 = num == 0 ? this.name.compareTo(s.name) : num;
        return num2;
        ---------------------------------------------------------------------
        return 0:輸出結果為duheng,21 認為s2和s1是同一個元素
        return 1:輸出結果為duheng,21   love,18   chencui,22  認為s1比s2大,因此按照存盤順序輸出
        return -1:輸出結果為chencui,22   love,18  duheng,21        認為s2比s1大,因此按照存盤順序逆向輸出
        return num = this.age-s.age: love,18  duheng,21   chencui,22  this即為s2,按照升序排列
        return num = s.age-this.age: chencui,22   duheng,21   love,18  this即為s2,按照降序排列

        int num = this.age - s.age;
        int num2 = num == 0 ? this.name.compareTo(s.name) : num;    //年齡從小到大排序,年齡相同時,按照姓名的字母順序排序
        return num2;
    }
}


/*   * 存盤學生物件并遍歷,創建TreeSet集合使用無參構造方法
     * 按照年齡從小到大排序,年齡相同時,按照姓名的字母順序排序*/
    public static void main(String[] args) {
        //創建集合物件
        TreeSet<Student> ts = new TreeSet<>();

        Student s1=new Student("dyxx",21);
        Student s2=new Student("love",18);
        Student s3=new Student("zhulu",22);
        Student s4=new Student("sss",18);

        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);

        for (Student s:ts){
            System.out.println(s.getName()+","+s.getAge());//Exception  ClassCastException   Comparable
        }
        //因此需要讓Student實作Comparable介面,并重寫方法compareTo方法
        
    }
比較器排序Comparator的使用
  • 用TreeSet集合存盤自定義物件,無參構造方法使用的是自然排序對元素進行排序的
  • 比較器排序,就是讓集合構造方法接收Comparator的實作類物件,重寫compareTo(To1,To2)方法
  • 重寫方法時,一定要注意排序規則必須按照要求的主要條件和次要條件來寫
        //創建集合物件
        TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s1.getAge() - s2.getAge();
                int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
                return num2;
            }
        });

        Student s1=new Student("duheng",21);
        Student s2=new Student("chencui",22);
        Student s3=new Student("love",18);

        ts.add(s1);
        ts.add(s2);
        ts.add(s3);

        for (Student s:ts){
            System.out.println(s.getName()+","+s.getAge());//Exception  ClassCastException   Comparable
        }

泛型

將型別由原來的具體的型別引數化,然后在使用/呼叫時傳入具體的型別,這種引數型別可以用在類、方法和介面中,分別為泛型類、泛型方法、泛型介面

定義格式=

  • <型別>:指定一種型別的格式,這里的型別可以看成時形參
  • <型別1,型別2...>:指定多種型別的格式,多種型別之間用逗號隔開,這里的型別可以看成時形參
  • 將來具體呼叫時候給定的型別可以看成是實參,并且實參的型別只能是參考資料型別

好處

  • 把運行時期的問題提前到了編譯期間
  • 避免了強制型別轉換
        //創建集合物件
        //Collection c=new ArrayList();

        Collection<String> c = new ArrayList<>();//100報錯:提前報錯 迭代器中型別自動為String型別,不需要強轉

        c.add("hello"); //將字串賦值給object——向上轉型
        c.add("world");
        c.add("java");
        //c.add(100);//自動封裝為Integer

//        Iterator t = c.iterator();
        Iterator<String> t = c.iterator();
        while (t.hasNext()) {
//            Object obj=t.next();
//            System.out.println(obj);
//            String s= (String) t.next();//100:ClassCastException:因此課采用泛型來解決
            String s = t.next();
            System.out.println(s);
        }

泛型類

定義格式

  • 格式:修飾符 class 類名<型別>{}

  • 范例:public class Generic<T>{}

    ? 此處的T可以隨便寫為任意標識,常見的如T、E、K、V等形式的引數常用于表示泛型

public class GenericClassDemo<T> {
    private  T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}


public static void main(String[] args) {
        Generic<String> g1 = new Generic<String>();
        g1.setT("杜恒");
        System.out.println(g1.getT());
  
        Generic<Integer> g2 = new Generic<Integer>();
        g2.setT(30);
        System.out.println(g1.getT());
    }

泛型方法

定義格式

  • 格式:修飾符<型別> 回傳值型別 方法名(型別 變數名){}
  • 范例:public <T> void show(T t){}
/*public class Generic{
    public void show(String s){
        System.out.println(s);
    }
    
    public void show(Integer i){
        System.out.println(i);
    }
	
  	public void show(Boolean b){
        System.out.println(b);
    }*/
    
  	/*public void show(T t){
    	System.out.println(t);
  	}
}
*/
  
/*public class Generic<T>{
  	public<> void show(T t){
    	System.out.println(t);
  	}
}
*/

public class Generic{
  	public <T> void show(T t){	//泛型方法
    	System.out.println(t);
  	}
}

public static void main(String[] args) {
	/*Generic<String> g1 = new Generic<String>();
	g1.show("杜恒");
  
	Generic<Integer> g2 = new Generic<Integer>();
	g1.show(22);
  
	Generic<Boolean> g3 = new Generic<Boolean>();
	g1.show(true);*/
  
  	Generic g = new Generic();
  	g.show("諸葛亮");
  	g.show(21);
  	g.show(true);
  	g.show(12.34);
}

泛型介面

定義格式

  • 格式:修飾符interface 介面名<型別>{}
  • 范例:public interface Generic<T>{}
public interface Generic<T> {
    void show(T t);
}

public class GenericImpl<T> implements Generic<T> {
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}

public class GenericInterfaceDemo {
    public static void main(String[] args) {
        Generic<String> g1 = new GenericImpl<>();
        g1.show("諸葛亮");

        Generic<Integer> g2 = new GenericImpl<>();
        g2.show(20);
    }
}

型別通配符

為了表示各種泛型List的父類,可以使用型別通配符

  • 型別通配符:<?>
  • List<?>:表示元素型別未知的List,他的元素可以匹配任何的型別
  • 這種帶通配符的List僅表示它是各種泛型List的父類,并不能把元素添加到其中

如果我們不希望List<?>是任何泛型List的父類,只希望它代表某一類泛型List的父類,可以使用型別通配符的上限

  • 型別通配符上限:<?extends 型別>
  • List<? extends Number>:他表示的型別是Number或者其子型別

除了可以指定型別通配符的上限,也可以指定型別通配符的下限

  • 型別通配符下限:<?super 型別>
  • List<? super Number>:他表示的型別是Number或者其父型別
 //型別通配符List<?>
        List<?> list1 = new ArrayList<Object>();
        List<?> list2 = new ArrayList<Number>();
        List<?> list3 = new ArrayList<Integer>();
        System.out.println("---------");

        //型別通配符上限
        List<? extends Number> list4= new ArrayList<Object>();//上限是Number,不能是Number父類Object
        List<? extends Number> list5 = new ArrayList<Number>();
        List<? extends Number> list6 = new ArrayList<Integer>();

        //型別通配符下限
        List<? super Number> list7 =new ArrayList<Object>();
        List<? super Number> list8 =new ArrayList<Number>();
        List<? super Number> list9 =new ArrayList<Integer>();//下限是Number,不能是Number的子類Integer

可變引數

可變引數又稱引數個數可變,用作方法的形參出現,那么方法引數個數就是可變的了

  • 格式:修飾符 回傳值型別 方法名(資料型別... 變數名){}
  • 范例:public static int sum(int... a){}
    public static void main(String[] args) {
        System.out.println(sum(10, 20));
        System.out.println(sum(10, 20, 30));
        System.out.println(sum(10, 20, 30, 40));

        System.out.println(sum(10, 20, 30, 40, 50));
        System.out.println(sum(10, 20, 30, 40, 50, 60));
        System.out.println(sum(10, 20, 30, 40, 50, 60, 70));
    }

    public static int sum(int... a) {//a是陣列
        int sum = 0;

        for (int i : a) {
            sum += i;
        }

        return sum;
    }

	public static int sum(int b,int... a){//一個方法有多個引數,包含可變引數的情況下,可變引數放在最后
        return 0;
    }

    /*public static int sum(int a,int b){
        return a+b;
    }

    public static int sum(int a,int b,int c){
        return a+b+c;
    }

    public static int sum(int a,int b,int c,int d){
        return a+b+c+d;
    }
    */

可變引數的使用

Arrays工具類中有一個靜態方法:

  • public static <T> List<T> asList(T... a):回傳由指定陣列支持的固定大小的串列
  • 回傳的集合不能做增刪操作,可以修改

List介面中有一個靜態方法:

  • public static <E> List<E> of(E... elements):回傳包含任意數量元素的不可變串列
  • 回傳的集合不能做增刪改操作

Arrays工具類中有一個靜態方法:

  • public static <E> Set<E> of(E... elements):回傳一個包含任意數量元素的不可變集合
  • 在給元素時不能給重復元素
  • 回傳的集合不能做增刪操作,沒有修改方法
        List<String> list = Arrays.asList("hello", "world", "java");//這樣做就不用一個個add了

        list.add("javaee"); //UnsupportedOperationException:不支持所請求的操作
        list.remove("java"); //UnsupportedOperationException
        list.set(1,"javaee");//success  陣列大小固定,不能添加洗掉,但是內容可改變

        System.out.println(list);
        

        List<String> list = List.of("hello", "world", "java","world");

        list.add("javaee"); //UnsupportedOperationException:不支持所請求的操作
        list.remove("java"); //UnsupportedOperationException
        list.set(1,"javaee");//UnsupportedOperationException    of:增刪改都不可以

        System.out.println(list);

         

        Set<String> set=Set.of("hello", "world", "java","world");   //IllegalArgumentException:非法或不適當的引數
        Set<String> set=Set.of("hello", "world", "java");

        set.add("javaee");//UnsupportedOperationException
        set.remove("javaee");//UnsupportedOperationException
        //set無索引,沒有set方法

Map:雙列(介面)

概述

  • interface Map<K,V> K:鍵的型別;V:值的型別
  • 將鍵映射到值的物件;不能包含重復的鍵;每個鍵可以映射到最多一個值
  • 舉例:學生的學號和姓名
    • 201 諸葛
    • 202 亮
    • 203 鐘無艷

創建Map集合的物件

  • 多型的方式
  • 具體的實作類HashMap
    //創建集合物件
    Map<String,String> map=new HashMap<>();

    map.put("194070201","諸葛亮");//put(K key, V value)將指定的值與此映射中的指定鍵相關聯
    map.put("194070202","鐘無艷");
    map.put("194070203","伽羅");
    map.put("194070203","劉");//當鍵重復時,就會修改元素,替代掉以前的值{194070201=杜恒, 194070202=杜, 194070203=陳}

    System.out.println(map);    //{201=劉, 202=王, 203=李}

Map集合的基本功能

方法名 說明
V put(K key,V value) 添加元素
V remove(Object key) 更具鍵洗掉鍵值對元素
void clear() 移除所有的鍵值對元素
boolean containsKey(Object key) 判斷集合是否包含指定的鍵
boolean containsValue(Object value) 判斷集合是否包含指定的值
boolean isEmpty() 判斷集合是否為空
int size() 集合的長度,也就是集合中鍵值對的個數
        //創建集合物件
        Map<String, String> map = new HashMap<>();

        //添加元素
        map.put("張無忌","趙敏");
        map.put("郭靖","黃蓉");
        map.put("楊過","小龍女");

        //System.out.println(map.remove("郭靖"));//黃蓉       {楊過=小龍女, 張無忌=趙敏}
        //System.out.println(map.remove("郭襄"));//null       {楊過=小龍女, 張無忌=趙敏}

        //map.clear();// {}慎重使用

        //System.out.println(map.containsKey("郭靖"));//true
        //System.out.println(map.containsKey("郭襄"));//false

        //System.out.println(map.containsValue("小龍女"));//true
        //System.out.println(map.containsValue("郭芙"));//false

        System.out.println(map.isEmpty());//false

        System.out.println(map.size());//3

        //輸出集合物件
        System.out.println(map);

Map集合的獲取功能

方法名 說明
V get(Object key) 根據鍵獲取值
Set<K> keySet() 獲取所有鍵的集合
Collection<V> values() 獲取所有值的集合
Set<Map.Empty<K,V>> entrySet() 獲取所有鍵值對物件的集合
        //創建集合物件
        Map<String, String> map = new HashMap<>();

        //添加元素
        map.put("張無忌","趙敏");
        map.put("郭靖","黃蓉");
        map.put("楊過","小龍女");

        System.out.println(map.get("張無忌"));//趙敏
        System.out.println(map.get("張三豐"));//null

        Set<String> keyset = map.keySet();
        for(String key:keyset){
            System.out.println(key);    //楊過    郭靖  張無忌
        }

        Collection<String> values = map.values();

        for (String value:values){
            System.out.println(value);  //小龍女   黃蓉  趙敏
        }

Map集合的遍歷

  • 方式1

    我們剛才存盤的元素時成對出現的,所以可以把Map看成是一個夫妻對的集合

    遍歷思路

    • 把所有的丈夫集中起來
    • 遍歷丈夫的集合,獲取到每一個丈夫
    • 根據丈夫去找對應的妻子

    轉換為Map集合中的操作:

    • 獲取所有鍵的集合,用keySet()方法實作
    • 遍歷鍵去找值,獲取到每一個鍵,用增強for實作
    • 根據鍵去找值,用get(object key)方法實作
    //創建集合物件
            Map<String, String> map = new HashMap<>();
    
            //添加元素
            map.put("張無忌","趙敏");
            map.put("郭靖","黃蓉");
            map.put("楊過","小龍女");
    
            Set<String> keySet = map.keySet();
            
            for (String key:keySet){
                String value = https://www.cnblogs.com/hackertyper/archive/2022/06/19/map.get(key);
                System.out.println(key+","+value);
            }
    
  • 方式2

    我們剛才存盤的元素時成對出現的,所以可以把Map看成是一個夫妻對的集合

    遍歷思路

    • 獲取所有結婚證的集合
    • 遍歷結婚證的集合,獲取到每一個結婚證
    • 根據結婚證去找對應的丈夫妻子

    轉換為Map集合中的操作:

    • 獲取所有鍵值對物件的集合,用entrySet()方法實作

      Set<Map.entry<K,V>> entrySet():獲取所有鍵值對物件的結合

    • 遍歷鍵值對物件的集合,獲取到每一個鍵每一個鍵值對物件

      用增強for實作,得到每一個Map.Entry

    • 根據鍵值對物件獲取值

      • 用getKey()得到鍵
      • 用getValue()得到值
     	    //創建集合物件
            Map<String, String> map = new HashMap<>();
    
            //添加元素
            map.put("張無忌", "趙敏");
            map.put("郭靖", "黃蓉");
            map.put("楊過", "小龍女");
    
            Set<Map.Entry<String, String>> entrySet = map.entrySet();
            for (Map.Entry<String, String> s : entrySet) {
                String key = s.getKey();
                String value = https://www.cnblogs.com/hackertyper/archive/2022/06/19/s.getValue();
                System.out.println(key +"," + value);
            }
    

HashMap(實作類)

實體:鍵是Student 值是String

        HashMap<String,Student> hm=new HashMap<>();

        Student s1= new Student("林青霞",30);
        Student s2= new Student("張曼玉",35);
        Student s3= new Student("王祖賢",36);

        hm.put("001",s1);
        hm.put("002",s2);
        hm.put("003",s3);

        Set<String> keySet = hm.keySet();

        for(String key:keySet){
            Student value=https://www.cnblogs.com/hackertyper/archive/2022/06/19/hm.get(key);
            System.out.println(key+","+value.getName()+','+value.getAge());
        }

        System.out.println("---------");

        Set<Map.Entry<String, Student>> entries = hm.entrySet();

        for (Map.Entry<String,Student> me:entries){
            String key=me.getKey();
            Student value=https://www.cnblogs.com/hackertyper/archive/2022/06/19/me.getValue();
            System.out.println(key+","+value.getName()+','+value.getAge());
        }

實體:鍵是String 值是Student

public class HashMapDemo {
    public static void main(String[] args) {
        HashMap<Student, String> hm = new HashMap<>();

        Student s1 = new Student("林青霞", 30);
        Student s2 = new Student("湯家鳳", 35);
        Student s3 = new Student("張曼玉", 36);
        Student s4 = new Student("張曼玉", 36);

        hm.put(s1, "西安");
        hm.put(s2, "北京");
        hm.put(s3, "重慶");
        hm.put(s3, "重慶");
        hm.put(s4, "上海");

        Set<Student> keySet = hm.keySet();

        for (Student key : keySet) {
            String value = https://www.cnblogs.com/hackertyper/archive/2022/06/19/hm.get(key);

            System.out.println(key.getName() +',' + key.getAge() + ',' + value);

        }

    }
}

public class Student {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/493004.html

標籤:其他

上一篇:4.使用CFileDialog打開檔案對話框,獲得檔案路徑 -windows編程

下一篇:google guava撰寫一個map中存盤list的示例分享

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more