黑马程序员——集合

来源:互联网 发布:淘宝 卖家 现状 编辑:程序博客网 时间:2024/05/16 01:32

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

1. 集合

---|Collection: 单列集合

           ---|List: 有存储顺序, 可重复

              ---|ArrayList:    数组实现, 查找快, 增删慢

                                  由于是数组实现, 在增和删的时候会牵扯到数组

增容, 以及拷贝元素. 所以慢。数组是可以直接

按索引查找, 所以查找时较快

              ---|LinkedList:   链表实现, 增删快, 查找慢

                                  由于链表实现, 增加时只要让前一个元素记住自

己就可以, 删除时让前一个元素记住后一个元

素, 后一个元素记住前一个元素. 这样的增删效

率较高但查询时需要一个一个的遍历, 所以效率

较低

              ---|Vector:   和ArrayList原理相同, 但线程安全, 效率略低

                              和ArrayList实现方式相同, 但考虑了线程安全问

题, 所以效率略低

           ---|Set: 无存储顺序, 不可重复

              ---|HashSet

              ---|TreeSet

              ---|LinkedHashSet

---| Map: 键值对

       ---|HashMap

       ---|TreeMap

       ---|HashTable

       ---|LinkedHashMap

 

为什么出现这么多集合容器,因为每一个容器对数据的存储方式不同,这种存储方式称之为数据结构(data structure)

注意 集合和数组中存放的都是对象的引用。

1.1. 什么时候该使用什么样的集合

Collection

我们需要保存若干个对象的时候使用集合。

 

List

 

 

如果我们需要保留存储顺序, 并且保留重复元素, 使用List.

如果查询较多, 那么使用ArrayList

如果存取较多, 那么使用LinkedList

如果需要线程安全, 那么使用Vector

 

 

Set

 

如果我们不需要保留存储顺序, 并且需要去掉重复元素, 使用Set.

如果我们需要将元素排序, 那么使用TreeSet

如果我们不需要排序, 使用HashSet, HashSet比

TreeSet效率高.

如果我们需要保留存储顺序, 又要过滤重复元素, 那么使用LinkedHashSet

 

2.     集合类(Collection)

Collection接口有两个子接口:

List(链表|线性表)

    Set(集)

特点:

Collection中描述的是集合共有的功能(CRUD)

    List可存放重复元素,元素存取是有序的

    Set不可以存放重复元素,元素存取是无序的

java.util.Collection

       ---| Collection      描述所有接口的共性

           ----| List接口    可以有重复元素的集合

           ----| Set  接口   不可以有重复元素的集合

 

 

2:学习集合对象

    学习Collection中的共性方法,多个容器在不断向上抽取就出现了该体系。发现Collection接口中具有所有容器都具备的共性方法。查阅API时,就可以直接看该接口中的方法。并创建其子类对象对集合进行基本应用。当要使用集合对象中特有的方法,在查看子类具体内容。

查看api 文档Collection在在java.util 中(注意是大写Collection)

注意在现阶段遇到的 E T 之类的类型,需要暂时理解为object  因为涉及到了泛型.

3:创建集合对象,使用Collection中的List的具体实现类ArrayList

    1:Collection coll=new Arraylist();

2.1. Collection接口的共性方法

增加:

       1:add()   将指定对象存储到容器中

                      add 方法的参数类型是Object 便于接收任意对象

       2:addAll() 将指定集合中的元素添加到调用该方法和集合中

删除:

       3:remove() 将指定的对象从集合中删除

       4:removeAll() 将指定集合中的元素删除

修改

       5:clear() 清空集合中的所有元素

判断

       6:isEmpty() 判断集合是否为空

       7:contains() 判断集合何中是否包含指定对象

           

       8:containsAll() 判断集合中是否包含指定集合

                            使用equals()判断两个对象是否相等 

获取:   9:int size()    返回集合容器的大小

 

转成数组10: toArray()   集合转换数组

2.1.1.    增加:

publicstaticvoid main(String[] args) {

       Collection list = new ArrayList();

       //增加:add() 将指定对象存储到容器中

       list.add("计算机网络");

       list.add("现代操作系统");

       list.add("java编程思想");

       System.out.println(list);

       // [计算机网络,现代操作系统, java编程思想]

      

       //增加2 list容器元素添加到list2容器中

       Collection list2 = new ArrayList();

       list2.add("java核心技术");

       list2.addAll(list);

       list2.add("java语言程序设计");

       System.out.println(list2);

       // [java核心技术,计算机网络, 现代操作系统, java编程思想, java语言程序设计]

    }

 

2.1.2.    删除:

// 删除1 remove

       boolean remove = list2.remove("java核心技术");

       System.out.println(remove);// true

       System.out.println(list2);//

       //删除2 removeAll()list中的元素删除

       boolean removeAll = list2.removeAll(list);

       System.out.println(removeAll);//true

       System.out.println(list2);//[java语言程序设计]

2.1.3.    修改:

publicstaticvoid main(String[] args) {

       Collection list = new ArrayList();

       //增加:add() 将指定对象存储到容器中

       list.add("计算机网络");

       list.add("现代操作系统");

       list.add("java编程思想");

       list.add("java核心技术");

       list.add("java语言程序设计");

       System.out.println(list);

       //修改 clear() 清空集合中的所有元素

       list.clear();

       System.out.println(list);//[]

    }

2.1.4.    判断:

