一、数组与集合

  1. 集合与数组存储数据概述:
    集合、数组都是对多个数据进行存储操作的结构,简称Java容器
    说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt .jpg .avi 数据库中)
  2. 数组存储的特点:
    一旦初始化以后,其长度就确定了
    数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。
  3. 数组存储的弊端:
    一旦初始化成功以后,其长度就不可修改
    数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高
    获取数组中实际元素的个数的需求,数组中没有现成的属性或方法可用
    数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。
  4. 集合存储的优点:
    解决数组存储数据方面的弊端

二、Collection接口

  1. 单列集合框架结构
    Collection接口:单列集合,用来储存一个一个的对象
  • HashSet、LinkedHashSet、TreeSet
  • ArrayList、LinkedList、Vector
  • List接口:存储序的、可重复的数据。--> “动态”数组
  • Set接口:存储无序的、不可重复的数据。-->高中讲的“集合”

java 判断两个list 是否存在某个属性一样的 java如何判断两个集合相等_判断集合相等

image-20200827195306769

  1. Collection接口常用方法:
// 添加add(Object object);addAll(Collection coll);// 获取有效元素个数int size()// 清空集合void clear()    // 是否是空集合boolean isEmpty();// 是否包含某个元素boolean contains(Object obj); // 通过元素的equals方法来判断是否是同一个对象boolean containsAll(Collection c); // 也是调用元素的equals方法来比较的。拿两个集合的元素挨个比较。// 删除boolean remove(Object obj); // 通过元素的equals方法判断是否是要删除的那个元素。只会删除找到的第一个元素。boolean removeAll(Colleation coll); // 取当前集合的差集// 取两个集合的交集boolean retainAll(Colleation c); // 把交集的结果存在当前集合中,不影响c// 集合是否相等boolean equals(Object obj);// 转成对象数组Object[] toArray();// 获取集合对象的哈希值hashCode();// 遍历iterator(); // 返回迭代器对象,用于集合遍历

三、Iterator接口

Iterator接口称为迭代器(设计模式的一种),主要用于遍历Collection集合中的元素。

Collection接口继承了java.lang.Iterable接口,该接口有一个iterator()方法,那么所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象。

Iterator仅用于遍历集合,Iterator本身并不提供承装对象的能力。如果需要创建Iterator对象,则必须有一个被迭代的集合。

集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。

Iterator iterator = coll.iterator();// 迭代器的使用while(iterator.hasNext()){    iterator.next();}

四、Collection接口的子接口:List接口

1. 概述

  • 鉴于Java中数组用来存储数据的局限性,我们通常使用List替代数组
  • List集合类中元素有序、且可重复,集合中的每个元素都有其对应的顺序索引。
  • List容器中的元素都对应一个整型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
  • JDK API中List接口的实现类常用的有:ArrayList、LinkedList和Vector

面试题:ArrayList、LinkedList和Vetor三者的异同?

同:三个类都实现了List接口,存储数据的特点相同:存储有序的、可重复的数据

异:

  • ArrayList:作为List接口的主要实现类;线程不安全的,效率高;底层使用Object[] elementData存储
  • LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;底层使用双向链表存储
  • Vector:作为List接口的古老实现类;线程安全的,效率低;底层使用Object[] elementData存储

2. ArrayList源码分析

2.1 jdk7情况下
ArrayList list = new ArrayList(); // 底层创建了长度是10的Object[]数组elementDatalist.add(123); // elementData[0] = new Integer(123);...list.add(111); // 如果此次的添加导致底层elementData数组容量不够,则扩容// 默认情况下。扩容为原来容量的1.5倍,同时需要将原有数组中数据复制到新的数组中结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity)
2.2 jdk8情况下
ArrayList list = new ArrayList(); // 底层Object[] elementData初始化为{}并没有创建长度为10的数组list.add(123); // 第一次调用add()时,底层才创建了长度为10的数组,并将数据123添加到elementData数组中...后续的添加操作与jdk7无异
2.3 小结:

jdk7中的ArrayList的创建类似于单例的饿汉式,而jdk8中的ArrayList的对象的创建类似于单例的懒汉式,延迟了数组的创建,节省内存。

3. LinkedList源码分析

LinkedList list = new LinkedList(); // 内部声明了Node类型的first和last属性,默认值为nulllist.add(123); // 将123封装到Node中,创建了Node对象

4. Vector源码分析

jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组,在扩容方面,默认扩容为原来数组长度的两倍

5. List接口中的常用方法

// 在index位置插入ele元素void add(int index, Object ele);// 从index位置开始将eles中的所有元素添加进来boolean addAll(int index, Collection eles);// 获取指定index位置的元素Object get(int index);// 返回obj在集合中首次出现的位置int indexOf(Object obj);// 返回obj在当前集合中末次出现的位置int LastIndexOf(Object obj);// 移除指定index位置的元素,并返回此元素Object remove(int index);// 设置指定index位置的元素为eleObject set(int index, Object ele);// 返回从fromIndex到toIndex位置的子集合List subList(int fromIndex, int toIndex);

五、Collection接口的子接口:Set接口

1. 概述

  • Set接口是Collection的子接口,Set接口没有提供额外的方法
  • Set集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set集合中,则添加操作失败
  • Set判断两个对象是否相同不是使用==运算符,而是根据equals()方法
  • 对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码。”

HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值

LinkedHashSet:作为HashSet的一个子类;遍历其数据时,可以按照添加的顺序遍历

TreeSet:可以按照添加的对象的指定属性,进行排序

2. HashSet的使用

向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断数组此位置上是否已经有元素:

如果此位置上没有其他元素,则元素a添加成功。—> 情况1

如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:

  • 如果hash值不相同,则元素a添加成功。—> 情况2
  • 如果hash值相同,进而需要调用元素a所在类的equals()方法:
  • equals()返回true,元素a添加失败
  • equals()返回false,元素a添加成功。—> 情况3

对于添加成功的情况2和情况3而言:元素a 与已经存在指定索引位置上的数据以链表的方式存储

jdk7:元素a放到数组中,指向原来的元素

jdk8:原来的元素在数组中,指向元素a

总结:7上8下

HashSet底层:数组+链表的结构

3. LinkedHashSet 的使用

LinkedHashSet作为HashSet的子类,再添加数据的同时,每个数据还维护了两个引用,记录了此数据前一个数据和后一个数据

优点:对于频繁的遍历操作,LinkedHashSet执行效率高于HashSet

4. TreeSet的使用(了解内容)

  • 向TreeSet添加的数据必须是同一个类的对象
  • 排序方式分为自然排序(实现Comparable接口)和自定义排序(Comparator)
  • 自然排序中,比较两个对象是否相同的标准为:compareTo()返回0.不再是equals()
  • 定制排序中,比较两个对象是否相同的标准为:compare()返回0.不再是equals()