JAVA——集合

集合 

集合是一种存储对象的容器,也是最为常用的一种存储对象的方式。在集合中可以存储任何类型的对象,且其长度可变。有时因为在程序中可能无法预先知道需要多少个对象,若用数组来存储对象,数组的长度不好定义,而集合的出现就解决了这样的问题。查看api 文档Collection在在java.util 中(注意是大写Collection)。

集合和数组的区别

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

集合:存储不同类型对象的容器。

数组和集合类都是容器。数组的长度是固定的,而集合的长度是可变的。数组可以存储基本数据类型,集合中可以存储任意类型的对象。

集合的特点:用来存储对象,且其长度是可以变得,而且可以存储不同类型的对象。

数组的特点:

  1. 只能存储同一种数据类型的数据。
  2. 一旦初始化,其长度就固定了。
  3. 数组中元素和元素之间的地址是连续的。

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

集合比数组的优势:

  1. 集合可以存储任意类型的对象的数据,而数组只能存储同一种数据类型的数据。
  2. 集合的长度是可以发生变化的,但是数组的长度是固定的。

集合的分类

---|Collection: 单列集合

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

                  ---|ArrayList: 数组实现, 查找快, 增删慢。由于底层是维护了一个Object数组实现, 在增和删的时候会牵扯到数组,因此增容以及拷贝元素比较慢。但是数组是可以直接按索引查找, 所以查找时较快。什么时候使用ArrayList: 如果目前的数据是查询比较多,增删比较少的时候,那么就使用ArrayList存储这批数据。比如:高校的图书馆。ArrayList底层维护了一个Object[] 用于存储对象,默认数组的长度是10。可以通过 new ArrayList(20)显式的指定用于存储对象的数组的长度。当默认的或者指定的容量不够存储对象的时候,容量自动增长为原来的容量的1.5倍。

                 ---|LinkedList:   链表实现, 增删快, 查找慢。由于链表实现, 增加时只要让前一个元素记住自己就可以, 删除时让前一个元素记住后一个元素, 后一个元素住前一个元素. 这样的增删效率较高但查询时需要一个一个的遍历, 所以效率较低。

                 ---|Vector: 和ArrayList原理相同, 但线程安全, 效率略低和ArrayList实现方式相同, 但考虑了线程安全问题, 所以效率略低。

          ---|Set: 无序, 不可重复

                ---|HashSet:线程不安全,存取速度快。底层是以哈希表实现的。特点:存取速度快。哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同) 是按照哈希值来存的,所以取数据也是按照哈希值来取得。

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

                ---|LinkedHashSet:会保存插入的顺序。

          ---| Map: 键值对。Map中的元素是两个对象,一个对象作为键,一个对象作为值。键不可以重复,但是值可以重复。

                ---|HashMap:采用哈希表实现,所以无序。底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。要保证键的唯一性,需要覆盖hashCode方法,和equals方法。

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

                ---|HashTable:底层是哈希表数据结构,线程是同步的,不可以存入null键,null值。效率较低,被HashMap 替代。

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

注意:

  1. 出现这么多集合容器的原因是:每一个容器对数据存储方式不同。而这样的存储方式就叫做:数据结构。
  2. 集合和数组中存放的都是对象的引用。
  3. 集合是有序的,集合的有序不是指自然顺序,而是指添加进去的顺序和元素出来的顺序是一致的。

使用集合的各种情况

Collection

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

 

List

 

 

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

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

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

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

 

 

Set

 

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

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

如果我们不需要排序, 使用HashSet, HashSet比TreeSet效率高.

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

 

集合类

学习集合对象

学习集合时,先学习Collection中的共性方法。因为其共性方法是在多个容器中都可以使用的。若要使用子类集合中的特有方法,可以查看子类的具体内容。

创建集合对象

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

Collection coll=new Arraylist();

Collection类的共性方法

增加:

       1: add(E e)  将指定对象存储到容器中,添加成功返回true,添加 失败返回false.

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

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

删除:

       3: clear()

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

       5: removeAll(Collection c) 将指定集合中的元素删除

       6: retainAll(Collection c)

查看

       7: size()

判断

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

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

       10:containsAll(Collection<?> c) 判断集合中是否包含指定集合

       10:equals()判断两个对象是否相等 

迭代: 

       11:int size()    返回集合容器的大小

       12: toArray()   集合转换数组

List集合特有方法

List操作的方法都有索引值。

增加

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

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

删除

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

修改

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

获取

       E get(int index)             注意: IndexOutOfBoundsException

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

       lastIndexOf(Object o)

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

迭代

       listIterator()  

ArrayList 类特有的方法:

   ensureCapacity(int minCapacity)

   trimToSize()

LinkedList类特有方法:

  addFirst(E e)

  addLast(E e)

  getFirst()

  getLast()

  removeFirst()

  removeLast()

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

数据结构

      栈 

               先进后出

               push()

               pop()

      队列

               先进先出

               offer()

               poll()

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

ArrayList 和 LinkedList的优缺点

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

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

      问题:有一批数据要存储,要求存储这批数据不能出现重复数据,ArrayList、LinkedList都没法满足需求。

      解决办法:使用 set集合。

Vector

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

笔试题: 说出ArrayLsit与Vector的区别?

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

   不同点:

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

       2. ArrayList是JDK1.2出现,Vector是jdk1.0的时候出现的。

ArrayList: 单线程效率高

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