publicstaticvoid main(String[] args) {

       Collection list = new ArrayList();

       //增加:add() 将指定对象存储到容器中

       list.add("计算机网络");

       list.add("现代操作系统");

       list.add("java编程思想");

       list.add("java核心技术");

       list.add("java语言程序设计");

       System.out.println(list);

      

       boolean empty = list.isEmpty();

       System.out.println(empty);// false

       boolean contains = list.contains("java编程思想");

       System.out.println(contains);// true

       Collection list2 = new ArrayList();

       list2.add("水许传");

       boolean containsAll = list.containsAll(list2);

       System.out.println(containsAll);// false

 

    }

2.1.5.    获取:

publicstaticvoid main(String[] args) {

       Collection list = new ArrayList();

       //增加:add() 将指定对象存储到容器中

       list.add("计算机网络");

       list.add("现代操作系统");

       list.add("java编程思想");

       list.add("java核心技术");

       list.add("java语言程序设计");

       System.out.println(list);

       //获取  集合容器的大小

       int size = list.size();

       System.out.println(size);

    }

 

2.2 List

---| Iterable     接口

          Iterator iterator()

    ----| Collection     接口

       ------| List      接口 元素可以重复,允许在指定位置插入元素,并通过索

引来访问元素

2.2.1.    List集合特有方法

1:增加

        void add(int index, E element) 指定位置添加元素           

        boolean addAll(int index, Collection c) 指定位置添加集合 

2:删除

E remove(int index) 删除指定位置元素

 

3:修改

       E set(int index, E element)    返回的是需要替换的集合中的元素

4:查找:

        E get(int index)             注意: IndexOutOfBoundsException

       int indexOf(Object o)         // 找不到返回-1

       lastIndexOf(Object o)

5:求子集合

        List<E> subList(int fromIndex, int toIndex) // 不包含toIndex  

 

2.2.2.    ArrayList

--| Iterable

             ----| Collection

               ------| List

                 ---------| ArrayList  底层采用数组实现,默认10。每次增长

60%,((oldCapacity * 3)/2 + 1) 查询快,增删慢。

               ---------| LinkedList          

ArrayList:实现原理:

数组实现, 查找快, 增删慢

数组为什么是查询快?因为数组的内存空间地址是连续的.

    ArrayList底层维护了一个Object[] 用于存储对象,默认数组的长度是10。可以通过 new ArrayList(20)显式的指定用于存储对象的数组的长度。

    当默认的或者指定的容量不够存储对象的时候,容量自动增长为原来的容量的1.5倍。

由于ArrayList是数组实现, 在增和删的时候会牵扯到数组增容, 以及拷贝元素. 所以慢。数组是可以直接按索引查找, 所以查找时较快

可以考虑,假设向数组的0角标未知添加元素,那么原来的角标位置的元素需要整体往后移,并且数组可能还要增容,一旦增容,就需要要将老数组的内容拷贝到新数组中.所以数组的增删的效率是很低的.

 

练习:去除ArrayList集合中重复元素

       1:存入字符串元素

       2:存入自定义对象元素(如Perosn对象)

原理:

     循环遍历该集合,每取出一个放置在新的集合中,放置之前先判断新的集合是否以包含了新的元素。

思路:

 存入人的对象.

 1先定义person

 2将该类的实例存入集合

 3 将对象元素进行操作. 注意:自定义对象要进行复写toString equals 方法.

 为什么?因为object person 的父类,object中的toString 返回的是哈希值,object 类中equals

 方法比较的是对象的地址值.

 思路

 1存入字符串对象

 2存入自定义对象person

 2创建容器,用于存储非重复元素

 3对原容器进行遍历,在遍历过程中进行判断遍历到的元素是否在容器中存在.(contains)

 4如果存在,就不存入,否则存入.

 5 返回新容器

 

publicclass Demo6 {

    publicstaticvoid main(String[] args) {

       ArrayList arr = new ArrayList();

       Person p1 = new Person("jack", 20);

       Person p2 = new Person("rose", 18);

       Person p3 = new Person("rose", 18);

       arr.add(p1);

       arr.add(p2);

       arr.add(p3);

       System.out.println(arr);

       ArrayList arr2 = new ArrayList();

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

           Object obj = arr.get(i);

           Person p = (Person) obj;

           if (!(arr2.contains(p))) {

              arr2.add(p);

           }

       }

       System.out.println(arr2);

    }

}

 

class Person {

    private Stringname;

    privateintage;

 

    public Person() {

 

    }

 

    public Person(String name,int age) {

 

       this.name = name;

       this.age = age;

    }

 

    public String getName() {

       returnname;

    }

 

    publicvoid setName(String name) {

       this.name = name;

    }

 

    publicint getAge() {

       returnage;

    }

 

    publicvoid setAge(int age) {

       this.age = age;

    }

 

    @Override

    publicint hashCode() {

       returnthis.name.hashCode() + age * 37;

    }

 

    @Override

    publicboolean equals(Object obj) {

       if (!(objinstanceof Person)) {

           returnfalse;

       }

       Person p = (Person) obj;

 

       returnthis.name.equals(p.name) && this.age == p.age;

    }

 

    @Override

    public String toString() {

       return"Person@name:" +this.name +" age:" + this.age;

    }

 

}

 

在实际的开发中ArrayList是使用频率最高的一个集合。

2.2.3.    LinkedList

--| Iterable

             ----| Collection

               ------| List

                 ---------| ArrayList  底层采用数组实现,默认10。每次增长

60%,((oldCapacity * 3)/2 + 1) 查询快,增删慢。

               ---------| LinkedList  底层采用链表实现,增删快,查询慢。        

LinkedList:链表实现,增删快, 查找慢

