Java集合框架——Map
发布日期:2021-06-30 17:59:53 浏览次数:3 分类:技术文章

本文共 28411 字,大约阅读时间需要 94 分钟。

Map

Map与Collection的不同

  • Map与Collection在集合框架中属并列存在
  • Map存储的是键值对
  • Map存储元素使用put方法,Collection使用add方法
  • Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素
  • Map集合中键要保证唯一性

    总结:Map是一个双列集合,一次存一对(键值对),而且要保证键的唯一性。

Map集合中的常用方法

Map集合中的常用方法有:

  • 添加
    • V put(K key, V value)
    • void putAll(Map<? extends K,? extends V> m)
  • 删除
    • void clear()
    • rV remove(Object key)
  • 判断
    • boolean containsKey(Object key)
    • boolean containsValue(Object value)
    • boolean isEmpty()
  • 获取
    • V get(Object key)
    • int size()
    • Collection<V> values()
    • entrySet()
    • keySet()

下面我们就来演示以上的一些方法。首先我们创建一个集合容器,使用Map接口的一个实现类——HashMap。

Map
map = new HashMap
();
  • 添加元素

    map.put("01", "zhangsan1");map.put("02", "zhangsan2");map.put("03", "zhangsan3");

    注意:添加元素时,如果出现相同的键,那么后添加的值会覆盖原有的键对应的值,并且put()方法会返回被覆盖的值。如:

    System.out.println("put:"+map.put("01", "zhangsan1")); // null,因为"01"键所对应的原来的值为nullSystem.out.println("put:"+map.put("01", "wangwu")); // zhangsan1,因为此时"01"键所对应的原来的值为"zhangsan1"
  • 判断

    System.out.println("containsKey:"+map.containsKey("022")); // containsKey:false
  • 删除

    System.out.println("remove:"+map.remove("02")); // remove:zhangsan2
  • 获取

    System.out.println("get:"+map.get("023")); // get:null

    在通过get()方法获取集合中的元素时,可以发现:

    1. 可以通过get()方法的返回值来判断一个键是否存在,通过返回null来判断
    2. HashMap允许使用null值和null,如:

      map.put("04", null); System.out.println("get:"+map.get("04")); // get:nullmap.put(null, "haha");System.out.println("get:"+map.get(null)); // get:haha
  • 获取集合中所有的值

    Collection
    coll = map.values();System.out.println(coll);

Map集合中常用类

  • Map

    • HashTable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。JDK1.0,效率低
    • HashMap:底层是哈希表数据结构,允许使用null值和null键,该集合是不同步的。JDK1.2,效率高
      • LinkedHashMap:HashMap接口的子类,该接口是哈希表和链接列表的实现,具有可预知的迭代顺序。在后面的学习中会经常用到。
    • TreeMap:底层是二叉树数据结构,线程不同步,可以给Map集合中的键进行排序。排序原理与TreeSet相同。

    Map和Set很像,其实Set底层就是使用了Map集合。

Map集合的两种取出方式

Map集合的两种取出方式:

  1. Set<K> keySet():将map所有的键存入到Set集合,因为Set集合具备迭代器,所以可以通过迭代方式取出所有的键,再根据get()方法,获取每一个键对应的值。Map集合的取出原理:将map集合转成set集合,再通过迭代器取出。
  2. Set<Map.Entry<K,V>> entrySet():将map集合中的映射关系存入到了Set集合中,而这个关系的数据类型就是:Map.Entry

现在我们就来演示Map集合的第一种取出方式。

