集合

1   集合

1.1   为什么要使用集合框架?

传统的容器(数组)在进行增、删等破坏性操作时,需要移动元素,可能导致性能问题;同时添加、删除等算法和具体业务耦合在一起,增加了程序开发的复杂度。

 

Java集合框架提供了一套性能优良、使用方便的接口和类,它们位于java.util包中

 

1.2   Collection

Collection是java集合框架(collection-frame)中的顶层接口。

Collection接口表示一个容器,容器中只能存储引用数据类型,建议存同一类型的引用类型,方便后续遍历等操作。

容器中的元素可以是有序的、可重复的,称为List接口

也可能是无序的、唯一的,称为Set接口。

 

 

 

 

1.2.1     集合常用方法

public static void main(String[] args) {

        

         /**

          * 增:add/addAll

          * 删:clear/remove/removeAll/retainAll

          * 改:

          * 查:contains/containsAll/isEmpty/size

          */

        

         Collection c1 = new ArrayList();

        

         // 追加

         c1.add("apple"); // Object object = new String("apple");

         // c1.add(1);      // Object object = new Integer(1);

         c1.add("banana");

         System.out.println(c1);

        

         // 追加一个集合

         Collection c2 = new ArrayList();

         c2.add("java");

         c2.add("c++");

         c1.addAll(c2);

         System.out.println(c1);

        

         // clear

         //c1.clear();

        

         // c1.remove("apple");

         // c1.removeAll(c2);

         //c1.retainAll(c2);

         //System.out.println(c1);

        

         System.out.println(c1.contains("apple"));

         c2.add("js");

         System.out.println(c1.containsAll(c2));

         // c1.clear();

         System.out.println(c1.isEmpty());

         // 返回集合元素的个数

         System.out.println(c1.size());

        

         System.out.println(c1.equals(c2));

        

     }

 

1.2.2     集合的遍历

Iterable 可遍历的接口,集合接口继承于它,集合支持快速遍历。

// 快速遍历

         // for-each

         // Object 表示元素类型

         // item表示迭代变量

         // c1表示集合

         for (Object item : c1) {

              System.out.println(item.toString());

         }

 

快速遍历的本质

Collection继承Iterable接口,表示集合支持快速遍历。Iterable接口定义了一个方法iterator()用于获取集合的迭代器,是一个Iterator接口类型,iterator()内部返回一个实现类实现类Iterator接口。这个实现类一定具有hasNext和next方法用于判断是否有下一个元素和获取下一个元素。快速遍历就是基于迭代器工作的。

 

public static void main(String[] args) {

        

 

         Collection c1 = new ArrayList();

         c1.add("apple");

         c1.add("banana");

         c1.add("coco");

        

        

         // 快速遍历

         // for-each

         // Object 表示元素类型

         // item表示迭代变量

         // c1表示集合

         for (Object item : c1) {

              System.out.println(item.toString());

         }

        

         // 迭代器遍历(国内)

         Iterator it = c1.iterator();

         while(it.hasNext()) {

              Object item = it.next();

              System.out.println(item.toString());

         }

        

         // 国外

         for(Iterator it2=c1.iterator();it2.hasNext();) {

              Object item = it2.next();

              System.out.println(item.toString());

         }   

     }

 

 

 

 

1.3   List接口

List 接口中的元素时有序的、可重复的。List接口中的元素通过索引(index)来确定元素的顺序。

有序的 collection(也称为序列)。可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素

 

1.3.1     List常用方法

public static void main(String[] args) {

        

         /**

          * 增:add/addAll/add(index,el)/addAll(index,collection)

          * 删:clear/remove/removeAll/remove(index)

          * 改:set(index,el)

          * 查:get(index)/indexOf/lastIndexOf()

          * 其他:contains/containsAll/isEmpty/size

          */

         List list1 = new ArrayList();

         // 添加元素

         list1.add("apple");

         list1.add("banana");

         // 在指定位置添加元素

         list1.add(0, "coco");

        

         System.out.println(list1);

        

         List list2 = new ArrayList();

         list2.add("java");

         list2.add("c++");

        

         list1.addAll(1, list2);

         System.out.println(list1);

        

         // 删除

          list1.remove(0);

         System.out.println(list1);

        

         // 修改

         list1.set(0, "javax");

         System.out.println(list1);

        

         // 查

         System.out.println(list1.get(0));

         list1.add("apple");

         list1.add("apple");

         System.out.println(list1);

         System.out.println(list1.indexOf("apple"));

         System.out.println(list1.lastIndexOf("apple"));

     }

 