由于LinkedList:在内存中的地址不连续,需要让上一个元素记住下一个元素.所以每个元素中保存的有下一个元素的位置.虽然也有角标,但是查找的时候,需要从头往下找,显然是没有数组查找快的.但是,链表在插入新元素的时候,只需要让前一个元素记住新元素,让新元素记住下一个元素就可以了.所以插入很快.

由于链表实现,增加时只要让前一个元素记住自己就可以, 删除时让前一个元素记住后一个元素,后一个元素记住前一个元素. 这样的增删效率较高。

但查询时需要一个一个的遍历,所以效率较低。

 

特有方法

1:方法介绍

            addFirst(E e)

addLast(E e)

getFirst()

getLast()

removeFirst()

removeLast()

如果集合中没有元素,获取或者删除元

素抛:NoSuchElementException

2:数据结构

              1:栈 (1.6)

                  先进后出

                  push()

                  pop()

              2:队列(双端队列1.5)

                  先进先出

                  offer()

                  poll()

3:返回逆序的迭代器对象     

descendingIterator()   返回逆序的迭代器对象

 

基本方法

import java.util.Iterator;

import java.util.LinkedList;

 

publicclass Demo3 {

    publicstaticvoid main(String[] args) {

       LinkedList list = new LinkedList();

       list.add("西游记");

       list.add("三国演义");

       list.add("石头记");

       list.add("水浒传");

       list.add("全球通史");

       list.addFirst("史记");

       list.addLast("呐喊");

       // list.addFirst(null);

       // list.addLast(null);

       System.out.println(list);

       //获取指定位置处的元素。

       String str = (String) list.get(0);

       //返回此列表的第一个元素。

       String str2 = (String) list.getFirst();

       System.out.println(str.equals(str2));

 

       //获取指定位置处的元素。

       String str3 = (String) list.get(list.size() - 1);

       //返回此列表的最后一个元素。

       String str4 = (String) list.getLast();

       System.out.println(str3.equals(str4));

 

       //获取但不移除此列表的头(第一个元素)。

       Object element = list.element();

       System.out.println(element);

 

       int size = list.size();

       System.out.println(size);

}

 

 

迭代

mport java.util.Iterator;

import java.util.LinkedList;

 

publicclass Demo3 {

    publicstaticvoid main(String[] args) {

       LinkedList list = new LinkedList();

       list.add("西游记");

       list.add("三国演义");

       list.add("石头记");

       list.add("水浒传");

       list.add("全球通史");

       Iterator it = list.iterator();

       while (it.hasNext()) {

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

           System.out.println(next);

       }

    }

}

 

逆序迭代

import java.util.Iterator;

import java.util.LinkedList;

 

publicclass Demo6 {

    publicstaticvoid main(String[] args) {

       LinkedList list = new LinkedList();

       list.add("aa");

       list.add("bb");

       list.add("cc");

       Iterator dit = list.descendingIterator();

       while (dit.hasNext()) {

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

       }

    }

}

 

 

 

注意:可以使用该集合去模拟出队列(先进先出)或者堆栈(后进先出)数据结构。

堆栈(后进先出)

//堆栈(后进先出)数据结构

publicclass Demo3 {

    publicstaticvoid main(String[] args) {

       LinkedList list = new LinkedList();

       //压栈,先进后出

       list.push("西游记");

       list.push("三国演义");

       list.push("石头记");

       list.push("水浒传");

       System.out.println(list);

       //弹栈

        String str1 = (String) list.pop();

       System.out.println(str1);

       String str2 = (String) list.pop();

       System.out.println(str2);

       String str3 = (String) list.pop();

       System.out.println(str3);

       String str4 = (String) list.pop();

       System.out.println(str4);

        System.out.println(list.size());// 0

       System.out.println(list); //[]

    }

}

 

队列,先进先出

import java.util.LinkedList;

 

publicclass Demo3 {

    publicstaticvoid main(String[] args) {

       LinkedList list = new LinkedList();

       //队列,先进先出

       list.offer("西游记");

       list.offer("三国演义");

       list.offer("石头记");

       list.offer("水浒传");

       System.out.println(list);

       //出队列

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

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

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

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

 

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

 

       System.out.println(list.peek());// 获取队列的头元素,但是不删除

       System.out.println(list.peekFirst());// 获取队列的头元素,但是不删除

       System.out.println(list.peekLast());// 获取队列的最后一个元素但是不删除

 

    }

}

 

 

 

ArrayList 和 LinkedList的存储查找的优缺点:

1、ArrayList 是采用动态数组来存储元素的,它允许直接用下标号来直接查找对应的元素。但是,但是插入元素要涉及数组元素移动及内存的操作。总结:查找速度快,插入操作慢。

2、LinkedList 是采用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快

问题:有一批数据要存储,要求存储这批数据不能出现重复数据,ArrayList、LinkedList都没法满足需求。解决办法:使用 set集合。

2.2.4.    Vector

Vector: 描述的是一个线程安全的ArrayList

        

ArrayList:单线程效率高

Vector   :多线程安全的,所以效率低

特有的方法:

 

 void addElement(E obj) 在集合末尾添加元素

 E elementAt( int index)返回指定角标的元素

 Enumeration elements() 返回集合中的所有元素,封装到Enumeration对象中

 

 

 Enumeration 接口:

 

  boolean hasMoreElements()

          测试此枚举是否包含更多的元素。

  E nextElement()

          如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。

 

 

publicstaticvoid main(String[] args)

    {

       Vector v = new Vector();

       v.addElement("aaa");

       v.addElement("bbb");

       v.addElement("ccc");

       System.out.println( v );

       System.out.println( v.elementAt(2) );  // ccc

       //遍历Vector遍历

       Enumeration ens = v.elements();

       while ( ens.hasMoreElements() )

       {

           System.out.println( ens.nextElement() );

       }

    }

 

 

2.3. 迭代器

2.3.1. Iterator

    Iterator iterator() 返回该集合的迭代器对象

该类主要用于遍历集合对象,该类描述了遍历集合的常见方法

           1:java.lang.Itreable 

            ---| Itreable      接口 实现该接口可以使用增强for循环

              ---| Collection      描述所有集合共性的接口

                  ---| List接口     可以有重复元素的集合

                  ---| Set接口      不可以有重复元素的集合

 

public interface Iterable<T>

Itreable   该接口仅有一个方法,用于返回集合迭代器对象。

    1: Iterator<T> iterator()  返回集合的迭代器对象

 

Iterator接口定义的方法

Itreator   该接口是集合的迭代器接口类,定义了常见的迭代方法

    1:boolean hasNext()

                     判断集合中是否有元素,如果有元素可以迭代,就返回true。

    2: E next() 

                     返回迭代的下一个元素,注意: 如果没有下一个元素时,调用

next元素会抛出NoSuchElementException

 

    3: void remove()

                     从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操

作)。

