第五周——集合、ArrayList、TreeSet

1

一、    回忆数组

1.1数组

 存储同一数据类型的集合容器。

1.2数组的特点

1.只能存储同一种数据类型的数据。

2.一旦初始化,长度固定。

3.数组中的元素与元素之间的内存地址是连续的。

1.3注意事项

Object类型的数组可以存储任意类型的数据。

二、为什么要学习集合

2.1需求

收集我们班同学的兴趣爱好。

数组存储兴趣爱好:

     String[]  arr = new String[];

难处在于,无法初始化数组的长度,因为每个人的兴趣爱好都不一样,有的人有很多的兴趣爱好,有的人的兴趣爱好比较少。如果给的太短,无法满足兴趣多的人,给的特别长的话浪费空间。

2.2集合

集合是存储对象数据的集合容器。

     集合比数组的优势:

      -1.集合可以存储任意类型的数据对象,数组只能存储同一种数据类型的数据。

      -2.集合的长度是会发生变化的,数据的长度是固定的。

2.3规范

 

如上图所示,各种各样的形状都是容器,这样的话不利于管理,于是乎,就需要一种规范来约束。在java中接口是用来约束的。也就是说,接口定义了容器的规范,所以说,如果,类实现了规范接口的接口,那么,这个类就是容器。

-----------| Collection    单例集合的根接口。

-------------------|List     Collection的子接口。

-------------------|Set     Collection的子接口。

List:如果是实现了List接口的集合类,具备的特点:有序,可重复。

Set:如果是实现了Set接口的集合类,具备的特点:无序,不可重复。

三、Collection接口

3.1增加

add(E e)  添加成功返回true,添加 失败返回false.

addAll(Collection c)  把一个集合 的元素添加到另外一个集合中去。

 

3.2删除

clear()

remove(Object o)

removeAll(Collection  c)

例如:c.removeAll(c2);

删除c集合中与c2的交集元素。

retainAll(Collection  c)

例如:c.retainAll(c2);

保留交集元素,删除其他元素;上述是保留c集合与c2的交集元素,其他的一并删除。

3.3查看

size()

     例如:c.size()

 查看元素的个数。

3.4判断

isEmpty() 判断集合是否为空;

contains(Object o) 判断是否存在谋元素:

其实contains方法内部是依赖于equals方法进行比较的。这里调用的是实参的equals()方法。

containsAll(Collection<?> c)

        例如:c.containsAll(c2)

       判断c集合是否有包含c2集合中的所有元素。

3.5迭代

toArray() 把集合中的元素全部存储到一个Object的数组中返回。

        例如: Object[ ] arr =c.toArray();

    Object类型声明变量接收,如果需要其他的类型,则需要进行强制类型转换。

Iterator()  返回的是接口的类型

        例如:Iterator it = c.iterator();

   Iterator()迭代器:作用,用于抓取集合中的元素。

迭代器,可以想象成抓娃娃机的抓子。而此迭代器是用于抓取集合中的元素的。

疑问:iterator()方法返回的是一个接口类型,为什么接口又可以调用方法可以使用呢?  iterator 实际 上返回的是iterator接口的实现类对象。

 

迭代器的方法:

hasNext()   问是否有元素可遍历。如果有元素可以遍历,返回true,否则返回false

next()    获取元素...

Next()    常见异常

java.util.NoSuchElementException

没有元素异常

 

迭代器在集合中的应用非常广泛,是个重点

 

 

remove()  移除迭代器最后一次返回 的元素,如果没有返回,执行该方法,则会报错。

四、集合的体系:

---------|Collection 单列集合的根接口

---------------|List   如果是实现了List接口的集合类,该接口的特点:有序,可重复。

---------------|Set   如果是实现了Set接口的集合类,该接口的特点:无序,不可重复。

五、List 接口中特有的方法:

2.1添加

add(int index, E element)

        例如:list.add(1,赵本山)把元素添加到集合中的指定索引位置上。

addAll(int index, Collection<? extends E> c)   

        例如:listaddAll2list2)把list2的元素添加到list结合指定索引值的位置上

2.2获取:

get(int index)   

例如:list.get(1) 根据索引值获取结合中的元素

indexOf(Object o)

         找出指定元素第一次出现在集合中 的索引值

lastIndexOf(Object o)

         找指定的元素最后一次出现在集合中的索引值