1.3.2     List接口遍历

ListIterator 继承于Iterator,在Iterator的基础上提供了以正向遍历集合,也可以以逆序遍历集合。

hasNext/next 以正向遍历

hasPrevious/previous 以逆序遍历

 

public static void main(String[] args) {

        

        

         List list1 = new ArrayList();

         list1.add("apple");

         list1.add("banana");

         list1.add("coco");

        

         // 【1】快速遍历

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

         for (Object item : list1) {

              System.out.println(item.toString());

         }

        

         // 【2】普通for

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

         for(int i=0;i<list1.size();i++) {

              System.out.println(list1.get(i));

         }

        

         // 【3】集合迭代器

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

         Iterator it = list1.iterator();

         while(it.hasNext()) {

              System.out.println(it.next());

         }

        

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

         // 正向遍历

         ListIterator it2 = list1.listIterator();

         while(it2.hasNext()) {

              System.out.println(it2.next());

         }

        

         // 逆序遍历

         while(it2.hasPrevious()) {

              System.out.println(it2.previous());

         }

        

         System.out.println("--list iterator with index--");

         ListIterator it3 = list1.listIterator(1);

         while(it3.hasNext()) {

              System.out.println(it3.next());

         }

     }

 

 

 

 

1.4   数据结构(补充)

数据结构就是数据在内存中存储结构。根据存储的方式不同,分为线性表、二叉树、图、栈、队列等

 

1.4.1     线性表

线性表数据按照一定的逻辑顺序存储在内存中。线性表是有序的。线性表根据内存的物理结构分为两种:数组和链表

 

数组是一种逻辑上有序的线性表,物理上也连续。

 

 

 

链表是一种逻辑上有序的线性表,但物理上不连续。

 

 

 

数组和链表的区别:

数组在查询时效率高,在添加、删除元素时效率低(涉及移动元素)

链表在查询时效率低(每次从头开始,不能跳跃访问),在添加、删除元素时效率高(不涉及移动元素)

1.4.2     栈

特性:先进后出,后进先出

 

 

 

1.4.3     队列

特性:先进先出

 

 

 


  

1.5   ArrayList/Vector

ArrayList 是List接口的实现类,底层数据结构是数组,实现大小可变的数组。

ArrayList 线程不安全,jdk1.2

 

ArrayList 底层数据结构是数组,默认数组大小是10,如果添加的元素个数超过默认容量,ArrayList会自动拓容,拓容原则:newCapacity = oldCapacity + oldCapacity / 2;

如果未来确定序列的元素不在增加,通过调用trimToSize()调制容量至合适的空间。

 

ArrayList作为List接口的实现类,常用方法和遍历方法参考List接口。

 

Vector 是List接口的实现类,底层数据结构也是数组,也是大小可变的数组。

Vector是线程安全的,jdk1.0

 

Vector底层数据结构是数组,默认数组大小是10,如果添加的元素个数超过默认容量,Vector会自动拓容,拓容原则:newCapacity = oldCapacity +capacityIncrement(增长因子);如果未来确定序列的元素不在增加,通过调用trimToSize()调制容量至合适的空间。

 

注意:Vector 在实现List接口的同时,同添加了自身特有的方法xxxElement,未来使用时为了程序的可拓展性,一定要按照接口来操作Vector。

 

1.6   LinkedList

LinkedList是List接口的实现类,底层数据结构是链表。

LinekList常用方法和遍历方法参照List接口。

LinkedList 线程不安全。

 

除了实现List接口, 还实现栈接口

 

 

push入栈操作 / pop出栈操作

public class Test01 {

     public static void main(String[] args) {

         LinkedList list = new LinkedList();

         list.push("apple");

         list.push("banana");

         list.push("coco");

        

        

         System.out.println(list.pop());

         System.out.println(list.pop());

         System.out.println(list.pop());

        

         // java.util.NoSuchElementException

         System.out.println(list.pop());

     }

}

 