思考:为什么next方法的返回类型是Object的呢? 为了可以接收任意类型的对象,那么返回的时候,不知道是什么类型的就定义为object

 

2.3.2.    迭代器遍历

1:while循环

publicstaticvoid main(String[] args) {

       ArrayList list = new ArrayList();

       //增加:add() 将指定对象存储到容器中

       list.add("计算机网络");

       list.add("现代操作系统");

       list.add("java编程思想");

       list.add("java核心技术");

       list.add("java语言程序设计");

       System.out.println(list);

       Iterator it = list.iterator();

       while (it.hasNext()) {

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

           System.out.println(next);

       }

    }

 

2:for循环

import java.util.ArrayList;

import java.util.Iterator;

 

publicclass Demo2 {

    publicstaticvoid main(String[] args) {

       ArrayList list = new ArrayList();

       //增加:add() 将指定对象存储到容器中

       list.add("计算机网络");

       list.add("现代操作系统");

       list.add("java编程思想");

       list.add("java核心技术");

       list.add("java语言程序设计");

       System.out.println(list);

 

       for (Iterator it = list.iterator(); it.hasNext();) {

             //迭代器的next方法返回值类型是Object,所以要记得类型转换。

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

           System.out.println(next);

       }

    }

}

 

需要取出所有元素时,可以通过循环,java 建议使用for 循环。因为可以对内存进行一下优化。

3:使用迭代器清空集合

publicclass Demo1 {

    publicstaticvoid main(String[] args) {

       Collection coll = new ArrayList();

       coll.add("aaa");

       coll.add("bbb");

       coll.add("ccc");

       coll.add("ddd");

       System.out.println(coll);

       Iterator it = coll.iterator();

       while (it.hasNext()) {

           it.next();

           it.remove();

       }

       System.out.println(coll);

    }

}

 

2.3.3.   List特有的迭代器ListIterator

public interface ListIterator extends Iterator

 

ListIterator<E> listIterator()

---| Iterator

       hasNext()

       next()

       remove()

       ------| ListIterator Iterator子接口 List专属的迭代器

                  add(E e)    将指定的元素插入列表(可选操作)。该元素直接插入到next返回的下一个元素的前面(如果有)

                  void set(E o)   用指定元素替换nextprevious返回的最后一个元素

                  hasPrevious()    逆向遍历列表,列表迭代器有多个元素,则返回true

                  previous()       返回列表中的前一个元素。

Iterator在迭代时,只能对元素进行获取(next())和删除(remove())的操作。

对于 Iterator 的子接口ListIterator 在迭代list 集合时,还可以对元素进行添加

(add(obj)),修改set(obj)的操作。

2.4. Set

Set:注重独一无二的性质,该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素

用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。

对象的相等性

引用到堆上同一个对象的两个引用是相等的。如果对两个引用调用hashCode方法,会得到相同的结果,如果对象所属的类没有覆盖Object的hashCode方法的话,hashCode会返回每个对象特有的序号(java是依据对象的内存地址计算出的此序号),所以两个不同的对象的hashCode值是不可能相等的。

    如果想要让两个不同的Person对象视为相等的,就必须覆盖Object继下来的hashCode方法和equals方法,因为Object  hashCode方法返回的是该对象的内存地址,所以必须重写hashCode方法,才能保证两个不同的对象具有相同的hashCode,同时也需要两个不同对象比较equals方法会返回true

该集合中没有特有的方法,直接继承自Collection。

---| Itreable      接口 实现该接口可以使用增强for循环

              ---| Collection      描述所有集合共性的接口

                  ---| List接口     可以有重复元素的集合

                            ---| ArrayList  

                            ---|  LinkedList

                  ---| Set接口      不可以有重复元素的集合

案例:set集合添加元素并使用迭代器迭代元素。

import java.util.HashSet;

import java.util.Iterator;

import java.util.Set;

 

publicclass Demo4 {

    publicstaticvoid main(String[] args) {

       //Set集合存和取的顺序不一致。

       Set hs = new HashSet();

       hs.add("世界军事");

       hs.add("兵器知识");

       hs.add("舰船知识");

       hs.add("汉和防务");

       System.out.println(hs);

       // [舰船知识,世界军事, 兵器知识, 汉和防务]

       Iterator it = hs.iterator();

       while (it.hasNext()) {

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

       }

    }

}

 

2.4.1.    HashSet