特有的方法

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

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

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

 Enumeration 接口:

 boolean hasMoreElements()  测试此枚举是否包含更多的元素。

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

Set

Set:注重独一无二的性质,该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素。用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。

对象的相等性

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

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

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

HashSet

HashSet:底层是使用哈希表来支持的。特点:存取速度快。哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同) 是按照哈希值来存的,所以取数据也是按照哈希值来取得。

由于Set集合是不能存入重复元素的集合。那么HashSet也是具备这一特性的。HashSet如何检查重复?HashSet会通过元素的hashcode()和equals方法进行判断元素师否重复。如果对象的hashCode值是不同的,那么HashSet会认为对象是不可能相等的。

因此我们自定义类的时候需要重写hashCode,来确保对象具有相同的hashCode值。

如果元素(对象)的hashCode值相同,会继续使用equals 进行比较.如果 equals为true 那么HashSet认为新加入的对象重复了,就会加入失败。如果equals 为false那么HashSet 认为新加入的对象没有重复.新元素可以存入.

总结:往Haset添加元素的时候,HashSet会先调用元素的hashCode方法得到元素的哈希值,然后通过元素的哈希值经过移位等运算,就可以算出该元素在哈希表中的存储位置。如果算出元素存储的位置目前没有任何元素存储,那么该元素可以直接存储到该位置上。如果算出该元素的存储位置目前已经存在有其他的元素了,那么会调用该元素的equals方法与该位置的元素再比较一次,如果equals返回的是true,那么该元素与这个位置上的元素就视为重复元素,不允许添加,如果equals方法返回的是false,那么就允许添加该元素。

   那么该元素运行添加。哈希值相同equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。

HashSet:通过hashCode值来确定元素在内存中的位置。一个hashCode位置上可以存放多个元素。

当hashcode() 值相同equals() 返回为true 时,hashset 集合认为这两个元素是相同的元素.只存储一个(重复元素无法放入)。调用原理:先判断hashcode 方法的值,如果相同才会去判断equals 如果不相同,是不会调用equals方法的。

问题:HashSet到底是如何判断两个元素重复的呢?

答:通过hashCode方法和equals方法来保证元素的唯一性,add()返回的是boolean类型判断两个元素是否相同,先要判断元素的hashCode值是否一致,只有在该值一致的情况下,才会判断equals方法,如果存储在HashSet中的两个对象hashCode方法的值相同equals方法返回的结果是true,那么HashSet认为这两个元素是相同元素,只存储一个(重复元素无法存入)。

注意:HashSet集合在判断元素是否相同先判断hashCode方法,如果相同才会判断equals。如果不相同,是不会调用equals方法的。

HashSet 和ArrayList集合都有判断元素是否相同的方法,HashSet使用hashCode和equals方法,ArrayList使用了equals方法。

​​​​​​​treeSet要注意的事项

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

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

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

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

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

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

       自定义比较器的格式 :

         class  类名  implements Comparator{

         }

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

原因:如果使用comparable接口,那么只能在定义的这个类内部使用这个比较器; 但是如果使用comparable借口,可以在其他类中使用这个比较器。

​​​​​​​红-黑树算法

红黑树是一种特定类型的二叉树。

红黑树算法的规则: 左小右大。

再次强调:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;

注意:在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较次要条件。

问题:为什么使用TreeSet存入字符串,字符串默认输出是按升序排列的?

答:因为字符串实现了一个接口,叫做Comparable 接口.字符串重写了该接口的compareTo 方法,所以String对象具备了比较性.那么同样道理,自定义元素(例如Person类,Book类)想要存入TreeSet集合,就需要实现该接口,也就是要让自定义对象具备比较性.

存入TreeSet集合中的元素要具备比较性。

比较性要实现Comparable接口,重写该接口的compareTo方法。

TreeSet属于Set集合,该集合的元素是不能重复的,TreeSet如何保证元素的唯一性。

通过compareTo或者compare方法中的来保证元素的唯一性。

添加的元素必须要实现Comparable接口。当compareTo()函数返回值为0时,说明两个对象相等,此时该对象不会添加进来。

Map

Map一次存一对元素, Collection 一次存一个。Map 的键不能重复,保证唯一。

Map 一次存入一对元素,是以键值对的形式存在.键与值存在映射关系.一定要保证键的唯一性.。

interface Map<K,V>:K - 此映射所维护的键的类型;V - 映射值的类型

常见方法

添加:

    1、V put(K key, V value)    (可以相同的key值,但是添加的value值会覆盖前面的,返回值是前一个,如果没有就返回null)                                         

    2、putAll(Map<? extends K,? extends V> m)  从指定映射中将所有映射关系复制到此映射中(可选操作)。

删除:

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

   2、clear()     清空集合对象

获取:

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

判断:

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

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

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

   4、Int size()   长度

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

常用方法

binarySearch(int[])    二分查找,数组需要有序

binarySearch(double[])    二分查找,数组需要有序

sort(int[])  数组排序

sort(char[])   数组排序

toString(int[]):将数组变成字符串。
copyOf():  复制数组。

copyOfRange():复制部分数组。

equals(int[],int[]):比较两个数组是否相同。

List asList(T[]):将数组变成集合。这样可以通过集合的操作来操作数组中元素,但是不可以使用增删方法,add,remove。因为数组长度是固定的,会出现UnsupportOperationExcetion。

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

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值