队列(Queue)接口

 

 

 

 

add/remove/element() 可能会出现NoSuchElementException异常

public static void main(String[] args) {

       

        LinkedList queue = new LinkedList();

        // 入队

        /**

         * 队列头                        队列尾

         *<-----          <-----

         * [apple, banana, coco]

         */

        queue.add("apple");

        queue.add("banana");

        queue.add("coco");

        System.out.println(queue);

       

        // 出队

        System.out.println(queue.remove());

        System.out.println(queue.remove());

        System.out.println(queue.remove());      

        System.out.println(queue);

       

        // java.util.NoSuchElementException

        System.out.println(queue.remove());

       

       

        // 获取表头元素

        System.out.println(queue.element());

    }

 

offer/poll/peek 可能会返回特殊值(null)

public static void main(String[] args) {

        

         LinkedList queue = new LinkedList();

         // 入队

         /**

          * 队列头                           队列尾

          *<-----          <-----

          * [apple, banana, coco]

          */

         queue.offer("apple");

         queue.offer("banana");

         queue.offer("coco");

        

         // 出队列

         //System.out.println(queue.poll());

         //System.out.println(queue.poll());

         //System.out.println(queue.poll());

         System.out.println(queue);

 

         //System.out.println(queue.poll());

        

         // 获取表头元素

         System.out.println(queue.peek());

    

     }

 

双向队列(Deque)接口

 

 

 

/**

 * 以双向队列形式操作LinkedList

 */

public class Test04 {

     public static void main(String[] args) {

        

         LinkedList queue = new LinkedList();

         // 入队

         /**

          *<-----          <-----

          * [apple, banana, coco]

          * ---->          ----->

          */

        

         queue.addFirst("apple");

         queue.addFirst("banana");

         queue.addFirst("coco");

         System.out.println(queue);

        

         System.out.println(queue.removeLast());

         System.out.println(queue.removeFirst());

         System.out.println(queue.removeFirst());

         System.out.println(queue);

        

         // 获取头元素

         System.out.println(queue.getFirst());

    

     }

}

 

1.7   Iterator和ListIterator

Iterator在迭代过程中不允许向集合中添加元素

 

public static void main(String[] args) {

         ArrayList list = new ArrayList();

         list.add("apple");

         list.add("banana");

         list.add("coco");

        

         Iterator it = list.iterator();

         while(it.hasNext()) {

              String item = (String) it.next();

              if(item.equals("banana")) {

                   list.add("test");

              }

         }

        

         System.out.println(list);

     }

当通过Iterator集合迭代器遍历集合过程中,不能再向集合汇总添加元素,否则出现ConcurrentModificationException 并发修改异常。

 

ListIterator允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置

public class Test01 {

    public static void main(String[] args) {

        ArrayList list = new ArrayList();

        list.add("apple");

        list.add("banana");

        list.add("coco");

       

        ListIterator it = list.listIterator();

        while(it.hasNext()) {

            String item = (String) it.next();

            if(item.equals("banana")) {

                it.add("test");

            }

        }

       

        System.out.println(list);

    }

}

 

熟悉Iterator实现类的源码hasNext/next

1.8   泛型(generic)

1.8.1     泛型的概念

泛型允许开发者在强类型程序设计语言(java)编写代码时定义一些可变部分,这些部分在使用前必须作出指明。

 

泛型就是将类型参数化

ArrayList<E>  list表示声明了一个列表list,列表的元素是E类型

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

声明了一个列表list,列表的元素只能是String类型。

 

泛型在编译器起作用,运行时jvm察觉不到泛型的存在。

 

1.8.2     泛型的擦除

泛型在运行时已经被擦除了。

 

public static void main(String[] args) {

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

        list.add("apple");

        System.out.println(list instanceof ArrayList);

        System.out.println(listinstanceof ArrayList<String>);

}

Cannot perform instanceof check against parameterized type ArrayList<String>. Use the form ArrayList<?> instead since further generic type information will be erased at runtime

 

1.8.3     泛型的应用

1.8.3.1  泛型类

