(1)为什么出现集合类?
面向对象对事物的体现都是以对象的形式,为了方便对多个对象的操作,就对对象进行存储。
集合就是存储对象最常用的一种方式.
(2)数组和集合都是容器,两者有何不同?
a.数组长度固定,而集合长度是可变的
b.数组值可以存储对象,还可以存储基本数据类型;而集合只能存储对象
c.数组存储数据类型是固定的,而集合存储的数据类型不固定
(3)集合类的特点:
集合只能存储对象
集合的长度可变
集合可以存储不同类型的对象
(4)各种集合的
ArrayList:
(1)当往ArrayList里面存入元素没什么要求时,即只要求有序就行时;
(2)当往ArrayList里面存入元素要求不重复时,比如存入学生对象,当同名同姓时
视为同一个人,则不往里面存储。则定义学生对象时,需复写equals方法
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
return false;
Student stu = (Student)obj;
return this.name.equals(stu.name)&&this.age==stu.age;
}
则往ArrayList集合通过add存入学生对象时,集合底层自己会调用学生类的equals方法,
判断重复学生则不存入。
(3)特有的列表迭代器:ListIterator
可以用于解决并发错误,
注:对于List集合,无论是add、contains、还是remove方法,判断元素是否相同,
都是通过复写equals方法来判断!
Vector
底层数据结构和ArrayList一样,但是是线程同步,数据安全的,效率比较低。
LinkedList
(1)LinkLedist的特有方法:
boolean offerFirst(E e) 在此列表的开头插入指定的元素。
boolean offerLast(E e) 在此列表末尾插入指定的元素。
E peekFirst() 获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。
E peekLast() 获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null。
E pollFirst() 获取并移除此列表的第一个元素;如果此列表为空,则返回 null。
E pollLast() 获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。
(2)通过LinkedList的特有方法,可以实现某些数据特殊方式的存取,比如堆栈和队列。
一般情况下,使用哪种List接口下的实现类呢?
如果要求增删快,考虑使用LinkedList
如果要求查询快,考虑使用ArrayList
如果要求线程安全,考虑使用Vector。
Set:集合,元素是无序的(因为没有索引),元素不可以重复。但可以有null元素。
HashSet:底层数据结构是哈希表、存取速度快、元素唯一、线程不同步。
TreeSet:底层数据结构是二叉树,元素唯一,线程不同步,元素排序。排序方法有自然排序和自定义排序。
TreeSet可以对set集合中的元素进行排序(按字母ASCII), 底层数据结构是二叉树,保证数据唯一性的是compareTo方法return 0;TreeSet排序第一种方式:元素自身具备比较性(元素类型必须实现Comparable接口并且覆盖其compareTo方法)。
HashMap:
1. 底层数据结构是数组+链表+红黑树(JDK1.8才有的红黑树,链表上的值多于8个就用红黑树结构),线程不同步,可以理解成:一个数组,它的每一项都是一条链,如果这条链长度大于8,就用红黑树代替链。
2. Key可以为null,即键值对的可以为(null,null);
3. put方法参数有相同的键key会导致新的(K1,newV1)覆盖旧的键值对。put方法返回值是原来的OldValue,也就是如果put方法返回值是null,说明是第一次put这个键以及对于的值。但有时候根据hash算法计算出的存储位置有可能相同,而这个位置原来就有其他元素占用,这就是哈希冲突,HashMap解决它的办法就是用链地址法:
首先判断key是否为null,若为null,则直接调用putForNullKey方法。若不为空则先计算key的hash值,然后根据hash值搜索在table数组中的索引位置,如果table数组在该位置处没有元素,则直接添加上去。如果table数组在该位置处有元素,则通过比较是否存在相同的key,若存在则覆盖原来key的value,否则将该元素保存在链头(最先保存的元素放在链尾)。
4.put到容量的0.75时候会扩容2倍,扩容的时候需冲重新add entry对象,需要重新计算hash,然后放进Map,所有比较耗资源,如果需要用到的容量很多,可能会导致多次扩容,一般如果知道容量大概有多少先指定容量。
5.HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
TreeMap:
1.实现了NavigableMap接口,意味着它支持一系列的导航方法。比如返回有序的key集合。实现了Cloneable接口,意味着它能被克隆,实现了java.io.Serializable接口,意味着它支持序列化。
2. 底层数据结构是红黑树,红黑树是一种自平衡排序二叉树,树中每个节点的值,都大于或等于在它的左子树中的所有节点的值,并且小于或等于在它的右子树中的所有节点的值。线程不同步,每个节点包含的内容有:左右节点引用,父亲节点引用,key,value,color;
一、Map集合和Collection集合的区别?
1
Map中一次存储是键值对。
Collection中一次存储是单个元素。
2
Map的存储使用的put方法。
Collection存储使用的是add方法。
3
Map集合没有迭代器,Map的取出,是将Map转成Set,在使用迭代器取出。
Collection取出,使用就是迭代器。
4
如果对象很多,必须使用集合存储。
如果元素存在着映射关系,可以优先考虑使用Map存储或者用数组,
如果没有映射关系,可以使用Collection存储。
二、集合类各种容器的使用注意细节:
(1)迭代器:
**迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。
也就是在迭代循环中调用一次next方法一次就要hasNext判断一次,比如语句
sop(it.next()+"..."+it.next())会发生上述异常。
**迭代器的next方法返回值类型是Object,所以要记得类型转换,应用泛型后就不用强转
(2)List集合:
**List集合里面的元素因为是带角标,所以List集合里面的元素都是有序的,
另外List集合可以包含重复元素,也可以包含null。
**List集合有迭代器Iterator,还有一个特有迭代器列表ListIterator
**List集合中判断元素是否相同都是用equals方法,无论contains、remove都依赖equals方法
比如往ArrayList集合里面存放学生,同名同年龄视为同一个人,此时就需要在学生类复写Object类
里面的equals方法(非常重要!!!要注意!!)
(3)Set集合:
**Set接口里面存放的是元素是无序的,不可以有重复元素,可以包含null
**Set集合只有一种取出方式,就是迭代器Iterator
**Set集合功能和Collection是一致的,没有特殊方法
HashSet:
**集合里面存放的元素是无序的,唯一的
**底层数据结构是哈希表,哈希表结构的数据都是无序的,哈希表结构的操作效率都高效
**线程不同步
**保证元素唯一性的原理是:通过复写hashCode和equals方法
****如果两元素的hashCode值相同,则继续判断两元素equals是否为真
****如果两元素的hashCode值不同,则不会调用equals方法。
**当我们往HashSet集合存放自定义的元素时(比如学生对象),通常都要复写hashCode和equals方法,
而且hashCode和equals方法不通过我们调用,HashSet集合底层内部自己调用,自己拿元素去比较
TreeSet
**TreeSet集合可以对存放的元素进行排序,弥补了Set集合元素无序的缺点,且元素是唯一的
**底层数据结构是二叉树,二叉树结构都是有序的
**线程不同步
**TreeSet集合要求往集合里存放的元素自身具备比较性,否则会报错
**TreeSet集合保证元素唯一性的依据是:通过compareTo或者compare方法中的来保证元素的唯一性。
TreeSet排序的第一种方式:让元素自身具备比较性,
定义元素类实现Compareble接口,覆盖compare方法,
此方式是元素的自然顺序。
TreeSet排序的第二种方式:让集合具备比较性
当元素自身不具备比较性或者具备的比较性不是
我们所需要的比较性时,此时就需要让集合具备自定义的比较性。
那如何让集合自身具备比较性呢?
可在集合初始化时,就让集合具备比较方式。
即定义一个类,实现Comparator接口,覆盖compare方法。
注:
**判断元素唯一时,当主要条件一样时,判断次要条件
**两种排序方式都在时,以比较器为主!!!
三、Map的两种取出方式:
第一种:Set<K> keySet()
返回此映射中包含的键的Set视图,将Map集合中所有的键存入Set集合,然后再通过Set集合的
迭代器取出所有的键,再根据get方法获取每个键的值;
第二种:Set<Map.Entry<K,V>> entrySet()
返回此映射中包含的映射关系的Set视图,将Map集合中的映射关系存入到Set集合中,
这个映射关系的数据类型是Map.entry,再通过Map.Entry类的方法再要取出关系里面的键和值
Map.Entry的方法摘要:
boolean equals(Object o) 比较指定对象与此项的相等性。
K getKey() 返回与此项对应的键。
V getValue() 返回与此项对应的值。
int hashCode() 返回此映射项的哈希码值。
V setValue(V value) 用指定的值替换与此项对应的值(特有!!!)。
四、Collections类:
(1)此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。
(2)静态方法摘要:
static <T> boolean addAll(Collection<? super T> c, T... elements)
将所有指定元素添加到指定 collection 中。
static <T> void fill(List<? super T> list, T obj)
使用指定元素替换指定列表中的所有元素。
static <T> boolean replaceAll(List<T> list, T oldVal, T newVal)
使用另一个值替换列表中出现的所有某一指定值。
static void reverse(List<?> list)
反转指定列表中元素的顺序。
static <T> Comparator<T> reverseOrder()
返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序
static <T> Comparator<T> reverseOrder(Comparator<T> cmp)
返回一个比较器,它强行逆转指定比较器的顺序。
(3)Collections类的方法:
集合有一个共同的缺点,那就是线程不安全,被多线程操作时,容易出现问题,虽然可以自己加锁
但是麻烦。Collections提供特牛的方法,就是给它一个不同步的集合,它返回一个同步的安全的集合
static <T> Collection<T> synchronizedCollection(Collection<T> c)
返回指定 collection 支持的同步(线程安全的)collection。
static <T> List<T> synchronizedList(List<T> list)
返回指定列表支持的同步(线程安全的)列表。
static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
返回由指定映射支持的同步(线程安全的)映射。
static <T> Set<T> synchronizedSet(Set<T> s)
返回指定 set 支持的同步(线程安全的)set。
static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
返回指定有序映射支持的同步(线程安全的)有序映射。
static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s)
返回指定有序 set 支持的同步(线程安全的)有序 set。
五、Arrays类:
此类包含用来操作数组(比如排序和搜索)的各种方法。里面都是静态方法。
如果指定数组引用为 null,则此类中的方法都会抛出 NullPointerException。
(1)数组变集合:
static <T> List<T> asList(T... a)
返回一个受指定数组支持的固定大小的列表。
注意:
A:该方法将一个数组变成集合后,不可以使用集合的增删方法,因为数组的长度是固定的!
如果增删,则发生UnsupportedOprationException(不支持操作异常)
B:如果数组中的元素都是基本数据类型,则该数组变成集合时,会将该数组作为集合的一个
元素出入集合
C:如果数组中的元素都是对象,如String,那么数组变成集合后,数组中的元素就直接转成
集合中的元素
(2)集合变数组:
方法:Collction中的toArray方法
好处:可以限定对集合元素的操作,防止对集合的元素进行增删,因为数组长度是固定的。
六、Collections类和Arrays类的使用?
A:Collections
排序 sort(List<T>list)
二分查找 binarySearch(List<T>list,t.key)
随机置换 shuffle(List<T>list)
反转 reverse(List<T>list)
B:Arrays
把数组变成字符串输出 toString (Array a)
排序 sort(Array a)
二分查找 binarySearch(Array a,String str)
七、HashMap和Hashtable的不同点?
1.HashMap继承于AbstractMap,而Hashtable继承于Dictionary
2.Hashtable的几乎所有函数都是同步的,即它是线程安全的,支持多线程。而HashMap的函数则是非同步的,它不是线程安全的。
3.HashMap只支持Iterator(迭代器)遍历。而Hashtable支持Iterator(迭代器)和Enumeration(枚举器)两种方式遍历。
4.容量的初始值 和 增加方式都不一样
HashMap默认的容量大小是16;容量使用0.75(加载因子)后,将容量变为“原始容量x2”。
Hashtable默认的容量大小是11;容量使用超过阈值后,将容量变为“原始容量x2”。
八、HashMap和TreeMap比较?
1)HashMap适用于Map中插入,删除和定位元素。
2)TreeMap时候用于需要排列的时候,遍历键。
3)线程都不是安全的,要安全就用Hashtable
4)HashMap遍历结果不排序,TreeMap排序。
5)HashMap基于哈希表实现(底层为数组+链表+红黑树),TreeMap基于红黑树实现
6)HashMap效率高一些
九、ArrayList和LinkedList区别?Vector?
1.ArrayList底层数据结构是数组,LinkedList。。是链表
2.当访问ArrayList的时候可以随机通过索引直接访问,而LinkedList要指针按顺序从前往后依次查找,故访问效率LinkedList不如ArrayList
3.基于2,进行增删操作时候,ArrayList的下标会有有所变化,需要进行大量的数据移动,所以增删效率不如LinkedList。
4.ArrayList直接开辟一块连续的内存空间,然后通过索引存储数据,而LinkedList通过形成一个数据结点来存储数据元素。
Vector底层数据结构跟ArrayList一样,但是Vector的线程同步,数据安全,效率不如ArrayList。
十、HashSet和treeSet的异同?
相同点:
都是单列集合;元素不重复。
不同点:
1.底层数据结构不一样,HashSet是哈希表,treeSet是二叉树
2.保证唯一性的方法不一样,HashSet需要先比较hashcode是不是一样,再通过equals方法判断相不相等。而treeSet只需要通过compareTo方法返回值是否为0 判断。
3.有序性不一样,HashSet的元素无序,而treeSet有排列顺序,treeSet通过自然排序或者比较器排序可以实现排序。
十一、数组和集合的区别?
1.长度区别:数组长度固定,集合长度可变
2.数据类型:数组的存放的数据类型可以是引用类型或者基本类型,而集合只能是放引用类型
3.元素内容区别:数组最多存一种类型的元素,而集合可以存放多种,但一般都放同一种