---| Itreable      接口 实现该接口可以使用增强for循环

              ---| Collection      描述所有集合共性的接口

                  ---| List接口     可以有重复元素的集合

                            ---| ArrayList  

                            ---|  LinkedList

                  ---| Set接口      不可以有重复元素的集合

                            ---| HashSet  线程不安全,存取速度快。底层是以哈希表实现的。

 

HashSet

哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同) 是按照哈希值来存的所以取数据也是按照哈希值取得。

HashSet不存入重复元素的规则.使用hashcode和equals

由于Set集合是不能存入重复元素的集合。那么HashSet也是具备这一特性的。HashSet如何检查重复?HashSet会通过元素的hashcode()和equals方法进行判断元素师否重复。

 

练习:使用HashSet存储字符串,并尝试添加重复字符串

       回顾String类的equals()、hashCode()两个方法。

import java.util.HashSet;

import java.util.Iterator;

import java.util.Set;

 

publicclass Demo4 {

    publicstaticvoid main(String[] args) {

       // Set集合存和取的顺序不一致。

       Set hs = new HashSet();

       hs.add("世界军事");

       hs.add("兵器知识");

       hs.add("舰船知识");

       hs.add("汉和防务");

 

       //返回此 set 中的元素的数量

       System.out.println(hs.size());// 4

 

       //如果此 set 尚未包含指定元素,则返回 true

       boolean add = hs.add("世界军事");// false

       System.out.println(add);

 

       //返回此 set 中的元素的数量

       System.out.println(hs.size());// 4

       Iterator it = hs.iterator();

       while (it.hasNext()) {

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

       }

    }

}

 

 

      使用HashSet存储自定义对象,并尝试添加重复对象(对象的重复的判定)

package cn.itcast.gz.map;

 

import java.util.HashSet;

import java.util.Iterator;

 

publicclass Demo4 {

    publicstaticvoid main(String[] args) {

       HashSet hs = new HashSet();

       hs.add(new Person("jack", 20));

       hs.add(new Person("rose", 20));

       hs.add(new Person("hmm", 20));

       hs.add(new Person("lilei", 20));

       hs.add(new Person("jack", 20));

 

       Iterator it = hs.iterator();

       while (it.hasNext()) {

           Object next = it.next();

           System.out.println(next);

       }

    }

}

 

class Person {

    private Stringname;

    privateintage;

 

    Person() {

 

    }

 

    public Person(String name,int age) {

 

       this.name = name;

       this.age = age;

    }

 

    public String getName() {

       returnname;

    }

 

    publicvoid setName(String name) {

       this.name = name;

    }

 

    publicint getAge() {

       returnage;

    }

 

    publicvoid setAge(int age) {

       this.age = age;

    }

 

    @Override

    publicint hashCode() {

       System.out.println("hashCode:" +this.name);

       returnthis.name.hashCode() + age * 37;

    }

 

    @Override

    publicboolean equals(Object obj) {

       System.out.println(this +"---equals---" + obj);

       if (objinstanceof Person) {

           Person p = (Person) obj;

           returnthis.name.equals(p.name) && this.age == p.age;

       } else {

           returnfalse;

       }

    }

 

    @Override

    public String toString() {

 

       return"Person@name:" +this.name +" age:" + this.age;

    }

 

}

 

 

问题:现在有一批数据,要求不能重复存储元素,而且要排序。ArrayList 、 LinkedList不能去除重复数据。HashSet可以去除重复,但是是无序。 

2.4.2.    TreeSet

 

案例:使用TreeSet集合存储字符串元素,并遍历

import java.util.TreeSet;

 

publicclass Demo5 {

    publicstaticvoid main(String[] args) {

       TreeSet ts = new TreeSet();

       ts.add("ccc");

       ts.add("aaa");

       ts.add("ddd");

       ts.add("bbb");

 

       System.out.println(ts);// [aaa, bbb, ccc, ddd]

 

    }

}

 

---| Itreable      接口 实现该接口可以使用增强for循环

              ---| Collection      描述所有集合共性的接口

                  ---| List接口     有序,可以重复,有角标的集合

                            ---| ArrayList  

                            ---|  LinkedList

                  ---| Set接口      无序,不可以重复的集合

                            ---| HashSet  线程不安全,存取速度快。底层是以hash表实现的。

                            ---| TreeSet  红-黑树的数据结构,默认对元素进行自然排序(String)。如果在比较的时候两个对象返回值为0,那么元素重复。

 

比较器接口

----| Comparable

           compareTo(Object o)     元素自身具备比较性

----| Comparator

           compare( Object o1, Object o2 ) 给容器传入比较器

 

TreeSet集合排序的两种方式:

一,让元素自身具备比较性。

也就是元素需要实现Comparable接口,覆盖compareTo 方法。

这种方式也作为元素的自然排序,也可称为默认排序。

年龄按照搜要条件,年龄相同再比姓名。

import java.util.TreeSet;

 

publicclass Demo4 {

    publicstaticvoid main(String[] args) {

       TreeSet ts = new TreeSet();

       ts.add(new Person("aa", 20,""));

       ts.add(new Person("bb", 18,""));

       ts.add(new Person("cc", 17,""));

       ts.add(new Person("dd", 17,""));

       ts.add(new Person("dd", 15,""));

        ts.add(new Person("dd", 15,""));

 

 

       System.out.println(ts);

       System.out.println(ts.size());// 5

 

    }

}

 

class Personimplements Comparable {

    private Stringname;

    privateintage;

    private Stringgender;

 

    public Person() {

 

    }

 

    public Person(String name,int age, String gender) {

 

       this.name = name;

       this.age = age;

       this.gender = gender;

    }

 

