zoukankan      html  css  js  c++  java
  • collection

    如何选择?
    1、容器类和Array的区别、择取
    * 容器类仅能持有对象引用(指向对象的指针),而不是将对象信息copy一份至数列某位置。
    * 一旦将对象置入容器内,便损失了该对象的型别信息。
    2、
    * 在各种Lists中,最好的做法是以ArrayList作为缺省选择。当插入、删除频繁时,使用LinkedList();
    Vector总是比ArrayList慢,所以要尽量避免使用。
    * 在各种Sets中,HashSet通常优于TreeSet(插入、查找)。只有当需要产生一个经过排序的序列,才用TreeSet。
    TreeSet存在的唯一理由:能够维护其内元素的排序状态。
    * 在各种Maps中
    HashMap用于快速查找。
    * 当元素个数固定,用Array,因为Array效率是最高的。
    结论:最常用的是ArrayList,HashSet,HashMap,Array。而且,我们也会发现一个规律,用TreeXXX都是排序的。

    注意:
    1、Collection没有get()方法来取得某个元素。只能通过iterator()遍历元素。
    2、Set和Collection拥有一模一样的接口。
    3、List,可以通过get()方法来一次取出一个元素。使用数字来选择一堆对象中的一个,get(0)...。(add/get)
    4、一般使用ArrayList。用LinkedList构造堆栈stack、队列queue。
    5、Map用 put(k,v) / get(k),还可以使用containsKey()/containsValue()来检查其中是否含有某个key/value。
    HashMap会利用对象的hashCode来快速找到key。
    * hashing
    哈希码就是将对象的信息经过一些转变形成一个独一无二的int值,这个值存储在一个array中。
    我们都知道所有存储结构中,array查找速度是最快的。所以,可以加速查找。

    发生碰撞时,让array指向多个values。即,数组每个位置上又生成一个梿表。
    6、Map中元素,可以将key序列、value序列单独抽取出来。
    使用keySet()抽取key序列,将map中的所有keys生成一个Set。
    使用values()抽取value序列,将map中的所有values生成一个Collection。
    为什么一个生成Set,一个生成Collection?那是因为,key总是独一无二的,value允许重复。

    Java集合就是一个容器。面向对象语言对事物的体现都是以对象的形式存在,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。如果往集合里存放基本数据类型,在存取过程中会有个自动装箱和拆箱。

        因为容器中数据结构不同,容器有很多种。不断地将共性功能向上抽取,形成了集合体系,称之为集合框架。

        集合框架的顶层就称之为Collection接口。所有的集合类都位于java.util包下,查阅API可以得到如下体系结构。在使用一个体系时,原则:参阅顶层内容。建立底层对象。

        集合和数组的区别:

      1:数组是固定长度的;集合可变长度的。

      2:数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。

      3:数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。

    Collection<E>接口

        Collection:单列集合

             |--List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引,允许重复元素。

             |--Set:无序(存入和取出顺序有可能不一致),不允许重复元素,必须保证元素的唯一性。

        java.util.Collection接口中的共性方法有:

        1.添加:
           boolean add(Object obj):一次添加一个。
           boolean addAll(Collection c):将指定容器中的所有元素添加。

        2.删除:
           void clear():将集合中的元素全删除,清空集合。
           boolean remove(Object o):删除集合中指定的对象。注意:删除成功,集合的长度会改变。
           boolean removeAll(Collection c):删除部分元素。部分元素和传入Collection一致。

        3.取交集:
           boolean retainAll(Collection c):对当前集合中保留和指定集合中的相同的元素。
           如果两个集合元素相同,返回false;如果retainAll修改了当前集合,返回true。

        4.获取长度:
           int size():集合中有几个元素。

        5.判断:
           boolean isEmpty():集合中是否有元素。 
           boolean contains(Object o):集合中是否包含指定元素。
           boolean containsAll(Collection c)集合中是否包含指定的多个元素。

        6.将集合转成数组。
           toArray()
           toArray([])

     

    package ustc.lichunchun.collection.demo;

    import java.util.ArrayList;
    import java.util.Collection;

    public class CollectionDemo {
    public static void main(String[] args) {
    Collection coll = new ArrayList();
    methodDemo(coll);
    System.out.println("------------------");
    methodAllDemo();
    }
    /*
    * 演示Collection中的基本功能。
    */
    public static void methodDemo(Collection coll){

    //1.添加元素。
    coll.add("abc1");
    coll.add("abc2");
    coll.add("abc3");

    //2.删除
    coll.remove("abc2");//移除和添加元素 --> 会改变集合的长度 --> 集合里面实际上存的是对象们的引用

    //3.清除。
    coll.clear();

    //4.判断包含。
    System.out.println("contains: "+coll.contains("abc1"));//底层实现判断用的是equals()

    System.out.println(coll);
    }

    /*
    * 演示带All的方法。
    */
    public static void methodAllDemo(){

    //1.创建两个容器。
    Collection c1 = new ArrayList();
    Collection c2 = new ArrayList();

    //2.添加元素。
    c1.add("abc1");
    c1.add("abc2");
    c1.add("abc3");
    c1.add("abc4");

    c2.add("abc2");
    c2.add("abc3");
    c2.add("abc5");

    //往c1中添加c2。
    c1.addAll(c2);

    //判断c1中是否包含c2中的所有元素。
    boolean b = c1.containsAll(c2);
    System.out.println("b = "+b);

    //从c1中删除c2。将c1中和c2相同的元素从c1中删除。
    c1.removeAll(c2);

    //将c1中和c2不同的元素从c1中删除。保留c1中和c2相同的元素。
    c1.retainAll(c2);
    System.out.println(c1);
    }
    }

     

     Collection 接口中明明没有toString()声明,怎么可能有权利调用这个ArrayList类的"特有"方法? (虽然ArrayList类继承它父类有toString()复写的方法了,但这个是ArrayList子类特有的方法啊,不符合多态的解释呀?)

     

    楼主懂得思考,先表扬一下。下面将引用一段接口的说明,你可以看看:
    9.2 Interface Members
    The members of an interface are:Those members declared in the interface.
    Those members inherited from direct superinterfaces.
    If an interface has no direct superinterfaces, then the interface implicitly declares a public abstract member method m with signature s, return type r, and throws clause t corresponding to each public instance method m with signature s, return type r, and throws clause t declared in Object, unless a method with the same signature, same return type, and a compatible throws clause is explicitly declared by the interface. It is a compile-time error if the interface explicitly declares such a method m in the case where m is declared to be final in Object.

    大致意思如下:
    9.2 接口方法
    一个接口中的方法有:
    1).直接声明在接口中的成员方法;
    2).直接从父类接口中继承而来的方法;
    3).如果一个接口没有直接的父类接口(也就是其自身就是顶层接口),并且在其没有显示声明相关方法时,那该接口则会根据Object中所有的public的实例方法进行一一映射(比如toString,Hashcode等)。当然如果此接口显示去声明一个与Object签名相同并且带有final修饰的方法时,则会有编译期错误。

    所以:由超类声明,子类来new。调用的最终是子类中定义的方法,如果子类没有,则调用子类的父类方法。这存在一种向上追溯的过程。说明是完全正确的。


    根据这一条说明,在List list=new ArrayList()之后,在list当中将可以调用object当中所有声明public的方法,而调用的方法实体是来自ArrayList的。而之所以没有list不可以调用,clone()与finalize()方法,只是因为它们是protected的。
    学习了。

    
    
     

     Iterator<E>接口

     

     java.util.Iterator接口是一个对 collection 进行迭代的迭代器,作用是取出集合中的元素。

        Iterator iterator():获取集合中元素上迭代功能的迭代器对象。

        迭代:取出元素的一种方式。有没有啊?有!取一个。还有没有啊?有!取一个。还有没有啊?没有。算了。

        迭代器:具备着迭代功能的对象。迭代器对象不需要new。直接通过 iterator()方法获取即可。

        迭代器是取出Collection集合中元素的公共方法。

    
    
     

    每一个集合都有自己的数据结构,都有特定的取出自己内部元素的方式。为了便于操作所有的容器,取出元素,将容器内部的取出方式按照一个统一的规则向外提供,这个规则就是Iterator接口。

        也就说,只要通过该接口就可以取出Collection集合中的元素,至于每一个具体的容器依据自己的数据结构,如何实现的具体取出细节,这个不用关心,这样就降低了取出元素和具体集合的耦合性。

        Iterator it = coll.iterator();//获取容器中的迭代器对象,至于这个对象是是什么不重要。这对象肯定符合一个规则Iterator接口。

     

    package ustc.lichunchun.collection.demo;

    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Iterator;

    public class IteratorDemo {

    public static void main(String[] args) {

    //1.创建集合。
    Collection coll = new ArrayList();

    coll.add("abc1");
    coll.add("abc2");
    coll.add("abc3");

    //方式一:获取该容器的迭代器。
    Iterator it = coll.iterator();
    while(it.hasNext()){
    System.out.println(it.next());
    }

    //方式二:直接for+alt+/,选择第三个。
    for (Iterator it = coll.iterator(); it.hasNext();) {
    System.out.println(it.next());
    }

    System.out.println(it.next());//abc1
    System.out.println(it.next());//abc2
    System.out.println(it.next());//abc3
    System.out.println(it.next());//java.util.NoSuchElementException

    }

    
    
     

     为了降低容器的数据结构和取出容器元素的方法之间的耦合性,把访问、取出容器元素的容器的内部类进行共性抽取,即各种容器的相应内部类都实现了Iterator接口,实现了hasNext()、next()、remove()方法。例如如下截取自ArrayList类的iterator()方法的底层实现代码

     

    public Iterator<E> iterator() {
    return new Itr();//取出ArrayList容器中元素的迭代器功能,返回的是一个Itr()迭代器对象,也就是实现Iterator接口的内部类对象。
    }

    /**
    * An optimized version of AbstractList.Itr
    */
    private class Itr implements Iterator<E> {//-->ArrayList容器的内部类,实现了Iterator迭代接口(迭代器),里面有hasNext()、next()、remove()方法。
    int cursor; // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;

    public boolean hasNext() {
    return cursor != size;
    }

    @SuppressWarnings("unchecked")
    public E next() {
    checkForComodification();
    int i = cursor;
    if (i >= size)
    throw new NoSuchElementException();
    Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length)
    throw new ConcurrentModificationException();
    cursor = i + 1;
    return (E) elementData[lastRet = i];
    }

    public void remove() {
    if (lastRet < 0)
    throw new IllegalStateException();
    checkForComodification();

    try {
    ArrayList.this.remove(lastRet);
    cursor = lastRet;
    lastRet = -1;
    expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
    throw new ConcurrentModificationException();
    }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void forEachRemaining(Consumer<? super E> consumer) {
    Objects.requireNonNull(consumer);
    final int size = ArrayList.this.size;
    int i = cursor;
    if (i >= size) {
    return;
    }
    final Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length) {
    throw new ConcurrentModificationException();
    }
    while (i != size && modCount == expectedModCount) {
    consumer.accept((E) elementData[i++]);
    }
    // update once at end of iteration to reduce heap write traffic
    cursor = i;
    lastRet = i - 1;
    checkForComodification();
    }

    final void checkForComodification() {
    if (modCount != expectedModCount)
    throw new ConcurrentModificationException();
    }
    }

    
    
     

     List<E>接口

     List本身是Collection接口的子接口,具备了Collection的所有方法。List集合的具体子类:子类之所以区分是因为内部的数据结构(存储数据的方式)不同。

       List:有序(元素存入集合顺序和取出一致),元素都有索引,允许重复元素-->自定义元素类型都要复写equals方法。
            |--Vector:底层的数据结构是数组。数组是可变长度的。线程同步的。增删和查询都巨慢!
            |--ArrayList:底层的也是数组结构,也是长度可变的。线程不同步的,替代了Vector。增删速度不快。查询速度很快。(因为在内存中是连续空间)
            |--LinkedList:底层的数据结构是链表,线程不同步的。增删速度很快。查询速度较慢。(因为在内存中需要一个个查询、判断地址来寻找下一元素)

        可变长度数组的原理:
        不断new新数组并将原数组元素复制到新数组。即当元素超出数组长度,会产生一个新数组,将原数组的数据复制到新数组中,再将新的元素添加到新数组中。

        ArrayList:是按照原数组的50%延长。构造一个初始容量为 10 的空列表。

        Vector:是按照原数组的100%延长。

        首先学习List体系特有的共性方法,查阅方法发现List的特有方法都有索引(角标),这是该集合最大的特点。也就是说,List的特有方法都是围绕索引(角标)定义的。

        List集合支持对元素的增、删、改、查。

        1.添加(增):
            add(index, element):在指定的索引位插入元素。
            addAll(index, collection):在指定的索引位插入一堆元素。

        2.删除(删):
            remove(index):删除指定索引位的元素。 返回被删的元素。

        3.获取(查):
            element get(index):通过索引获取指定元素。
            int indexOf(element):获取指定元素第一次出现的索引位,如果该元素不存在返回—1;所以,通过—1,可以判断一个元素是否存在。
            int lastIndexOf(element) :反向索引指定元素的位置。
            List subList(start,end) :获取子列表。

        4.修改(改):
            element set(index, newElement):对指定索引位进行元素的修改。

        下面的代码演示了List的特有方法:

     

    package ustc.lichunchun.list.demo;

    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;

    public class ListDemo {

    public static void main(String[] args) {
    List list = new ArrayList();
    methodDemo(list);
    }
    /*
    * 演示List特有的方法。
    */
    public static void methodDemo(List list){
    //1.常规添加元素。
    list.add("abc1");
    list.add("abc2");
    list.add("abc3");

    //2.插入元素。
    list.add(1,"hehe");

    //3.删除。
    list.remove(1);
    list.remove(1);

    //4.获取。
    System.out.println(list.get(3));// java.lang.IndexOutOfBoundsException
    System.out.println(list.get(1));
    System.out.println(list.indexOf("abc3"));

    //5.修改。
    list.set(1,"keke");

    System.out.println(list);

    //6.取出集合中所有的元素。
    for (Iterator it = list.iterator(); it.hasNext();) {
    System.out.println("iterator: "+it.next());
    }

    //7.List集合特有的取出方式。遍历。
    for (int i = 0; i < list.size(); i++) {
    System.out.println("get: "+list.get(i));
    }
    }
    }

    
    
     

     什么时候使用Map集合呢?

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

     

    package ustc.lichunchun.map;

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

    import ustc.lichunchun.exception.NoWeekException;

    public class MapTest {

    public static void main(String[] args) {
    /*
    * 什么时候使用map集合呢?
    * 当需求中出现映射关系时,应该最先想到map集合。
    */
    String cnWeek = getCnWeek(3);
    System.out.println(cnWeek);
    String enWeek = getEnWeek(cnWeek);
    System.out.println(enWeek);
    }

    /*
    * 根据中文的星期,获取对应的英文星期。
    * 中文与英文相对应,可以建立表,没有有序的编号,只能通过map集合。
    */
    public static String getEnWeek(String cnWeek){
    //创建一个表。
    Map<String,String> map = new HashMap<String, String>();
    map.put("星期一","Monday");
    map.put("星期二","Tuesday");
    map.put("星期三","Wednesday");
    map.put("星期四","Thursday");
    map.put("星期五","Friday");
    map.put("星期六","Saturday");
    map.put("星期日","Sunday");
    return map.get(cnWeek);
    }

    /*
    * 根据用户指定的数据获取对应的星期。
    */
    public static String getCnWeek(int num){
    if (num>7 || num<=0)
    throw new NotWeekException(num+", 没有对应的星期");
    String[] cnWeeks = {"","星期一","星期二","星期三","星期四","星期五","星期六","星期日"};
    return cnWeeks[num];
    }
    }

     
     

    package ustc.lichunchun.exception;

    public class NotWeekException extends RuntimeException {

    /**
    *
    */
    private static final long serialVersionUID = 1L;

    public NotWeekException() {
    super();
    }

    public NotWeekException(String message, Throwable cause,
    boolean enableSuppression, boolean writableStackTrace) {
    super(message, cause, enableSuppression, writableStackTrace);
    }

    public NotWeekException(String message, Throwable cause) {
    super(message, cause);
    }

    public NotWeekException(String message) {
    super(message);
    }

    public NotWeekException(Throwable cause) {
    super(cause);
    }

    }

     
     
     
  • 相关阅读:
    运算
    使用mysql出现错误:com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column '??????' in 'field list'
    POI-HSSF and POI-XSSF
    java pio项目使用
    mysql安装及卸载
    pdf转word
    【android studio】android studio使用过程中,搜集的一些问题
    github提交失败并报错java.io.IOException: Authentication failed:
    收集的github的东西
    Material Design
  • 原文地址:https://www.cnblogs.com/yunfeioliver/p/9207236.html
Copyright © 2011-2022 走看看