subList(int fromIndex, int toIndex)

       例如:List subList = list.subList(1, 3); //指定开始与结束的索引值截取集合中的元素

2.3修改:

set(int index, E element)

        例如:list.set(3, "赵本山"); //使用指定的元素替换指定索引值位置的元素。

2.4迭代

listIterator()

2.5有序

 集合的有序不是指自然顺序,而是指添加进去的顺序与元素出来的顺序是一致的。

 List接口中特有的方法具备的特点:操作的方法都存在索引值

 只有List接口下面的集合类才具备索引值。其他接口下面的集合类都没有索引值。

2.6迭代(vip

listIterator()  返回的是一个List接口中特有的迭代器,他的超级接口是Iterator

    ListIterator特有的方法:

添加:

hasPrevious()  判断是否存在上一个元素。

previous()    当前指针先向上移动一个单位,然后再取出当前指针指向的元素。

next();  先取出当前指针指向的元素,然后指针向下移动一个单位。

add(E e)   把当前有元素插入到当前指针指向的位置上。

set(E e)   替换迭代器最后一次返回的元素。

六、迭代器需要注意的事项

1.1引包

迭代器所引用的数据包是:java.util.List;

1.2声明

声明需要用List进行声明,不能够用Collection进行声明,只有使用List声明的,才有可能有list特有的方法。

1.3迭代器在变量元素的时候要注意事项:

    在迭代器迭代元素 的过程中,不允许使用集合对象改变集合中的元素 个数,如果需要添加或者删除只能使用迭代器的方法进行操作。

    如果使用过了集合对象改变集合中元素个数那么就会出现ConcurrentModificationException异常。

   迭代元素 的过程中: 迭代器创建到使用结束的时间。

七、List接口下的实现类

1.1集合的体系:

----------| Collection  单列集合的根接口

----------------| List 如果实现了List接口的集合类,具备的特点: 有序,可重复。

----------------------| ArrayList   

----------------------| LinkedList

----------------------| Vector(了解即可)

----------------| Set  如果实现了Set接口的集合类, 具备的特点: 无序,不可重复。

1.2ArrayList原理:

使用ArrayList无参的构造函数创建一个 对象时, 默认的容量是多少? 如果长度不够使用时又自增增长多少?

  ArrayList底层是维护了一个Object数组实现 的,使用无参构造函数时,Object数组默认的容量是10,当长度不够时,自动增长0.5倍。

ArrayList 底层是维护了一个Object数组实现 的, 特点: 查询速度快,增删慢。

查询快:是由于数组的特点决定的。可以根据索引进行查找。

增删慢:

增加慢的原因:假设现有数组的容量是7,添加第八个元素的时候,由于长度不够,则需要新创建一个1.5倍长度的新数组,然后,把旧数组的内容copy到新的数组中,然后在进行添加。如图所示.

 

                           图:添加大数据量的数据

         删除慢的原因:删除的原理是先要找到需要删除的元素 ,然后进行删除,删除后,ArrayList会把后面的元素copy到前面的空缺,所以数据量比较庞大。

什么时候使用ArrayList: 如果目前的数据是查询比较多,增删比较少的时候,那么就使用ArrayList存储这批数据。  比如 :高校的 图书馆

八、ArrayList 特有的方法:

1.ensureCapacity(int minCapacity) 可以初始化默认的长度。

2.trimToSize()                  ArrayList调整为列表当前大小。

九、LinkedList的实现原理

1.1 LinkedList底层

LinkedList底层是使用了链表数据结构实现的,  特点: 查询速度慢,增删快。

1.2LinkedList的特有方法

方法介绍

            addFirst(E e)

addLast(E e)

getFirst()

getLast()

removeFirst()

removeLast()

1.3LinkedList的数据结构

 

如上图所示:每个元素不但记录了元素,还记录了内存地址。

1.栈方法 :

 主要是用于实现堆栈数据结构的存储方式。

先进后出

push()

pop()

2:队列方法

(双端队列1.5): 主要是为了让你们可以使用LinkedList模拟队列数据结构的存储方式。

先进先出

offer()

poll()

十、Vector(了解即可)

1.Vector底层原理

vector底层也是维护了一个Object的数组实现的,实现与ArrayList是一样的,但是Vector是线程安全的,操作效率低。

2.ArrayListVector的区别

相同点: ArrayListVector底层都是使用了Object数组实现的。

不同点:

1. ArrayList是线程不同步的,操作效率高。

   Vector是线程同步的,操作效率低。

2. ArrayListJDK1.2出现,Vectorjdk1.0的时候出现的。

十一、集合的体系:

------------| Collection 单例集合的根接口

----------------| List  如果是实现了List接口的集合类,具备的特点: 有序,可重复。

-------------------| ArrayList  ArrayList 底层是维护了一个Object数组实现的。 特点: 查询速度快,增删慢。

-------------------| LinkedList LinkedList 底层是使用了链表数据结构实现的, 特点: 查询速度慢,增删快。

-------------------| Vector(了解即可)  底层也是维护了一个Object的数组实现的,实现与ArrayList是一样的,但是Vector是线程安全的,操作效率低。

----------------| Set  如果是实现了Set接口的集合类,具备的特点: 无序,不可重复。

-------------------| HashSet  底层是使用了哈希表来支持的,特点: 存取速度快.

无序: 添加元素 的顺序与元素出来的顺序是不一致的。

-------------------| TreeSet  

小例子:

——

十二、set接口下的实现类------------hashSet的实现原理

Haset添加元素的时候,HashSet会先调用元素的hashCode方法得到元素的哈希值 ,

然后通过元素 的哈希值经过移位等运算,就可以算出该元素在哈希表中 的存储位置。

 

情况1: 如果算出元素存储的位置目前没有任何元素存储,那么该元素可以直接存储到该位置上。

情况2: 如果算出该元素的存储位置目前已经存在有其他的元素了,那么会调用该元素的equals方法与该位置的元素再比较一次,如果equals返回的是true,那么该元素与这个位置上的元素就视为重复元素,不允许添加,如果equals方法返回的是false,那么该元素运行 添加。

2.1 哈希表的特点:桶式结构。

即哈希表的一个位置可以存放多个元素。

2.3hashCode()原理

 

HashCode默认情况下表示的是内存地址,String类已经重写了ObjecthashCode方法了。

注意:如果两个字符串的内容一致,那么返回的hashCode码肯定也会一致的。因为String重写ObjecthashCode的方法,是将内容存在数组里面了,就已经不是hashCode的内存地址了。

十三、TreeSet

1.TreeSet中添加自定义元素需要注意的事项:

1. TreeSet添加元素的时候,如果元素本身具备了自然顺序的特性,那么就按照元素自然顺序的特性进行排序存储。

  2. TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,那么该元素所属的类必须要实现Comparable接口,把元素的比较规则定义在compareTo(T o)方法上。

  

   也就是说,需要把元素与元素之间的比较规则,写在compareTo方法中。

     //负整数、零或正整数,根据此对象是小于、等于还是大于指定对象。

Public    int   compareTo (Object o) {

  Emp  e = Empo;

  Return this.salary-e.salary;       

}

      官方定义:

如何自定义定义比较器: 自定义一个类实现Comparator接口即可,把元素与元素之间的比较规则定义在compare方法内即可。

 

 自定义比较器的格式

 

 class  类名  implements Comparator{

 

 }

 

 推荐使用:使用比较器(Comparator)

实例代码:

 

  3. 如果比较元素的时候,compareTo方法返回 的是0,那么该元素就被视为重复元素,不允许添加.(注意:TreeSetHashCodeequals方法是没有任何关系。)

   4. TreeSet添加元素的时候, 如果元素本身没有具备自然顺序 的特性,而元素所属的类也没有实现Comparable接口,那么必须要在创建TreeSet的时候传入一个比较器。

    

如何自定义定义比较器: 自定义一个类实现Comparator接口即可,把元素与元素之间的比较规则定义在compare方法内即可。

    自定义比较器的格式

 

 class  类名  implements  Comparator{

 

 }

  推荐使用:使用比较器(Comparator)

   5.  TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,而元素所属的类已经实现了Comparable接口, 在创建TreeSet对象的时候也传入了比较器,那么是以比较器的比较规则优先使用。

6.TreeSet是可以对字符串进行排序的,因为字符串已经实现了Comparable接口。

字符串的比较规则:

情况一: 对应位置有不同的字符出现, 就比较的就是对应位置不同的字符。

情况 二:对应位置上 的字符都一样,比较的就是字符串的长度。

十四、treeSet的存储原理

1.treeSet存储原理

 

 

2.treeSet小练习

 

原文地址:https://www.cnblogs.com/xiangnianchulian/p/7570608.html