    public String getName() {

       returnname;

    }

 

    publicvoid setName(String name) {

       this.name = name;

    }

 

    publicint getAge() {

       returnage;

    }

 

    publicvoid setAge(int age) {

       this.age = age;

    }

 

    public String getGender() {

       returngender;

    }

 

    publicvoid setGender(String gender) {

       this.gender = gender;

    }

 

    @Override

    publicint hashCode() {

       returnname.hashCode() +age * 37;

    }

 

    publicboolean equals(Object obj) {

       System.err.println(this +"equals :" + obj);

       if (!(objinstanceof Person)) {

           returnfalse;

       }

       Person p = (Person) obj;

       returnthis.name.equals(p.name) && this.age == p.age;

 

    }

 

    public String toString() {

       return"Person [name=" +name + ", age=" + age +", gender=" +gender

              + "]";

    }

 

    @Override

    publicint compareTo(Object obj) {

      

       Person p = (Person) obj;

       System.out.println(this+" compareTo:"+p);

       if (this.age > p.age) {

           return 1;

       }

       if (this.age < p.age) {

           return -1;

       }

       returnthis.name.compareTo(p.name);

    }

 

}

 

 

二,让容器自身具备比较性,自定义比较器。

需求:当元素自身不具备比较性,或者元素自身具备的比较性不是所需的。

那么这时只能让容器自身具备。

定义一个类实现Comparator 接口,覆盖compare方法。

并将该接口的子类对象作为参数传递给TreeSet集合的构造函数。

当Comparable比较方式,及Comparator比较方式同时存在,以Comparator

比较方式为主。

import java.util.Comparator;

import java.util.TreeSet;

 

publicclass Demo5 {

    publicstaticvoid main(String[] args) {

       TreeSet ts = new TreeSet(new MyComparator());

       ts.add(new Book("think in java", 100));

       ts.add(new Book("java核心技术", 75));

       ts.add(new Book("现代操作系统", 50));

       ts.add(new Book("java就业教程", 35));

       ts.add(new Book("think in java", 100));

       ts.add(new Book("ccc in java", 100));

 

       System.out.println(ts);

    }

}

 

class MyComparatorimplements Comparator {

 

    publicint compare(Object o1, Object o2) {

       Book b1 = (Book) o1;

       Book b2 = (Book) o2;

       System.out.println(b1+" comparator "+b2);

       if (b1.getPrice() > b2.getPrice()) {

           return 1;

       }

       if (b1.getPrice() < b2.getPrice()) {

           return -1;

       }

       return b1.getName().compareTo(b2.getName());

    }

 

}

 

class Book {

    private Stringname;

    privatedoubleprice;

 

    public Book() {

 

    }

 

    public String getName() {

       returnname;

    }

 

    publicvoid setName(String name) {

       this.name = name;

    }

 

    publicdouble getPrice() {

       returnprice;

    }

 

    publicvoid setPrice(double price) {

       this.price = price;

    }

 

    public Book(String name,double price) {

 

       this.name = name;

       this.price = price;

    }

 

    @Override

    public String toString() {

       return"Book [name=" +name + ", price=" + price + "]";

    }

 

}

 

3.     Map

Map学习体系:

 ---| Map  接口    将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

           ---| HashMap  采用哈希表实现,所以无序

            ---| TreeMap   可以对健进行排序

 

---|Hashtable:

底层是哈希表数据结构,线程是同步的,不可以存入null键,null值。

效率较低,被HashMap 替代。

---|HashMap:

底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。

要保证键的唯一性,需要覆盖hashCode方法,和equals方法。

---|LinkedHashMap:

该子类基于哈希表又融入了链表。可以Map集合进行增删提高效率。

---|TreeMap:

底层是二叉树数据结构。可以对map集合中的键进行排序。需要使用Comparable或者Comparator 进行比较排序。return 0,来判断键的唯一性。

 

常见方法

1、添加:

    1、V put(K key, V value)    (可以相同的key值,但是添加的value值会覆

盖前面的,返回值是前一个,如果没有就返回null)                                         

    2、putAll(Map<? extends K,? extends V> m)  从指定映射中将所有映射关

系复制到此映射中(可选操作)。

2、删除

    1、remove()    删除关联对象,指定key对象

    2、clear()     清空集合对象

3、获取

     1:value get(key); 可以用于判断键是否存在的情况。当指定的键不存在的时候,返

回的是null。

 

3、判断:

    1、boolean isEmpty()   长度为0返回true否则false

    2、boolean containsKey(Object key)  判断集合中是否包含指定的key

3、boolean containsValue(Object value)  判断集合中是否包含指定的value

4、长度:

Int size()

 

 

遍历Map的方式:

1、将map 集合中所有的键取出存入set集合。

       Set<K> keySet()   返回所有的key对象的Set集合

                             再通过get方法获取键对应的值。

2、 values() ,获取所有的值.

       Collection<V> values()不能获取到key对象

3、 Map.Entry对象  推荐使用   重点

       Set<Map.Entry<k,v>> entrySet()

将map 集合中的键值映射关系打包成一个对象

Map.Entry对象通过Map.Entry 对象的getKey,

getValue获取其键和值。

 

 

第一种方式:使用keySet

Map转成Set集合(keySet()),通过Set的迭代器取出Set集合中的每一个元素(Iterator)就是Map集合中的所有的键,再通过get方法获取键对应的值。

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.Set;

 