当一个类中属性的数据类型不确定时,具体是什么类型由使用者来确定时,使用泛型。泛型类的形式

public class 类名<T> {

    

}

 

定义一个泛型类

public class FanClass<T> {

     private T t;

 

     public T getT() {

         return t;

     }

 

     public void setT(T t) {

         this.t = t;

     }

 

     public FanClass(T t) {

         super();

         this.t = t;

     }

 

     public FanClass() {

         super();

     }

}

 

public class Test01 {

     public static void main(String[] args) {

         FanClass<String> fan = new FanClass<String>();

         fan.setT("apple");

        

         FanClass<Integer> fan2 = new FanClass<Integer>();

         fan2.setT(1);

     }

}

 

 

1.8.3.2  泛型方法

当一个方法的参数类型不确定时,具体是什么类型由使用者来确定,可以考虑使用泛型方法。形式:

public <T> void xxx(T a) {

    System.out.println(a);

}

 

public class Student {

    

    

     /*public void showInfo(int a) {

         System.out.println(a);

     }

    

     public void showInfo(float a) {

         System.out.println(a);

     }

    

     public void showInfo(String a) {

         System.out.println(a);

     }*/

    

     public <T> void showInfo(T a) {

         System.out.println(a);

     }

}

 

public static void main(String[] args) {

        

         Student stu = new Student();

         stu.showInfo(1);

         stu.showInfo("apple");

         stu.showInfo(1.0f);

     }

 

泛型方法在调用时确定(指明)类型。

泛型方法在一定程度上优化了方法重载。

 

泛型方法可以定义多个泛型类型

// 可以定义多个泛型的类型

    public <A,B> void showInfo(A a,B b) {

        System.out.println(a);

        System.out.println(b);

    }

多个泛型类型进一步优化了方法重载。

 

多个同类型的泛型

// 多个同类型的泛型

     /*public <A> void print(A a) {

         System.out.println(a);

     }

     public <A> void print(A a,A b) {

         System.out.println(a);

         System.out.println(b);

     }*/

    

     public <A> void print(A...a) {

         System.out.println(a);

     }

 

A… a 表示方法可以接受多个参数。当调用方法传递多个参数时,多个参数被放到a数组中,a是什么类型的数组由开发者调用处传参决定。

stu.print(1);

stu.print(1,2);

        

stu.print("apple");

stu.print("apple","banana");

print(A...a) 方法称为可变参数的泛型形式。

 

1.8.3.3  泛型接口(C)

如果接口中的方法的参数(形参、返回值)不确定时,可以考虑使用泛型接口。形式

public interface FanInterface<T> {

    public void showInfo(T t);

}

 

[1]实现类能确定泛型接口的类型

public class ImplClass implements FanInterface<String>{

 

     @Override

     public void showInfo(String t) {

         // TODO Auto-generated method stub

        

     }

}

 

[2]实现类不能确定泛型接口的类型->继续泛。

public class ImplClass2<T> implements FanInterface<T>{

 

     @Override

     public void showInfo(T t) {

        

     }

}

 

1.8.3.4  泛型的上限和下限 (C)

public static void print(ArrayList<? extends Pet> list) {

        for (Pet pet : list) {

            pet.showInfo();

        }

    }

 

泛型的上限ArrayList(? extends Pet) list 声明了一个容器,容器中的元素类型一定要继承于Pet,我们称这种形式叫做泛型的上限。

 

泛型的下限ArrayList(? super Pet) list 声明了一个容器,容器中的元素类型一定要是Pet的父类,我们称这个形式为泛型的下限。

 

1.9   Set接口

Set接口表示一个唯一、无序的容器(和添加顺序无关)

 

1.9.1     Set接口提供的方法

public static void main(String[] args) {

         /**

          * 增:add/addAll

          * 删:clear/remove/removeAll/retainAll

          * 改:

          * 查:contains/containsAll

          * 遍历:iterator

          * 其他:size/isEmpty

          */

        

         Set<Integer> set = new HashSet<Integer>();

         // [1]添加

         // 无序

         set.add(10);

         set.add(3);

         set.add(20);

         set.add(0);

         // 不能添加重复元素

         boolean r = set.add(1);

         System.out.println(set);

        

         // 【2】删除

//       set.remove(1);

//       set.clear();

//       System.out.println(set);

        

         // 【3】查看是否包含

         System.out.println(set.contains(1));

        

         // 【4】其他

         System.out.println(set.size());

         System.out.println(set.isEmpty());

     }

 

