Java基礎(六)——TreeSet、Comparable、泛型、Map、Collections

TreeSet集合

TreeSet集合特點

  • 元素有序,這裏的順序不是指存儲和取出的順序,而是按照一定的規則進行排序,具體排序方式取決於構造方法
    • TreeSet():根據其元素的自然排序進行排序
    • TreeSet(Comparator comparator) :根據指定的比較器進行排序
  • 沒有帶索引的方法,所以不能使用普通for循環遍歷
  • 由於是Set集合,所以不包含重複元素的集合

 

自然排序Comparable的使用

●存儲學生對象並遍歷, 創建TreeSet集合使用無參構造方法
要求:按照年齡從小到大排序,年齡相同時,按照姓名的字母順序排序

  • public interface Comparable<T>
    該接口對實現它的每個類的對象強加一個整體排序。 這個排序被稱爲類的自然排序 ,類的compareTo方法被稱爲其自然比較方法

    Collections.sort (和Arrays.sort )可以自動對實現此接口的對象進行列表(和數組)排序。 實現該接口的對象,可以使用如在鍵sorted map或作爲在元件sorted set ,而不需要指定一個comparator

    一類C的自然順序被說成是與equals一致當且僅當e1.compareTo(e2) == 0對每一個e1和C類e2相同的布爾值e1.equals(e2)。 請注意, null不是任何類的實例, e.compareTo(null)應該拋出一個NullPointerException即使e.equals(null)返回false 。

例子:


public class Student implements Comparable<Student>{
    private String name;
    private int age;

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

    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;
    }
    //重寫接口Comparable的方法,爲了集合中能夠按照年齡進行排序
    @Override
    public int compareTo(Student o) {
        //年齡從小到大來排序
        int num = this.age - o.age;
        //年齡相同時,按字母的順序進行排序
        int num2 = num==0?this.name.compareTo(o.name):num;
        return num2;
    }
}
public class SetDemo {
    public static void main(String[] args) {
        TreeSet<Student> st = new TreeSet<Student>();

        Student s1 = new Student("zhangsan",32);
        Student s2 = new Student("lisi",31);
        Student s3 = new Student("hejin",37);
        Student s4 = new Student("daoming",35);
        Student s5 = new Student("xiaohan",27);
        Student s6 = new Student("feizi",31);

        st.add(s1);
        st.add(s2);
        st.add(s3);
        st.add(s4);
        st.add(s5);
        st.add(s6);
        for(Student i:st){
            System.out.println(i.getName() + ":" + i.getAge());
        }

    }
}

效果:

 

結論

  • 用TreeSet集合存儲自定義對象, 無參構造方法使用的是自然排序對元素進行排序的
  • 自然排序, 就是讓元素所屬的類實現Comparable接口,重寫compareTo(T o)方法
  • 重寫方法時, - 定要注意排序規則必須按照要求的主要條件和次要條件來寫
     

實現不重複的隨機數

public class ListDemo {
    public static void main(String[] args) {
//        Set<Integer> s = new HashSet<Integer>();
        //會自然排序
        Set<Integer> s = new TreeSet<Integer>();
        //隨機數對象
        Random r = new Random();
        //集合數量不大於10
        while (s.size()<10){
            int num = r.nextInt(21);
            s.add(num);
        }
        for (int i:s) {
            System.out.println(i);
        }
    }
}

 

泛型

泛型概述

泛型:是JDK5中引入的特性,它提供了編譯時類型安全檢測機制,該機制允許在編譯時檢測到非法的類型
它的本質是參數化類型,也就是說所操作的數據類型被指定爲一個參數
一提到參數, 最熟悉的就是定義方法時有形參,然後調用此方法時傳遞實參。那麼參數化類型怎麼理解呢?
顧名思義,就是將類型由原來的具體的類型參數化,然後在使用/調用時傳入具體的類型
這種參數類型可以用在類、方法和接口中,分別被稱爲泛型類、泛型方法、泛型接口

泛型定義格式:

  • <類型>: 指定一種類型的格式。這裏的類型可以看成是形參
  • <類型1,類型2...>:指定多種類型的格式,多種類型之間用逗號隔開。這裏的類型可以看成是形參
  • 將來具體調用時候給定的類型可以看成是實參,並且實參的類型只能是引用數據類型

例子:

Collection c = new ArrayList();
//使用泛型解決int和string混雜集合
Collection<String> c = new ArrayList<String>();

泛型的好處:

  • 把運行時期的問題提前到了編譯期間
  • 避免了強制類型轉換

 

泛型類

例子:

public class Generic<T> {
    private T t;

    public T getT() {
        return t;
    }
    public void setT(T t) {
        this.t = t;
    }
}
public class ListDemo {
    public static void main(String[] args) {
        Generic<String> s = new Generic<>();
        s.setT("水滸");
        System.out.println(s.getT());

        Generic<Integer> n = new Generic<>();
        n.setT(100);
        System.out.println(s.getT());
    }
}