publicclass Demo2 {

    publicstaticvoid main(String[] args) {

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

       map.put(1, "aaaa");

       map.put(2, "bbbb");

       map.put(3, "cccc");

       System.out.println(map);

 

       //

       //获取方法:

       //第一种方式: 使用keySet

       //需要分别获取keyvalue,没有面向对象的思想

       // Set<K> keySet()返回所有的key对象的Set集合

 

       Set<Integer> ks = map.keySet();

       Iterator<Integer> it = ks.iterator();

       while (it.hasNext()) {

           Integer key = it.next();

           String value = map.get(key);

           System.out.println("key=" + key +" value=" + value);

       }

    }

}

 

 

第二种方式:通过values获取所有值,不能获取到key对象

publicstaticvoid main(String[] args) {

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

       map.put(1, "aaaa");

       map.put(2, "bbbb");

       map.put(3, "cccc");

       System.out.println(map);

// 第二种方式:

       //通过values 获取所有值,不能获取到key对象

       // Collection<V> values()

 

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

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

       while (it.hasNext()) {

           String value = it.next();

           System.out.println(" value=" + value);

       }

}

 

第三种方式: Map.Entry

public static interface Map.Entry<K,V>

通过Map中的entrySet()方法获取存放Map.Entry<K,V>对象的Set集合。

Set<Map.Entry<K,V>> entrySet()

面向对象的思想将map集合中的键和值映射关系打包为一个对象,就是Map.Entry

,将该对象存入Set集合,Map.Entry是一个对象,那么该对象具备的getKey,getValue获得键和值。

publicstaticvoid main(String[] args) {

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

       map.put(1, "aaaa");

       map.put(2, "bbbb");

       map.put(3, "cccc");

       System.out.println(map);

       //第三种方式: Map.Entry对象推荐使用重点

       // Set<Map.Entry<K,V>> entrySet()

      

 

       //返回的Map.Entry对象的Set集合 Map.Entry包含了keyvalue对象

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

 

       Iterator<Map.Entry<Integer, String>> it = es.iterator();

 

       while (it.hasNext()) {

          

           //返回的是封装了keyvalue对象的Map.Entry对象

           Map.Entry<Integer, String> en = it.next();

 

           //获取Map.Entry对象中封装的keyvalue对象

           Integer key = en.getKey();

           String value = en.getValue();

 

           System.out.println("key=" + key +" value=" + value);

       }

    }

 

3.1. HashMap

底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。要保证键的唯一性,需要覆盖hashCode方法,和equals方法。

案例:自定义对象作为Map的键。

 

package cn.itcast.gz.map;

 

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map.Entry;

import java.util.Set;

 

publicclass Demo3 {

    publicstaticvoidmain(String[] args) {

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

       hm.put(new Person("jack", 20),"1001");

       hm.put(new Person("rose", 18),"1002");

       hm.put(new Person("lucy", 19),"1003");

       hm.put(new Person("hmm", 17),"1004");

       hm.put(new Person("ll", 25),"1005");

       System.out.println(hm);

       System.out.println(hm.put(new Person("rose", 18), "1006"));

 

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

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

       while (it.hasNext()) {

           Entry<Person, String> next = it.next();

           Person key = next.getKey();

           String value = next.getValue();

           System.out.println(key +" = " + value);

       }

    }

}

 

class Person {

    private Stringname;

    privateintage;

 

    Person() {

 

    }

 

    public Person(String name,int age) {

 

       this.name = name;

       this.age = age;

    }

 

    public String getName() {

       returnname;

    }

 

    publicvoid setName(String name) {

       this.name = name;

    }

 

    publicint getAge() {

       returnage;

    }

 

    publicvoid setAge(int age) {

       this.age = age;

    }

 

    @Override

    publicint hashCode() {

 

       returnthis.name.hashCode() + age * 37;

    }

 

    @Override

    publicboolean equals(Object obj) {

       if (objinstanceof Person) {

           Person p = (Person) obj;

           returnthis.name.equals(p.name) && this.age == p.age;

       } else {

           returnfalse;

       }

    }

 

    @Override

    public String toString() {

 

       return"Person@name:" +this.name +" age:" + this.age;

    }

 

}

}

 

 

3.2. TreeMap

 

TreeMap的排序,TreeMap可以对集合中的键进行排序。如何实现键的排序?

方式一:元素自身具备比较性

和TreeSet一样原理,需要让存储在键位置的对象实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。

方式二:容器具备比较性

当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。

注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;

注意:在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较次要条件。(假设姓名和年龄一直的人为相同的人,如果想要对人按照年龄的大小来排序,如果年龄相同的人,需要如何处理?不能直接return 0,以为可能姓名不同(年龄相同姓名不同的人是不同的人)。此时就需要进行次要条件判断(需要判断姓名),只有姓名和年龄同时相等的才可以返回0.)

通过return 0来判断唯一性。

import java.util.TreeMap;

 

publicclass Demo4 {

    publicstaticvoid main(String[] args) {

       TreeMap<String, Integer> tree = new TreeMap<String, Integer>();

       tree.put("张三", 19);

       tree.put("李四", 20);

       tree.put("王五", 21);

       tree.put("赵六", 22);

       tree.put("周七", 23);

       tree.put("张三", 24);

       System.out.println(tree);

       System.out.println("张三".compareTo("李四"));//-2094

    }

}

自定义元素排序

package cn.itcast.gz.map;

 

import java.util.Comparator;

import java.util.Iterator;

import java.util.Map.Entry;

import java.util.Set;

import java.util.TreeMap;

 