1.9.2     Set接口的遍历

public static void main(String[] args) {

        

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

         set.add("banana");

         set.add("apple");

         set.add("coco");

        

         // 快速遍历

         for (String item : set) {

              System.out.println(item);

         }

        

         // 迭代器

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

         while(it.hasNext()) {

              String item = it.next();

              System.out.println(item);

         }

     }

 

 

Set接口的实现类常见的有HashSet、LinkedHashSet、TreeSet

 

1.10HashSet

HashSet是Set接口的实现类,底层数据结构是哈希表。

HashSet是线程不安全的(不保证同步)

1.10.1   哈希表工作原理

 

 

 

 

1.10.2   添加自定义对象

根据哈希表的工作原理,请存储一个自定义对象到HashSet中。

package cn.sxt03.hashset;

 

public class Student {

     private String id;

     private String name;

     private int age;

 

     // …

    

 

     @Override

     public int hashCode() {

         final int prime = 31;

         int result = 1;

         result = prime * result + age;

         result = prime * result + ((id == null) ? 0 : id.hashCode());

         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;

         Student other = (Student) obj;

         if (age != other.age)

              return false;

         if (id == null) {

              if (other.id != null)

                   return false;

         } else if (!id.equals(other.id))

              return false;

         if (name == null) {

              if (other.name != null)

                   return false;

         } else if (!name.equals(other.name))

              return false;

         return true;

     }

 

     @Override

     public String toString() {

         return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";

     }

 

}

 

 

总结

[1]如果向HashSet中存储元素时,元素一定要实现hashCode方法和equals方法。

[2] 优点:添加、删除、查询效率高;缺点:无序

 

 

1.11LinkedHashSet

LinkedHashSet是Set接口的实现类,底层数据结构哈希表+链表

哈希表用于散列元素;链表用于维持添加顺序。

 

如果要添加自定义对象元素,也需要重写hashCode和equals方法。

 

1.12TreeSet

TreeSet 是Set接口的实现类,底层数据结构是二叉树。

TreeSet 存储的数据按照一定的规则存储。存储规则让数据表现出自然顺序。

 

1.12.1   TreeSet工作原理

 

 

 

添加一个新元素t的存储的步骤

[1] 如果集合无元素,t直接加入;如果集合有元素,t和根节点比较;

[2] 如果t小于根节点;把t放到根节点的左子树上;重复1-3步骤

[3] t大于根节点;把t放到根节点的右子树上;重复1-3步骤

 

输出时按照一定的规则:左子树->根节点->右子树

 

根据TreeSet的工作原理,向TreeSet添加自定义元素?

向TreeSet中添加元素时,一定要提供比较策略,否则会出现ClassCastException。

 

比较策略分两种:内部比较器和外部比较器

 

1.12.2   内部比较器

当一个自定义对象实现Comparable并实现compareTo方法时,通过指定具体的比较策略,此时称为内部比较器。

package cn.sxt05.treeset;

 

public class Student implements Comparable<Student>{

    private String id;

    private String name;

    private int age;

 

    // 。。。

 

    @Override

    public String toString() {

        return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";

    }

 

    @Override

    public int compareTo(Student o) {

        if(this.getAge()<o.getAge()) {

            return -1;

        }else if(this.getAge() == o.getAge()) {

            return 0;

        }else {

            return 1;

        }

    }

 

}

 

 

比较策略的几种情况

[1]比较策略一般当前对象写在前面,待比较对象也在后面,比较结果默认升序

return  this.getAge() - o.getAge() ;

如果想要降序,改变两个比较对象的位置即可。

 

[2] 多种比较因素

     @Override

     public int compareTo(Student o) {

         /*if(this.getAge()<o.getAge()) {

              return -1;

         }else if(this.getAge() == o.getAge()) {

              return 0;

         }else {

              return 1;

         }*/

        

         // return  this.getAge() - o.getAge() ;

        

         if(this.getAge()<o.getAge()) {

              return -1;

         }else if(this.getAge() == o.getAge()) {

              return this.getName().compareTo(o.getName());

         }else {

              return 1;

         }

     }

 