結果:

 

泛型方法

public class Generic {
    public <T> void show(T t){
        System.out.println(t);
    }
}
public class ListDemo {
    public static void main(String[] args) {
        Generic g = new Generic();
        g.show("李牧");
        g.show(100);
        g.show(true);
        g.show(12.56);
    }
}

結果:

 

類型通配符

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

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

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

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

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

  • 類型通配符 下限: <?super 類型>
  • List<? super Number>:它表示的類型是Number或者其父類型

 

例子:

public class ListDemo {
    public static void main(String[] args) {
        //類型通配符: <?>
        List<?> list1 = new ArrayList<Object>();
        List<?> list2 = new ArrayList<Number>();
        List<?> list3 = new ArrayList<Integer>();
        //類型通配符上限: <? extends類型>
        List<? extends Number> list4 = new ArrayList<Integer>();
        //類型通配符 下限: <?super 類型>
        List<? super Number> list5 = new ArrayList<Object>();
    }
}

 

可變參數

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

  • 格式:修飾符返回值類型方法名(數據類型..變量名{ }
  • 範例: public static int sum(int...a){ }

例子:

public class ListDemo {
    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,50));
    }
    public static int Sum(int ...a){
        //將數據變成了一個數組,輸出a是數組地址
        System.out.println(a);
        int sum=0;
        for(int i:a){
            sum+=i;
        }
       return sum;
    }
}

結果:

 

Map

  • public interface Map<K,V>
    將鍵映射到值的對象。 地圖不能包含重複的鍵; 每個鍵可以映射到最多一個值。

    這個接口取代了Dictionary類,它是一個完全抽象的類而不是接口。

    Map界面提供了三個集合視圖 ,允許將映射內容視爲一組鍵,值集合或鍵值映射集合。 地圖的順序被定義爲其中在地圖上的集合視圖迭代返回元素的順序。 一些地圖實現,如TreeMap課程,對他們的訂單做出了具體的保證; 其他人,像HashMap班,不要。

    注意:如果使用可變對象作爲地圖鍵,必須非常小心。 如果對象的值以影響equals比較的方式更改,而對象是地圖中的鍵,則不會指定地圖的行爲。 這個禁令的一個特殊情況是,地圖不允許將自己包含在內。 雖然地圖可以將其本身作爲一個值,但建議您非常小心: equals和hashCode方法在這樣的地圖上已經不太明確。

    所有通用映射實現類應提供兩個“標準”構造函數:一個創建空映射的void(無參數)構造函數,以及一個具有類型爲Map的單個參數的構造函數 ,它創建一個具有相同鍵值的新映射映射作爲參數。 實際上,後一個構造函數允許用戶複製任何地圖,產生所需類的等效地圖。 沒有辦法強制執行此建議(因爲接口不能包含構造函數),而JDK中的所有通用映射實現都符合要求。

創建Map集合的對象

  • 多態的方式
  • 具體的實現類HashMap

 

例子:(注意在map中鍵是唯一的)

import java.util.HashMap;
import java.util.Map;

public class MapDemo {
    public static void main(String[] args) {
        //創建map集合對象
        Map<String,String> map = new HashMap<String,String>();

        //添加對象使用put方法
        map.put("map1","天地");
        map.put("map2","玄黃");
        map.put("map3","宇宙");
        map.put("map4","洪荒");
        System.out.println(map);
    }
}

結果:

Map集合的遍歷:

  1. 獲取所有鍵值對對象的集合
    1. Set<Map. Entry<K,V>> entrySet(): 獲取所有鍵值對對象的集合
  2. 遍歷鍵值對對象的集合,得到每一個鍵值對對象
    1. 用增強for實現,得到每一個Map.Entry
  3. 根據鍵值對對象獲取鍵和值
    1. 用getKey()得到鍵
    2. 用getValue()得到值

例子:

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapDemo {
    public static void main(String[] args) {
        //創建map集合對象
        Map<String,String> map = new HashMap<String,String>();

        //添加對象使用put方法
        map.put("map1","天地");
        map.put("map2","玄黃");
        map.put("map3","宇宙");
        map.put("map4","洪荒");
        //獲取所有鍵值集合的對象
        Set<Map.Entry<String,String>> entrySet = map.entrySet();
        //遍歷鍵值對象的集合,得到每一個簡直對象
        for(Map.Entry<String,String> i:entrySet){
            //根據鍵值對象獲取鍵和值
            String key = i.getKey();
            String value = i.getValue();
            System.out.println(key+":"+value);
        }
    }
}

結果:

HashMap嵌套ArrayList

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapDemo {
    public static void main(String[] args) {
        //創建HashMap集合
        HashMap<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>();
        //創建Arraylist集合,並添加元素
        ArrayList<String> sgyy = new ArrayList<String>();
        sgyy . add( "諸葛亮");
        sgyy. add("趙雲");
        //把ArrayL ist作爲元素添加到HashMap集合
        hm. put("三國演義" ,sgyy);
        ArrayList<String> xyj = new ArrayList<String>();
        xyj. add("唐僧");
        xyj. add("孫悟空");
        //把ArrayL ist作爲元素添加到HashMap集合
        hm. put("西遊記",xyj);
        ArrayList<String> shz = new ArrayList<String>();
        shz . add("武松");
        shz.add("魯智深");
        //把ArrayL ist作爲元素添加到HashMap集合
        hm. put("水滸傳",shz);
        //遍歷HashMap集合
        Set<String> keySet = hm. keySet();
        for(String key : keySet) {
            System.out.println(key);
            ArrayList<String> value = hm.get(key);
            for (String s : value) {
                System.out.println("\t" + s);
            }
        }
    }
}

結果:

案例: 統計字符串中每個字符出現的次數

需求:鍵盤錄入一個字符串,要求統計字符串中每個字符串出現的次數。
舉例:鍵盤錄入"aababcabcdabcde"
在控制檯輸出: "a(5)b(4)c(3)d(2)e(1)"
思路:

  • ①鍵盤錄入一個字符串
  • ②創建HashMap集合,鍵是Character, 值是Integer
  • ③遍歷字符串,得到每一個字符
  • ④拿得到的每一個字符作爲鍵 到HashMap集合中去找對應的值,看其返回值
    • 如果返回值是null:說明該字符在HashMap集合中不存在,就把該字符作爲鍵,1作爲值存儲
    • 如果返回值不是null:說明該字符在HashMap集合中存在,把該值加1,然後重新存儲該字符和對應的值
  • ⑤遍歷HashMap集合,得到鍵和值,按照要求進行拼接
  • ⑥輸出結果

代碼:

public class MapDemo {
    public static void main(String[] args) {
        //鍵盤錄入一個字符串
        Scanner sc = new Scanner(System. in);
        System.out.println("請輸入一個字符串: ");
        String line = sc.nextLine();
        //創建HashMap集合,鍵是Character, 值是Integer
        HashMap<Character, Integer> hm = new HashMap<Character, Integer>();
        //遍歷字符串,得到每一個字符
        for (int i = 0; i < line.length(); i++) {
            char key = line.charAt(i);
            //拿得到的每一個字符作爲鍵到HashMap集合中去找對應的值,看其返回值
            Integer value = hm.get(key);
            if (value == null) {
                //如果返回值是null: 說明該字符在HashMap集合中不存在,就把該字符作爲鍵,1作爲值存儲
                hm.put(key, 1);
            } else {
                //如果返回值不是null:說明該字符在HashMap集合中存在,把該值加1,然後重新存儲該字符和對應的值
                value++;
                hm.put(key, value);
            }
        }

        //遍歷HashMap集合,得到鍵和值,按照要求進行拼接
        StringBuilder sb = new StringBuilder();
        Set<Character> keySet = hm.keySet();
        for(Character key : keySet) {
            Integer value = hm. get(key);
            sb.append(key).append("(").append(value).append(")");
        }
        System.out.println(sb);
    }
}

結果:

 

Collections

  • public class Collections
    extends Object
    此類僅由靜態方法組合或返回集合。 它包含對集合進行操作的多態算法,“包裝器”,返回由指定集合支持的新集合,以及其他一些可能的和最終的。

    如果提供給它們的集合或類對象爲null,則此類的方法都拋出一個NullPointerException 。

    該類中包含的多態算法的文檔通常包括實現的簡要說明 。 這些描述應被視爲實施說明 ,而不是說明書的一部分 。 只要規範本身得到遵守,實現者就可以隨意替代其他算法。 (例如,sort使用的算法不一定是一個mergeesort,但它必須是穩定的 。)

Collections類的概述

  • 是針對集合操作的工類

Collections類的常用方法

  • public static <T extends Comparable<? super T>> void sort(List<T> list): 將指定的列表按升序排序
  • public static void reverse(List<?> list): 反轉指定列表中元素的順序
  • public static void shuffle(List<?> list):使用默認的隨機源隨機排列指定的列表

例子:

public class MapDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        //添加元素
        list.add(30);
        list.add(20);
        list.add(50);
        list.add(10);
        list.add(40);
        //public static <T extends Comparable<? super T>> void sort (List<T> list): 將指定的列表按升序排序
        Collections.sort(list);
        //public static void reverse (List<?> list): 反轉指定列表中元素的順序
        Collections.reverse(list);
        //public static void shuffle (List<?> list): 使用默認的隨機源隨機排列指定的列表
        //Collections.shuffle(list);
        System.out.println(list);
    }
}

結果:

 

 

 

 

 

一起學習,一起進步 -.- ,如有錯誤,可以發評論

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