publicclass Demo3 {

    publicstaticvoidmain(String[] args) {

       TreeMap<Person, String> hm =new TreeMap<Person, String>(

              new MyComparator());

       hm.put(new Person("jack", 20),"1001");

       hm.put(new Person("rose", 18),"1002");

       hm.put(new Person("lucy", 19),"1003");

       hm.put(new Person("hmm", 17),"1004");

       hm.put(new Person("ll", 25),"1005");

       System.out.println(hm);

       System.out.println(hm.put(new Person("rose", 18), "1006"));

 

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

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

       while (it.hasNext()) {

           Entry<Person, String> next = it.next();

           Person key = next.getKey();

           String value = next.getValue();

           System.out.println(key +" = " + value);

       }

    }

}

 

class MyComparatorimplements Comparator<Person> {

 

    @Override

    publicint compare(Person p1, Person p2) {

       if (p1.getAge() > p2.getAge()) {

           return -1;

       } elseif (p1.getAge() < p2.getAge()) {

           return 1;

       }

       return p1.getName().compareTo(p2.getName());

    }

 

}

 

class Personimplements Comparable<Person> {

    private Stringname;

    privateintage;

 

    Person() {

 

    }

 

    public Person(String name,int age) {

 

       this.name = name;

       this.age = age;

    }

 

    public String getName() {

       returnname;

    }

 

    publicvoid setName(String name) {

       this.name = name;

    }

 

    publicint getAge() {

       returnage;

    }

 

    publicvoid setAge(int age) {

       this.age = age;

    }

 

    @Override

    publicint hashCode() {

 

       returnthis.name.hashCode() + age * 37;

    }

 

    @Override

    publicboolean equals(Object obj) {

       if (objinstanceof Person) {

           Person p = (Person) obj;

           returnthis.name.equals(p.name) && this.age == p.age;

       } else {

           returnfalse;

       }

    }

 

    @Override

    public String toString() {

 

       return"Person@name:" +this.name +" age:" + this.age;

    }

 

    @Override

    publicint compareTo(Person p) {

 

       if (this.age > p.age) {

           return 1;

       } elseif (this.age < p.age) {

           return -1;

       }

       returnthis.name.compareTo(p.name);

    }

 

}

 

注意:Set的元素不可重复,Map的键不可重复,如果存入重复元素如何处理

Set元素重复元素不能存入add方法返回false

Map的重复健将覆盖旧键,将旧值返回。

 

4.     Collections与Arrays

集合框架中的工具类:特点:该工具类中的方法都是静态的。

Collections:常见方法:

1, 对list进行二分查找:

前提该集合一定要有序。

int binarySearch(list,key);

//必须根据元素自然顺序对列表进行升级排序

//要求list 集合中的元素都是Comparable 的子类。

int binarySearch(list,key,Comparator);

2,对list集合进行排序。

sort(list);

//对list进行排序,其实使用的事list容器中的对象的compareTo方法

sort(list,comaprator);

//按照指定比较器进行排序

3,对集合取最大值或者最小值。

max(Collection)

max(Collection,comparator)

min(Collection)

min(Collection,comparator)
4,对list集合进行反转。

reverse(list);

5,对比较方式进行强行逆转。

Comparator reverseOrder();

Comparator reverseOrder(Comparator);

6,对list集合中的元素进行位置的置换。

swap(list,x,y);

7,对list集合进行元素的替换。如果被替换的元素不存在,那么原集合不变。

replaceAll(list,old,new);

8,可以将不同步的集合变成同步的集合。

Set synchronizedSet(Set<T> s)

Map synchronizedMap(Map<K,V> m)

List synchronizedList(List<T> list)

9. 如果想要将集合变数组:

可以使用Collection 中的toArray 方法。注意:是Collection不是Collections工具类

传入指定的类型数组即可,该数组的长度最好为集合的size。

 

Arrays:用于对数组操作的工具类

1,二分查找,数组需要有序

binarySearch(int[])

binarySearch(double[])

 

2,数组排序

sort(int[])

sort(char[])……

2, 将数组变成字符串。

 toString(int[])

3, 复制数组。
 copyOf();

4, 复制部分数组。

copyOfRange():

5, 比较两个数组是否相同。

equals(int[],int[]);

6, 将数组变成集合。

List asList(T[]);

这样可以通过集合的操作来操作数组中元素,

但是不可以使用增删方法,add,remove。因为数组长度是固定的,会出现

UnsupportOperationExcetion。

可以使用的方法:contains,indexOf。。。

如果数组中存入的基本数据类型,那么asList会将数组实体作为集合中的元素。

如果数组中的存入的引用数据类型,那么asList会将数组中的元素作为集合中

的元素。

 

import java.util.ArrayList;

import java.util.Collections;

import java.util.Arrays;

import java.util.List;

class Demo1

{

    publicstaticvoid main(String[] args)

    {

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

       list.add(4);

       list.add(3);

       list.add(1);

       list.add(2);

       list.add(3);

       //排序

       Collections.sort(list);

       //折半查找的前提是排序好的元素

       System.out.println( Collections.binarySearch( list , 8 ) ); // 找不到返回-插入点-1

       //反序集合输出

       Collections.reverse( list );

       System.out.println( list );

       //求最值

       System.out.println( Collections.max( list ) );  // 4

       // fill() 使用指定的元素替换指定集合中的所有元素

       // Collections.fill( list, 5 );

       System.out.println( list );

 

       //将数组转换为集合

       Integer is[] = new Integer[]{6,7,8};

       List<Integer> list2 =  Arrays.asList(is);

       list.addAll( list2 );

       System.out.println( list );

 

       //List转换为数组

       Object [] ins =  list.toArray();

       System.out.println( Arrays.toString( ins ) );

  

 

    }

}

0 0