1.12.3   外部比较器

当实际开发过程中不知道添加元素的源代码、无权修改别人的代码,此时可以使用外部比较器。

 

Comparator 位于java.util包中,定义了compare(o1,o2) 用于提供外部比较策略。

TreeSet接受一个指定比较策略的构造方法,这些比较策略的实现类必须实现Comparator

接口。

 

需求:按照字符串的长度比较

public class Test01 {

    public static void main(String[] args) {

       

        LenComparator lenComparator = new LenComparator();

        TreeSet<String> set2 = new TreeSet<String>(lenComparator);

       

        set2.add("banana");

        set2.add("coco");

        set2.add("apple");

       

        set2.add("apple");

        System.out.println(set2);

       

    }

}

 

class LenComparator implements Comparator<String>{

 

    @Override

    public int compare(String o1, String o2) {

        return o1.length() - o2.length();

    }  

}

 

使用匿名内部类优化

public class Test02 {

     public static void main(String[] args) {

        

         TreeSet<String> set2 = new TreeSet<String>(new Comparator<String>() {

 

              @Override

              public int compare(String o1, String o2) {

                   return o1.length() - o2.length();

              }

             

          });

        

         set2.add("banana");

         set2.add("coco");

         set2.add("apple");

        

         set2.add("apple");

         System.out.println(set2);

        

     }

}

 

1.13Map接口

Map接口称为键值对集合或者映射集合,其中的元素(entry)是以键值对(key-value)的形式存在。

Map 容器接口中提供了增、删、改、查的方式对集合进行操作。

Map接口中都是通过key来操作键值对,一般key是已知。通过key获取value。

1.13.1   map常用方法

public static void main(String[] args) {

        

         /**

          * 增:put/putAll

          * 删:clear/remove

          * 改:put

          * 查:get/containsKey/containsValue

          * 其他:isEmpty/size

          */

        

         Map<String, String> map = new HashMap<String,String>();

        

         // 【1】put

         map.put("A", "apple");

         map.put("B", "banana");

         map.put("C", "coco");

        

         // 【2】删除

         // map.clear();

         // smap.remove("A");

        

         // 【3】修改

         //map.put("A", "apple x");

        

         // 【4】查看

         String val = map.get("A");

         System.out.println(map.containsKey("D"));

        

        

         System.out.println(map);

     }

 

1.13.2   map接口的遍历

 

通过keySet() 返回map中键的set集合。

public static void main(String[] args) {

 

         Map<String, String> map = new HashMap<String,String>();

        

         map.put("B", "banana");

         map.put("A", "apple");

         map.put("C", "coco");

         // map无序

         // 可以根据key的自然顺序 让map有序  => 一般用string作为key

         System.out.println(map);

        

        

         // 遍历

         Set<String> keys = map.keySet();

         for (String key : keys) {

              System.out.println(key+"=>"+map.get(key));

         }

        

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

         while(it.hasNext()) {

              String key = it.next();

              System.out.println(key+"=>"+map.get(key));

         }

     }

 

map中以键值对作为元素,键值对在map中称为entry,entrySet返回键值对的set集合。

public static void main(String[] args) {

 

         Map<String, String> map = new HashMap<String,String>();

        

         map.put("B", "banana");

         map.put("A", "apple");

         map.put("C", "coco");

         // map无序

         // 可以根据key的自然顺序 让map有序  => 一般用string作为key

         System.out.println(map);

        

         // entrySet

         Set<Entry<String, String>> entrySet = map.entrySet();

         for (Entry<String, String> entry : entrySet) {

              System.out.println(entry.getKey()+"=>"+entry.getValue());

         }

        

         Iterator<Entry<String, String>> it2 = entrySet.iterator();

         while(it2.hasNext()) {

              Entry<String, String> entry = it2.next();

              System.out.println(entry.getKey()+"=>"+entry.getValue());

         }

     }

 

Map接口的实现类HashMap、LinkedHashMap、TreeMap

 