import java.util.*;class MapDemo {    public static void main(String[] args) {        Map
map = new HashMap
(); map.put("02", "zhangsan2"); map.put("03", "zhangsan3"); map.put("01", "zhangsan1"); map.put("04", "zhangsan4"); // 先获取map集合的所有的键的Set集合,keySet() Set
ketSet = map.keySet(); // 有了Set集合,就可以获取其迭代器 Iterator
it = ketSet.iterator(); while(it.hasNext()) { String key = it.next(); // 有了键就可以通过map集合的get()方法获取其对应的值 String value = map.get(key); System.out.println("key:"+key+", value:"+value); } }}

紧接着我们再来演示Map集合的第二种取出方式。

import java.util.*;class MapDemo {    public static void main(String[] args) {        Map
map = new HashMap
(); map.put("02", "zhangsan2"); map.put("03", "zhangsan3"); map.put("01", "zhangsan1"); map.put("04", "zhangsan4"); // 将map集合中的映射关系取出,存入到set集合中 Set
> entrySet = map.entrySet(); Iterator
> it = entrySet.iterator(); while(it.hasNext()) { Map.Entry
me = it.next(); String key = me.getKey(); String value = me.getValue(); System.out.println(key+":"+value); } }}

Map.Entry,其实Entry也是一个接口,它是Map接口中的一个内部接口。源码我们可以理解为:

interface Map {    // entry就是Map接口中的内部接口    public static interface Entry {
public abstract Object getKey(); public abstract Object getValue(); }}class HashMap implements Map { class HaHa implements Map.Entry { public Object getKey() {} public Object getValue() {} }}

练习一、每一个雇员都有对应的归属地。雇员Employee,地址String。雇员属性:姓名,年龄。将雇员和归属地存储到HashMap集合中并取出,注意:姓名和年龄相同的视为同一个雇员,须保证雇员的唯一性。

解:

  1. 描述雇员,由于要将雇员对象作为键存入HashMap集合中,所以为了保证键的唯一性,雇员类中应该覆盖掉hashCode()和equals()方法。

    public class Employee {
    private String name; private int age; public Employee() { super(); } public Employee(String name, int age) { super(); 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; } @Override public String toString() { return "Employee [name=" + name + ", age=" + age + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; }}
  2. 定义Map容器,将雇员作为键,地址作为值存入。

    Map
    map = new HashMap
    ();map.put(new Employee("xiaozhang", 24), "北京");map.put(new Employee("laoli", 34), "上海");map.put(new Employee("mingming", 26), "南京");map.put(new Employee("xili", 30), "广州");map.put(new Employee("laoli", 34), "铁岭");
  3. 获取map集合中的元素,在这里我们只使用keySet()方法进行取出。

    Set
    keySet = map.keySet();for (Employee employee : keySet) { String value = map.get(employee); System.out.println(employee.getName() + ":" + employee.getAge() + "..." + value);}

练习二、现在我们又有了这样一个需求:按照雇员的年龄进行升序排序并取出。

解:因为数据是以键值对的形式存在的。所以要使用可以排序的Map集合——TreeMap。

  1. 描述雇员,为了能按照雇员的年龄进行升序排序,我们可以让自定义的Employee类实现Comparable接口(强制让Employee类具备比较性),覆盖compareTo()方法。

    public class Employee implements Comparable
    { private String name; private int age; public Employee() { super(); } public Employee(String name, int age) { super(); 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; } @Override public String toString() { return "Employee [name=" + name + ", age=" + age + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public int compareTo(Employee o) { int temp = this.age - o.age; return temp == 0 ? this.name.compareTo(o.name) : temp; }}
  2. 定义Map容器,将雇员作为键,地址作为值存入。

    Map
    map = new TreeMap
    ();map.put(new Employee("xiaozhang", 24), "北京");map.put(new Employee("laoli", 34), "上海");map.put(new Employee("mingming", 26), "南京");map.put(new Employee("xili", 30), "广州");map.put(new Employee("laoli", 34), "铁岭");
  3. 获取map集合中的元素,在这里我们只使用entrySet()方法进行取出。

    Set
    > entrySet = map.entrySet();for (Map.Entry
    me : entrySet) { Employee key = me.getKey(); String value = me.getValue(); System.out.println(key.getName() + ":" + key.getAge() + "..." + value);}

练习三、现在我们又有了这样一个需求:按照雇员的姓名进行升序排序并取出。

解:因为数据是以键值对的形式存在的。所以要使用可以排序的Map集合——TreeMap。

  1. 描述雇员,雇员类在以上练习中我们已描述,在此省略。
  2. 定义一个按姓名排序的比较器。

    Comparator
    comparator = new Comparator
    () { @Override public int compare(Employee o1, Employee o2) { int temp = o1.getName().compareTo(o2.getName()); return temp == 0 ? o1.getAge() - o2.getAge() : temp; }};
  3. 定义Map容器,将雇员作为键,地址作为值存入。

    Map
    map = new TreeMap
    (comparator);map.put(new Employee("xiaozhang", 24), "北京");map.put(new Employee("laoli", 34), "上海");map.put(new Employee("mingming", 26), "南京");map.put(new Employee("xili", 30), "广州");map.put(new Employee("laoli", 34), "铁岭");
  4. 获取map集合中的元素,在这里我们只使用entrySet()方法进行取出。

    Set
    > entrySet = map.entrySet();for (Map.Entry
    me : entrySet) { Employee key = me.getKey(); String value = me.getValue(); System.out.println(key.getName() + ":" + key.getAge() + "..." + value);}

练习四、获取字符串(比如”bwaerbctyxbacecrtdcvr”)中每一个字母出现的次数,要求结果格式为:a(2)b(1)d(3)…

解:通过结果发现,每一个字母都有对应的次数,说明字母和次数之间具有映射关系。注意:当发现有映射关系时,可以选择map集合,因为map集合中存放的就是映射关系。
本题思路:

  1. 将字符串转换为字符数组。因为要对每一个字母进行操作。
  2. 定义一个Map集合,因为打印结果的字母有顺序,所以使用TreeMap集合。
  3. 遍历字符数组,将每一个字母作为键去查map集合。如果返回null,将该字母和1存入到map集合中。如果返回不是null,说明该字母在map集合中已经存在,并有对应次数。那么就获取该次数并进行自增,然后将该字母和自增后的次数存入到map集合中,覆盖掉原来键所对应的值。
  4. 将map集合中的数据变成指定的字符串返回。
public class Test {    public static void main(String[] args) {        /*         * 作业:"bwaerbctyxbacecrtdcvr"         * 获取字符串中每一个字母出现的次数,要求结果格式:a(2)b(1)d(3)...         */        String str = "bw?aer+bct=yxb-acecrtdcvr";        String char_count = getCharCount(str);        System.out.println(char_count);    }    public static String getCharCount(String str) {        // 1,将字符串转成字符数组        char[] chs = str.toCharArray();        // 2,定义Map集合表        Map
map = new TreeMap
(); // 3,遍历字符数组,获取每一个字母 for (int i = 0; i < chs.length; i++) { // 只对字母操作 if (!(chs[i] >= 'a' && chs[i] <= 'z' || chs[i] >= 'A' && chs[i] <= 'Z')) { continue; } // 将遍历到的字母作为键去查表,获取值 Integer value = map.get(chs[i]); int count = 0; // 用于记录次数 // 如果次数存在,就用count记录该次数。如果次数不存在,就不记录,只对count自增变成1 if (value != null) { count = value; } count++; map.put(chs[i], count); /* if (value == null) { map.put(chs[i], 1); } else { value++; map.put(chs[i], value); } */ } return toString(map); } /* * 将Map集合中的元素转成指定格式的字符串。a(2)b(1)d(3)... */ private static String toString(Map
map) { // 1,数据多,无论类型是什么,最终都要变成字符串,所以可以使用StringBuilder StringBuilder sb = new StringBuilder(); // 2,遍历集合map。keySet Set
keySet = map.keySet(); for (Iterator
it = keySet.iterator(); it.hasNext();) { Character key = it.next(); Integer value = map.get(key); // 将键值存储到sb中 sb.append(key + "(" + value + ")"); } return sb.toString(); }}

结论:

问:什么时候使用Map集合呢?

答:当需求中出现映射关系时,应该最先想到Map集合。

map集合扩展知识——一对多关系

一对多的关系:一个学校有多个教室,每一个教室都有名称。一个教室有多个学生。假设学生属性:学号和姓名。

  • 学生未封装成对象时

    import java.util.*;class MapDemo {     public static void main(String[] args) {        // 首先定义一个学校        HashMap
    > czbk = new HashMap
    >(); // 接着再定义两个教室,预热班和就业班 HashMap
    yure = new HashMap
    (); HashMap
    jiuye = new HashMap
    (); // 学校和教室建立对应关系 czbk.put("yureban", yure); czbk.put("jiuyeban", jiuye); // 教室里面装有学生 yure.put("01", "zhangsan"); yure.put("02", "lisi"); jiuye.put("01", "zhaoliu"); jiuye.put("02", "wangwu"); // 遍历czbk集合,获取所有的教室 Iterator
    it = czbk.keySet().iterator(); while(it.hasNext()) { String roomName = it.next(); HashMap
    room = czbk.get(roomName); System.out.println(roomName); getStudentInfo(room); } } public static void getStudentInfo(HashMap
    roomMap) { Iterator
    it = roomMap.keySet().iterator(); while(it.hasNext()) { String id = it.next(); String name = roomMap.get(id); System.out.println(id+"::"+name); } }}
  • 学生封装成对象,这个是经常用到的。将学生封装成对象:

    class Student {    private String id;    private String name;    public Student(String id, String name) {        this.id = id;        this.name = name;    }    public String toString() {        return id + ":::" + name;    }}
    class MapDemo {    public static void demo() {        // 首先定义一个学校        HashMap
    > czbk = new HashMap
    >(); // 接着再定义两个教室,预热班和就业班,注意此时使用的是List集合 List
    yure = new ArrayList
    (); List
    jiuye = new ArrayList
    (); // 学校和教室建立对应关系 czbk.put("yureban", yure); czbk.put("jiuyeban", jiuye); // 教室里面装有学生 yure.add(new Student("01", "zhangsan")); yure.add(new Student("04", "wangwu")); jiuye.add(new Student("01", "zhouqi")); jiuye.add(new Student("02", "zhaoliu")); Iterator
    it = czbk.keySet().iterator(); while(it.hasNext()) { String roomName = it.next(); List
    room = czbk.get(roomName); System.out.println(roomName); getInfos(room); } } public static void getInfos(List
    list) { Iterator
    it = list.iterator(); while(it.hasNext()) { Student s = it.next(); System.out.println(s); } } public static void main(String[] args) { demo(); }}

集合框架中的工具类

Collections

Collections类中定义的都是操作Collection的静态方法。

Collections常见方法

  • sort()

    • public static <T extends Comparable<? super T>> void sort(List<T> list):根据元素的自然顺序对指定列表按升序进行排序,列表中的所有元素都必须实现Comparable接口。

      public static void methodDemo1() {    List
      list = new ArrayList
      (); list.add("abce"); list.add("z"); list.add("hehe"); list.add("nba"); System.out.println(list); // 对list排序,自然排序使用的是元素的compareTo方法 Collections.sort(list); System.out.println(list);}

      以上是使用Collections类中的sort()方法对List集合进行排序,而且使用的是自然排序。但现在我们想要按照字符串的长度进行排序,那又该如何做呢?这时需要用到下面的方法。

    • public static <T> void sort(List<T> list, Comparator<? super T> c):根据指定比较器产生的顺序对指定列表进行排序。此列表内的所有元素都必须可使用指定比较器相互比较。

      很显然,这时我们需要自定义一个比较器,使得比较是按照字符串的长度来排序的。

      public class ComparatorByLength implements Comparator
      {
      @Override public int compare(String o1, String o2) { int temp = o1.length() - o2.length(); return temp == 0 ? o1.compareTo(o2) : temp; }}

      测试方法为:

      public static void methodDemo1() {    List
      list = new ArrayList
      (); list.add("abce"); list.add("z"); list.add("hehe"); list.add("nba"); System.out.println(list); // 想按照长度排序 Collections.sort(list, new ComparatorByLength()); System.out.println(list);}
  • max()

    • public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll):根据元素的自然顺序,返回给定Collection的最大元素。Collection中的所有元素都必须实现Comparable接口。

      示例代码如下:

      public static void maxDemo() {    List
      list = new ArrayList
      (); list.add("abcd"); list.add("aaa"); list.add("zz"); list.add("kkkkk"); list.add("qq"); list.add("z"); Collections.sort(list); // 可以看出元素的自然顺序结果 System.out.println(list); String max = Collections.max(list); System.out.println("max="+max);}

      但现在要让我们自己模拟一个获取集合最大值的功能,那又该怎么做呢?直接贴出代码如下:

      /** * 模拟一个获取集合最大值的功能 */public static 
      > T getMax(Collection
      coll) { Iterator
      it = coll.iterator(); // 1,定义变量记录容器中的其中一个。 T max = it.next(); // 2,遍历容器所有的元素 while (it.hasNext()) { T temp = it.next(); // 3,在遍历的过程中进行比较,只要比变量中的值大,就用变量记录下来。 if (temp.compareTo(max) > 0) { max = temp; } } return max;}

      我们查看Java源代码,发现它写的和我们写的一模一样。

    • public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp):根据指定比较器产生的顺序,返回给定Collection的最大元素。Collection中的所有元素都必须可通过指定比较器相互比较。

      首先,我们先自定义一个比较器——ComparatorByLength.java。

      public class ComparatorByLength implements Comparator
      {
      @Override public int compare(String o1, String o2) { int temp = o1.length() - o2.length(); return temp == 0 ? o1.compareTo(o2) : temp; }}

      我们的测试代码为:

      public class CollectionsDemo {    public static void main(String[] args) {        Collection
      coll = new ArrayList
      (); coll.add("abcd"); coll.add("aa"); coll.add("z"); coll.add("nba"); String max = Collections.max(coll, new ComparatorByLength()); System.out.println("max = " + max); }}
  • binarySearch()

    • public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key):使用二分搜索法搜索指定列表,以获得指定对象。在进行此调用之前,必须根据列表元素的自然顺序对列表进行升序排序(通过sort(List)方法)。如果搜索键包含在列表中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。

      示例代码如下:

      public static void binarySearchDemo() {    List
      list = new ArrayList
      (); list.add("abcd"); list.add("aaa"); list.add("zz"); list.add("kkkkk"); list.add("qq"); list.add("z"); Collections.sort(list); System.out.println(list); int index = Collections.binarySearch(list, "aaa"); System.out.println("index="+index); // index=0}

      其内部原理是:

      public static int halfSearch(List
      list, String key) { int max, min, mid; max = list.size() - 1; min = 0; while(min <= max) { mid = (max + min) >> 1; // /2 String str = list.get(mid); int num = str.compareTo(key); if(num > 0) max = mid - 1; else if(num < 0) min = mid + 1; else return mid; } return -min-1;}

      现在我们调用halfSearch方法:

      public static void binarySearchDemo() {    List
      list = new ArrayList
      (); list.add("abcd"); list.add("aaa"); list.add("zz"); list.add("kkkkk"); list.add("qq"); list.add("z"); Collections.sort(list); System.out.println(list); int index = halfSearch(list, "aaaa"); System.out.println("index="+index); // index=-2}
    • public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c):使用二分搜索法搜索指定列表,以获得指定对象。在进行此调用之前,必须根据指定的比较器对列表进行升序排序(通过sort(List, Comparator) 方法)。

      首先,我们先自定义一个比较器——ComparatorByLength.java。

      public class ComparatorByLength implements Comparator
      {
      @Override public int compare(String o1, String o2) { int temp = o1.length() - o2.length(); return temp == 0 ? o1.compareTo(o2) : temp; }}

      然后编写我们的测试方法:

      public static void binarySearchDemo() {    List
      list = new ArrayList
      (); list.add("abcd"); list.add("aaa"); list.add("zz"); list.add("kkkkk"); list.add("qq"); list.add("z"); Collections.sort(list, new StrLenComparator()); System.out.println(list); int index = Collections.binarySearch(list, "aaa", new StrLenComparator()); System.out.println("index="+index); // index=3}

      其内部原理是:

      public static int halfSearch(List
      list, String key, Comparator
      cmp) { int max, min, mid; max = list.size() - 1; min = 0; while(min <= max) { mid = (max + min) >> 1; // /2 String str = list.get(mid); int num = cmp.compare(str, key); if(num > 0) max = mid - 1; else if(num < 0) min = mid + 1; else return mid; } return -min-1;}

      现在来测试我们编写的方法,调用halfSearch方法的代码:

      public static void binarySearchDemo() {    List
      list = new ArrayList
      (); list.add("abcd"); list.add("aaa"); list.add("zz"); list.add("kkkkk"); list.add("qq"); list.add("z"); Collections.sort(list, new ComparatorByLength()); System.out.println(list); int index = halfSearch(list, "cc", new ComparatorByLength()); System.out.println("index="+index); // index=-2}
  • public static <T> void fill(List<? super T> list, T obj):使用指定元素替换指定列表中的所有元素。

    示例代码如下:

    public static void fillDemo() {    List
    list = new ArrayList
    (); list.add("abcd"); list.add("aaa"); list.add("zz"); list.add("kkkkk"); System.out.println(list); Collections.fill(list,"pp"); System.out.println(list);}

    练习、复写fill(),将list集合中部分元素替换成指定元素。

    public static void fillDemo() {    List
    list = new ArrayList
    (); list.add("abcd"); list.add("aaa"); list.add("zz"); list.add("kkkkk"); System.out.println(list); fill(list, 1, 3, "hello"); System.out.println(list);}public static void fill(List
    list, int start, int end, String str) { for(int i = start; i < end; i++) { list.set(i, str); } }
  • public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal):使用另一个值替换列表中出现的所有某一指定值。

    示例代码如下:

    public static void replaceAllDemo() {    List
    list = new ArrayList
    (); list.add("abcd"); list.add("aaa"); list.add("zz"); list.add("kkkkk"); System.out.println(list); Collections.replaceAll(list, "aaa", "pp"); System.out.println(list);}
  • public static void reverse(List<?> list):反转指定列表中元素的顺序。

    示例代码如下:

    public static void replaceAllDemo() {    List
    list = new ArrayList
    (); list.add("abcd"); list.add("aaa"); list.add("zz"); list.add("kkkkk"); System.out.println(list); Collections.reverse(list); System.out.println(list);}
  • reverseOrder()

    • public static <T> Comparator<T> reverseOrder():返回一个比较器,它强行逆转实现了Comparable接口的对象Collection的自然顺序。

      我们首先按照字符串的自然顺序排序:

      public static void orderDemo() {    TreeSet
      ts = new TreeSet
      (); ts.add("abcde"); ts.add("aaa"); ts.add("k"); ts.add("cc"); Iterator it = ts.iterator(); while(it.hasNext()) { System.out.println(it.next()); }}

      接下来,我们要反转其自然排序:

      public static void orderDemo() {    TreeSet
      ts = new TreeSet
      (Collections.reverseOrder()); ts.add("abcde"); ts.add("aaa"); ts.add("k"); ts.add("cc"); Iterator it = ts.iterator(); while(it.hasNext()) { System.out.println(it.next()); }}

      当然了,我们可以使用比较器来做。首先我们定义一个反转字符串的自然顺序的比较器:

      public class StrComparator implements Comparator
      {
      public int compare(String s1, String s2) { // 这样写太繁琐 /* int num = s1.compareTo(s2); if(num > 0) return -1; if(num < 0) return 1; return num; */ return s2.compareTo(s1); // 简写 }}

      然后我们调用此比较器:

      public static void orderDemo() {    TreeSet
      ts = new TreeSet
      (new StrComparator()); ts.add("abcde"); ts.add("aaa"); ts.add("k"); ts.add("cc"); Iterator it = ts.iterator(); while(it.hasNext()) { System.out.println(it.next()); }}
    • public static <T> Comparator<T> reverseOrder(Comparator<T> cmp):返回一个比较器,它强行逆转指定比较器的顺序。

      我们首先定义一个按照字符串的长度排序的比较器:

      public class ComparatorByLength implements Comparator
      {
      @Override public int compare(String o1, String o2) { int temp = o1.length() - o2.length(); return temp == 0 ? o1.compareTo(o2) : temp; }}

      接着,我们按照字符串的长度排序:

      public static void orderDemo() {    TreeSet
      ts = new TreeSet
      (new ComparatorByLength()); ts.add("abcde"); ts.add("aaa"); ts.add("k"); ts.add("cc"); Iterator it = ts.iterator(); while(it.hasNext()) { System.out.println(it.next()); }}

      最后,我们反转其顺序:

      public static void orderDemo() {    TreeSet
      ts = new TreeSet
      (Collections.reverseOrder(new StrLenComparator())); ts.add("abcde"); ts.add("aaa"); ts.add("k"); ts.add("cc"); Iterator it = ts.iterator(); while(it.hasNext()) { System.out.println(it.next()); }}
  • public static void shuffle(List<?> list):使用默认随机源对指定列表进行置换。所有置换发生的可能性都是大致相等的。

    示例代码为:

    public static void shuffleDemo() {    List
    list = new ArrayList
    (); list.add("abcd"); list.add("aaa"); list.add("zz"); list.add("kkkkk"); list.add("qq"); list.add("z"); System.out.println(list); Collections.shuffle(list); System.out.println(list);}
  • swap(List<?> list, int i, int j):在指定列表的指定位置处交换元素。(如果指定位置相同,则调用此方法不会更改列表。)

    示例代码:

    public static void sortDemo() {    List
    list = new ArrayList
    (); list.add("abcd"); list.add("aaa"); list.add("zz"); list.add("kkkkk"); list.add("qq"); list.add("z"); System.out.println(list); Collections.swap(list, 1, 2); System.out.println(list);}
  • Collections还有一个可以将非同步集合转成同步集合的方法
    • 同步集合 synchronized集合(非同步的集合)

Arrays

Arrays:用于操作数组的工具类。里面都是静态方法。

Arrays的2个常见方法

  • toString():返回指定数组内容的字符串表示形式。

    int[] arr = {
    2, 4, 5};System.out.println(Arrays.toString(arr));
  • public static <T> List<T> asList(T... a):返回一个受指定数组支持的固定大小的列表。

    String[] strs = {
    "abc", "haha", "nba", "zz"};List
    list = Arrays.asList(strs);// list.add("qq"); // 会发生java.lang.UnsupportedOperationException,注意不能使用集合的增删方法,即不能改变长度。System.out.println(list.contains("nba"));

    那么问题就来了,把数组变成List集合有什么好处?

    答:可以使用集合的思想和方法来操作数组中的元素。但要注意:将数组变成集合,不可以使用集合的增删方法。因为数组的长度是固定的。可以使用集合的诸如contains()get()indexOf()subList()等等方法,如果你增删,那么会生成UnsupportedOperationException

    再看下面一段代码:

    int[] nums = {2, 4, 5};List li = Arrays.asList(nums);System.out.println(li);

    此时将会输出[[I@139a55]类似结果,以上代码没有使用泛型,使用泛型应是如此:

    int[] nums = {
    2, 4, 5};List
    li = Arrays.asList(nums);System.out.println(li);

    如果代码修改为:

    Integer[] nums = {
    2,4,5};List
    li = Arrays.asList(nums);System.out.println(li);

    此时输出[2, 4, 5]。所以,得出结论:如果数组中的元素都是引用数据类型,那么变成集合时,数组中的元素就直接转成集合中的元素。如果数组中的元素都是基本数据类型,那么会将该数组([I@139a55)对象作为集合中的元素存在。

集合变数组:Collections接口中的toArray()方法

例,Collections接口中的toArray()方法的应用。

import java.util.*;class CollectionToArray {    public static void main(String[] args) {        ArrayList
al = new ArrayList
(); al.add("abc1"); al.add("abc2"); al.add("abc3"); String[] arr = al.toArray(new String[al.size()]); System.out.println(Arrays.toString(arr)); }}
  1. 指定类型的数组到底要定义多长呢?
    当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组,长度为集合的size。当指定类型的数组长度大于了集合的size,那么就不会新创建数组,而是使用传递进来的数组。所以创建一个刚刚好的数组最优。
  2. 为什么要将集合变数组?
    为了限定对元素的操作,不需要进行增删了。

JDK1.5新特性

高级for循环

高级for循环的作用:用于遍历Collection集合或数组。

格式:

for(数据类型(一般是泛型类型) 变量名 : 被遍历的集合(Collection)或者数组) {}

例,遍历集合。

ArrayList
al = new ArrayList
();al.add("abc1");al.add("abc2");al.add("abc3");

之前我们使用迭代器遍历:

Iterator
it = al.iterator();while(it.hasNext()) { System.out.println(it.next());}

现在我们可使用高级For循环了,主要就是为了简化书写。

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

结论:

高级for循环对集合进行遍历,只能获取集合中的元素,但是不能对集合进行操作。迭代器除了遍历,还可以进行remove()集合中元素的动作,如果使用ListIterator,还可以在遍历过程中对集合进行增删改查的操作。

对于数组int[] arr = {3,5,1};,我们可使用传统for循环:

for (int x = 0; x < arr.length; x++) {    System.out.println(arr[x]);}

还可使用高级for循环:

for (int i : arr) {    System.out.println("i:"+i);}

问:传统for和高级for有什么区别呢?

答:高级for有一个局限性,必须有被遍历的目标,而该目标只能是Collection或数组。
建议:在遍历数组的时候还是希望使用传统for,因为传统for可以定义角标。

对于Map集合,我们也可以使用高级for循环。

HashMap
hm = new HashMap
();hm.put(1, "a");hm.put(2, "b");hm.put(3, "c");

第一种遍历方式:

Set
keySet = hm.keySet();for (Integer i : keySet) { System.out.println(i+"::"+hm.get(i));}

第二种遍历方式:

for (Map.Entry
me : hm.entrySet()) { System.out.println(me.getKey()+"---"+me.getValue());}

可变参数

JDK1.5版本出现的新特性。可变参数其实就是一种数组参数的简写形式,不用每一次都手动的建立数组对象,只要将要操作的元素作为参数传递即可,隐式地将这些参数封装成了数组。

class ParamMethodDemo {    public static void main(String[] args) {        show("gaga",2,3,4,5,6);    }    public static void show(String str, int... arr) {        System.out.println(arr.length);    }}

注意:方法的可变参数在使用时,可变参数一定要定义在参数列表的最后面。

静态导入

例,

import java.util.*;import static java.util.Arrays.*; // 导入的是Arrays类中的所有静态成员。import static java.lang.System.*; // 导入了System类中所有静态成员。class StaticImport extends Object {    public static void main(String[] args) {        out.println("hello");        int[] arr = {
3,1,5}; sort(arr); int index = binarySearch(arr, 1); System.out.println(Arrays.toString(arr)); // 此时不能省略Arrays,方法重名时,指定具备所属的对象或类。 System.out.println("index="+index); }}

注意:

  1. 当类名重名时,需要指定具体的包名。
  2. 当方法重名时,指定具备所属的对象或类。

转载地址:https://liayun.blog.csdn.net/article/details/54188414 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:常用API(一)——String、StringBuffer与基本类型包装类
下一篇:泛型基础

发表评论

最新留言

感谢大佬
[***.8.128.20]2024年05月04日 04时56分04秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章