• 容器-Collection子类接口List和Set


    容器:是用来装数据的

    1.数组
    优点:可以根据索引快速的定位到某个元素,访问速度特别快
    缺点:长度是固定的,如果数组满了,需要考虑扩容,并且删除和插入元素时,需要移动元素.
    需要另一个变量,例如:total,来辅助记录实际有效元素的个数.
    2.集合
    集合是新设计的一组容器,具有各种特点.
    数据结构
    栈,队列,链表,堆,图,树,哈希表

    无论多复杂,都是从一下两种物理结构的基础上构建出来的:
    (1)数组
    在内存中需要开辟连续的存储空间,有可能有很多空余的空间
    元素类型:就是数据的类型
    (2)链式
    在内存中不需要连续的空间,不会有空闲空间.
    元素类型:结点类型
    结点类型:
    单向链表
    class Node{
    Object data;
    Node next;
    }
    双向链表
    class Node{
    Node previous;
    Object data;
    Node next;
    }

    class Node{
    Node parent;
    Object data;
    Node left;
    Node right;
    }

    数组:
    缺点:(1)长度固定,如果要扩容等需要程序自己维护,如果要删除和插入,程序员要移动元素等.
    (2)数组只支持可重复,顺序存储的特点,比较单一.

    实际开发中,数据的存储特点:(1)有序的(2)无序的(3)可以重复的(4)不能重复的(5)一对一的(6)一对多的....
    JDK在数组和链式结构的基础上,重新设计了很多的容器类型.

    主要是两大类:
    1.Collection:一组对象,比喻"单身party"
    2.Map:键值对,(key,value),比喻"情侣party","家庭party"

    容器有共同的行为特征,操作方式:增删改查

    把对容器的操作的行为标准化,用接口来声明.

    一 java.util.Collection
    (一)Collection的概述
    Collection层次结构中的根接口.Collection表示一组对象.
    一些Collection允许有重复的元素,二另一些不允许,一些Collection时有序的,而另一些时无序的.
    JDK不提供此接口的任何直接实现:它提供更具体的子接口(如Set和List)实现
    1.List
    列表:可重复的,有序的和添加顺序有关系(按顺序存储)
    实现类:例如ArrayList(动态数组)
    2.Set
    集:不可重复的,无序的(和添加顺序无关)
    (二)Collection的常用方法
    1.添加
    (1)add(Object obj):一次添加一个
    (2)addAll(Collection other):一次添加多个,把other中的元素都添加到当前集合中,this = this 并 other
    2.删除
    (1)remove(Object obj):一次删除一个
    (2)removeAll(Collection other):一次删除多个,删除other与this交的交集的元素.
    (3)clean()清空
    3.修改:Collection中没有提供修改的方法
    4.查找
    (1)Boolean contains(Object obj):判断obj是否在当前集合中
    (2)Boolean containsAll(Collection c):判断c是否为this的子集
    (3)Boolean isEmpty()
    Collection接口中没有提供获取一个元素的方法

    5.获取有效元素的个数 int size()
    6.遍历
    (1)老方法
    Object[] toArray():如果该集合的底层是数组,那么可以用这种方法,如果其底层不是数组,用数组遍历会比较浪费时间浪费空间,无论底层怎么样,都会返回一个尺寸为size的数组.
    (2)foreach:称为增强版for循环
    语法结构:for(元素的类型 元素名:可迭代的容器名)
    把元素名理解为形参,每循环一次,就把数组或集合的元素以此作为实参赋值给形参,
    即:如果元素类型是基本数据类型,那么把数组或者集合的元素"数据值"赋值给它,那么对他怎么修改和实参无关.
    如果元素是引用数据类型,那么把数组或者集合的元素"地址值"赋值给他,那么对他的属性修改和实参有关.对他的地址修改和实参无关.

    结论:如果你只是查看数组或者集合的元素,用foreach比较简单,如果是修改,就考虑其他的循环方式.

    (3)Iterator迭代器遍历
    java.util.Iterator迭代器:用于遍历(迭代)Collection系列集合用的.

    步骤:
    (1)先通过Collection系列集合,对象拿到迭代器对象
    (2)再通过Iterator的方法进行迭代.
    boolean hasNext():判断集合中是否有下一个元素
    Object next():取出下一个元素
    void remove():删除刚刚取出的元素,用于根据条件删除

    在集合中,涉及到对象的比较,用的都是equals方法进行比较,分为空和不空两种讨论方式,如果在原来的元素所在类中没有重写equals方法,就会比较两个元素的地址值。


    下图为利用foreach方法遍历并且想删除元素的操作,报错了,针对引用数据类型.

    7.其他
    retainAll(Collection c):保留this与c的交集

    java.util.List:接口
    (1)有序:可以对元素的索引index,进行控制
    (2)可重复。

    常用方法:
    继承了Collection,因此Collection的所有的方法和操作它都有。
    List还增加了很多方法,这些方法都和index有关系。

    1.添加
    add(int index,E element):在index位置插入一个元素
    addAll(int index,Collection<? extends E> c):在index位置插入多个元素
    2.删除
    remove(int index)
    删除指定索引位置的元素
    3.改
    Collection中没有提供关于修改的操作方法
    set(int index,E element)
    修改指定索引位置的元素为element
    4.查询
    int indexOf(E element):从左往右找
    int lastIndexOf(Eelement):从右往左找
    因为List是可以重复的集合,所以设置了两种查找顺序。
    get(int index):返回指定位置的元素
    subList(int fromIndex,int toIndex):截取[fromIndex,toIndex)
    5.遍历
    (1)toArray()
    (2)foreach
    (3)Iterator
    (4)listIterator
    listIterator是Iterator的子接口,Iterator的功能方法,listIterator
    也有,还增加了一些功能
    A:Iterator只能从前往后遍历
    listIterator可以从任意位置开始,从前往后,或者从后往前遍历。
    listIterator的使用步骤:
    (1)先获取listIterator的对象,获取方式为:集合对象.listIterator()
    (2)通过遍历方法
    hasNext()+next()
    hasPrevious()+previous()
    B:不仅可以在遍历中删除了,还增加了set和add方法。

    //从前往后遍历
    ListIterator listIterator = c.listIterator();//默认迭代器指向最前面
    while(listIterator.hasNext()){
    Object next = listIterator.next();
    System.out.println(next);
    }
    //从后往前遍历
    ListIterator listIterator = c.listIterator(list.size());
    while(listIterator.hasPrevious()){
    Object previous = listIterator.previous();
    System.out.println(previous);
    }
    //从第三个元素位置开始遍历
    ListIterator listIterator = c.listIterator(3);
    while(listIterator.hasPrevious()){
    Object previous = listIterator.previous();
    System.out.println(previous);
    }

    List常见的实现类
    1.Vector:动态数组
    内部实现:数组,初始大小为10
    2.ArrayList:动态数组
    内部实现:数组,初始大小为10
    3.LinkedList:双向链表,双端队列:又是Queue和Deque的实现子类
    内部实现:链表
    4.Stack:栈,又是Vector的子类
    Stack:后进先出(LIFO)(Last in first out)、先进后出(FILO)(First in last out)
    压栈:push;弹栈:pop(移除栈顶元素);peek(返回栈顶元素,但不移除)

    (接口)Queue(队列)(extends Collection):先进先出(FIFO)
    添加到队列offer(e),移出队列poll(),返回队头但不移除peek()

    (接口)Deque(extends Queue):(Double ended queue)双端队列:队头和队尾都可以添加元素和移除元素。不支持通过索引来访问元素
    offerFirst(e)offerLast(e)
    pollFirst()pollLast()
    peekFirst()peekLast()

    面试题:Vector和ArrayList有什么区别?
    Vector:旧版,线程安全的,当空间不够时,扩容为原来的两倍。支持的迭代方式更多,支持旧版Enumeration迭代器
    ArrayList:新版,线程不安全的,当空间不够时,扩容为原来的1.5倍。不支持旧版的Enumeration迭代器。

    面试题:动态数组和LinkedList有什么区别?
    (1)内部实现不同
    动态数组底层是数组
    LinkedList底层是链表,元素的类型是Node
    (2)动态数组:对索引的相关操作,效率很高
    链表:对索引的相关操作,效率比较低
    (3)动态数组:插入和删除操作涉及到元素的移动,时间复杂度高
    链表:插入和删除操作只涉及到前后元素的关系。

    结论:如果后面的操作针对索引更多,那么选择动态数组,如果是添加和删除的操作更多,那么选择链表。

    java.util.Set(接口)
    (1)不支持重复
    (2)无序的(和添加顺序无关)
    set中没有新添加方法,都是Collection的方法

    Set:实现子类
    (1)HashSet:完全无序
    说明:
    判断元素是否重复,是参考equals方法,如果equals方法在元素的类中没有被重写,则默认比较地址值。
    (2)TreeSet:大小顺序,和添加顺序无关,如果添加元素为引用数据类型,比如Student等,这个类需要实现Comparable,然后复写compareTo的方法。
    说明:
    判断元素是否重复,依据是元素复写的compareTo方法。
    (3)LinkedHashSet:遍历时可以保证添加顺序,存储和添加顺序无关。
    说明:
    判断元素是否重复,是参考equals方法,如果equals方法在元素的类中没有被重写,则默认比较地址值。

    LinkedHashSet是HashSet的子类,但是它的元素比HashSet的元素要多维护一个添加的顺序。
    LinkedHashSet的效率就比HashSet低,每次添加,删除要同时考虑顺序。但是前者迭代中受到容量的影响较小。

    结论:
    如果既要元素不重复,又要按大小,选TreeSet
    如果既要元素不重复,又要保证添加顺序,选LinkedHashSet
    如果只要元素不重复,选HashSet

    使用HashSet为容器承载数据元素的话,如果要求某个属性一样就认为是同一种元素,这种时候需要重写hashCode()和equals()方法。
    重写要求:
    (1)必须一起重写。
    (2)hashCode值相同,不一定相同
    hashCode值不同,equals一定不相同
    equals相同,hashCode值一定相同。

    要求:
    参与hashCode值计算的属性,就要做equals的比较。
    (3)equals的方法重写遵循几个原则
    对称性、自反性、传递性、一致性、非空与null比较返回false。
    参考:Object的equals的API。

    实际情况分析:在实际中,我们可能遇到这样的情况,一次可能需要一个对象的一个元素属性进行排序,那么此时我们会使此对象类实现Comparable接口,进而重写compareTo方法,制定好排序的依据,然后利用treeSet容器进行承载,遍历之后的结果就依据compareTo定义排好了顺序。紧接着有要求依据元素对象的另一个属性进行排序,比如价钱,那么此时再回去重写compareTo方法就很麻烦,而且丧失了之前的排序依据,此时就可以在定义treeSet容器时,传入一个比较器,那么系统会优先考虑比较器中的排序依据,传入的比较器需要重写compare方法,此方法的返回值是int类型,而比较的属性可能是double类型,不能强制转换成int,因为这样会失去精度,并且影响比较结果。此时有三种处理方法:
    (1)用compare方法中传入的两个对象.属性进行比较,如果前大后小,返回值为1
    如果前小后大,返回值为-1;否则返回值为0.此方法精度有限
    (2)利用Double的静态compare方法,将被比较的两个对象.属性传入Double的compare方法,返回值类型为int。
    (3)将比较器中compare方法中传入的两个对象.属性利用Double.doubleToLongBits方法转成long类型数据,然后利用Long.compare(long x,long y)进行比较,返回值为int,此方法是1.8之后加进来的。

  • 相关阅读:
    python初步学习-查看文档及数据类型转换
    python初步学习-python数据类型-集合(set)
    python初步学习-python数据类型-字典(dict)
    python初步学习-python数据类型-列表(list)
    python初步学习-python数据类型之strings(字符串)
    python初步学习-python数据类型之number(数值)
    python初步学习-python运算符
    python初步学习-pycharm使用 (二)
    python初步学习-pycharm使用
    yarn npm 镜像切换
  • 原文地址:https://www.cnblogs.com/1185937986-jili/p/12887945.html
Copyright © 2020-2023  润新知