1.14HashMap

HashMap 是Map的实现类,key以HashSet存储。

HashMap 线程不安全,jdk1.2;Hashtable是HashMap的线程安全版本,jdk1.0

 

public static void main(String[] args) {

        

         /*

         HashMap<String, Object> map = new HashMap<String,Object>();

        

         ArrayList<String> list1 = new ArrayList<String>();

         list1.add("alex");

         list1.add("alice");

         list1.add("allen");

         map.put("A", list1);

        

        

         ArrayList<String> list2 = new ArrayList<String>();

         list2.add("ben");

         list2.add("bill");

         map.put("B", list2);

        

         System.out.println(map);

         */

        

        

         HashMap<Student, Object> map = new HashMap<Student,Object>();

        

         ArrayList<String> list1 = new ArrayList<String>();

         list1.add("alex");

         list1.add("alice");

         list1.add("allen");

         Student s1 = new Student("001", "大狗", 20);

         map.put(s1, list1);

        

        

         ArrayList<String> list2 = new ArrayList<String>();

         list2.add("ben");

         list2.add("bill");

         Student s2 = new Student("001", "大狗", 20);

         // 修改

         map.put(s2, list2);

         System.out.println(map);

        

     }

 

总结:

[1] 向HashMap中存储元素时,key一定要实现hashCode和equals

[2] 一般建议使用String作为Map接口的key

 

1.15LinkedHashMap

LinkedHashMap是Map接口的实现类,key以LinkedHashSet存储。

哈希表散列key,链表维持key的添加顺序。

 

public static void main(String[] args) {

        

        

         /*LinkedHashMap<String, Object> map = new LinkedHashMap<String,Object>();

        

         ArrayList<String> list2 = new ArrayList<String>();

         list2.add("ben");

         list2.add("bill");

         map.put("B", list2);

        

         ArrayList<String> list1 = new ArrayList<String>();

         list1.add("alex");

         list1.add("alice");

         list1.add("allen");

         map.put("A", list1);

        

         System.out.println(map);*/

        

        

        

         HashMap<Student, Object> map = new HashMap<Student,Object>();

        

         ArrayList<String> list1 = new ArrayList<String>();

         list1.add("alex");

         list1.add("alice");

         list1.add("allen");

         Student s1 = new Student("001", "大狗", 20);

         map.put(s1, list1);

        

        

         ArrayList<String> list2 = new ArrayList<String>();

         list2.add("ben");

         list2.add("bill");

         Student s2 = new Student("001", "大狗", 20);

         // 修改

         map.put(s2, list2);

         System.out.println(map);

        

     }

 

 

1.16TreeMap

TreeMap是Map的实现类,key以TreeSet存储。

 

public static void main(String[] args) {

        

        

         /*TreeMap<String, Object> map = new TreeMap<String,Object>(new Comparator<String>() {

 

              @Override

              public int compare(String o1, String o2) {

                   return o1.length() - o2.length();

              }

         });

        

         ArrayList<String> list2 = new ArrayList<String>();

         list2.add("ben");

         list2.add("bill");

         map.put("Aa", list2);

        

         ArrayList<String> list1 = new ArrayList<String>();

         list1.add("alex");

         list1.add("alice");

         list1.add("allen");

         map.put("B", list1);

        

         System.out.println(map);*/

        

        

        

         TreeMap<Student, Object> map = new TreeMap<Student,Object>(new Comparator<Student>() {

 

              @Override

              public int compare(Student o1, Student o2) {

                   return o1.getAge() - o2.getAge();

              }

         });

        

         ArrayList<String> list1 = new ArrayList<String>();

         list1.add("alex");

         list1.add("alice");

         list1.add("allen");

         Student s1 = new Student("001", "大狗", 20);

         map.put(s1, list1);

        

        

         ArrayList<String> list2 = new ArrayList<String>();

         list2.add("ben");

         list2.add("bill");

         Student s2 = new Student("001", "2狗", 20);

         // 修改

         map.put(s2, list2);

         System.out.println(map);

        

     }

 

1.17总结

 

 

posted @ 2019-05-06 23:10  小小穿梭机^^  阅读(117)  评论(0编辑  收藏  举报