Collection(集合)
Collection:
- List : Vector, ArrayList , LinkedList
- Set : HashSet, TreeSet
List 元素是有序的、可重复
有序的 collection,可以对列表中每个元素的插入位置进行精确地控制。
可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
可存放重复元素,元素存取是有序的。
Vector : 底层数据结构是数组结构,线程安全,但速度慢,已被ArrayList替代。
ArrayList :线程不安全,查询速度快,底层数据结构是数组结构。
LinkedList :线程不安全。增删速度快,底层数据结构是列表结构。
Set(集合) 元素无序的、不可重复。
取出元素的方法只有迭代器。不可以存放重复元素,元素存取是无序的。
HashSet:线程不安全,存取速度快。依赖的是元素的hashCode方法和euqals方法,保证元素唯一性。
TreeSet:线程不安全,可以对Set集合中的元素进行排序。通过compareTo或者compare方法中的来保证元素的唯一性。元素是以二叉树的形式存放的。
HashMap,HashSet,ArrayList都不具备线程安全。
可以用 Set s=Collections.synchronizedSet(new Hashset<…>());
Map m=Collections.synchronizedMap(new HashMap<…>());
List l=Collections.synchronizedList(new ArrayList<…>());
获得被同步后的版本。
Iterator:迭代器
它是Java集合的顶层接口(不包括 map 系列的集合,Map接口 是 map 系列集合的顶层接口),主要包含三个重要方法:
-
Object next():返回迭代器刚越过的元素的引用,返回值是 Object,需要强制转换成自己需要的类型
-
boolean hasNext():判断容器内是否还有可供访问的元素
-
void remove():删除迭代器刚越过的元素
所以除了 map 系列的集合,我们都能通过迭代器来对集合中的元素进行遍历。
这里我们引用一个Iterator 的实现类 ArrayList 来看一下迭代器的使用:
//产生一个 List 集合,典型实现为 ArrayList。
List list = new ArrayList();
//添加三个元素
list.add("Tom");
list.add("Bob");
list.add("Marry");
//构造 List 的迭代器
Iterator it = list.iterator();
//通过迭代器遍历元素
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}
Map:
- HashMap
- Hashtable
- TreeMap
Map 是一个双列集合,以键值的形式存放数据。
Hashtable:线程安全,速度快。底层是哈希表数据结构。是同步的。不允许null作为键,null作为值。
HashMap:线程不安全,速度更快。底层也是哈希表数据结构。是不同步的。允许null作为键,null作为值。替代了Hashtable.
在JDK1.6,JDK1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。
但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。
而JDK1.8中,HashMap采用位桶+链表+红黑树实现,
当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
l |–LinkedHashMap: 可以保证HashMap集合有序。存入的顺序和取出的顺序一致。
TreeMap:可以用来对Map集合中的键进行排序.
Hashtable与HashMap简单总结如下:
- 1.Hashtable是Dictionary的子类,HashMap是Map接口的一个实现类;
- 2.Hashtable中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。
即是说,在多线程应用程序中,不用专门的操作就安全地可以使用Hashtable了;
而对于HashMap,则需要额外的同步机制。
但HashMap的同步问题可通过Collections的一个静态方法得到解决:
Map Collections.synchronizedMap(Map m);
这个方法返回一个同步的Map,这个Map封装了底层的HashMap的所有方法,使得底层的HashMap即使是在多线程的环境中也是安全的。
- 3.在HashMap中,null可以作为键,也可以作为value,(key不可重复,value可重复)这样的键只有一个;因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()方法来判断。
集合面试题
一.Collection 和 Collections的区别
-
Collection是集合类的上级接口,子接口主要有Set 和List。
-
Collections是针对集合类的一个帮助类,提供了操作集合的工具方法:一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
二.集合与数组的区别
- 集合与数组都是容器,数组大小固定,只能存储相同数据类型的数据,集合大小可动态扩展,可以存储各种类型的数据;
- 集合只能存放对象,如果放一个int类型的数,集合会自动转成它的包装类再进行存储,数组可以存放基本数据类型。
转换:
数组转换为集合: Arrays.asList(数组)
集合转换为数组: 集合.toArray();
三.ArrayList和Vector的区别
(1)同步性:
Vector是线程安全的,也就是说是它的方法之间是线程同步的,而ArrayList是线程序不安全的,它的方法之间是线程不同步的。
如果只有一个线程会访问到集合,那最好是使用ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用Vector,因为不需要我们自己再去考虑和编写线程安全的代码。
(2)数据增长:
ArrayList与Vector都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加ArrayList与Vector的存储空间。
Vector默认增长为原来两倍,而ArrayList的增长为原来的1.5倍。ArrayList与Vector都可以设置初始的空间大小,Vector还可以设置增长的空间大小。
四.HashMap和Hashtable的区别
主要从三方面来说:
一.历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现
二.同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的
三.值:只有HashMap可以让你将空值作为一个表的条目的key或value
五.List、Map、Set三个接口,存取元素时,各有什么特点????
-
首先,List与Set具有相似性,它们都是单列元素的集合,所以,它们有一个共同的父接口,叫Collection。Set里面不允许有重复的元素,所谓重复,即不能有两个相等(注意,不是仅仅是相同)的对象 ,即假设Set集合中有了一个A对象,现在我要向Set集合再存入一个B对象,但B对象与A对象equals相等,则B对象存储不进去,所以,Set集合的add方法有一个boolean的返回值,当集合中没有某个元素,此时add方法可成功加入该元素时,则返回true,当集合含有与某个元素equals相等的元素时,此时add方法无法加入该元素,返回结果为false。Set取元素时,没法说取第几个,只能以Iterator接口取得所有的元素,再逐一遍历各个元素。
-
List表示有先后顺序的集合, 注意,不是那种按年龄、按大小、按价格之类的排序。当我们多次调用add(Obj e)方法时,每次加入的对象就像火车站买票有排队顺序一样,按先来后到的顺序排序。有时候,也可以插队,即调用add(int index,Obj e)方法,就可以指定当前对象在集合中的存放位置。一个对象可以被反复存储进List中,每调用一次add方法,这个对象就被插入进集合中一次,其实,并不是把这个对象本身存储进了集合中,而是在集合中用一个索引变量指向这个对象,当这个对象被add多次时,即相当于集合中有多个索引指向了这个对象。List除了可以以Iterator接口取得所有的元素,再逐一遍历各个元素之外,还可以调用get(index i)来明确说明取第几个。
-
Map与List和Set不同,它是双列的集合,其中有put方法,定义如下:put(obj key,obj value),每次存储时,要存储一对key/value,不能存储重复的key,这个重复的规则也是按equals比较相等。取则可以根据key获得相应的value,即get(Object key)返回值为key 所对应的value。另外,也可以获得所有的key的结合,还可以获得所有的value的结合,还可以获得key和value组合成的Map.Entry对象的集合。
六.说出ArrayList,Vector, LinkedList的存储性能和特性。
-
1.ArrayList和Vector都是使用数组方式存储数据,都允许直接按序号索引元素,但是索引数据快而插入数据慢。Vector缺省情况下自动增长原来一倍的数组长度,ArrayList是原来的50%。
-
2.Vector由于使用了synchronized方法(线程安全),ArrayList非线程安全,Vector通常性能上较ArrayList差。
-
3.LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快查询较慢。LinkedList也是线程不安全的。
总结:如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。 如果要考虑到线程安全问题,可以使用Vector。
七.Collection框架中实现比较要实现什么接口
comparable/comparator
八.Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
= =equals()和= =的区别= =
- = =主要用在基本数据类型及引用,来比较两个变量的值是否相等,如果一个变量只想的数据是对象类型,那么= = 比较两个变量指向的内存地址是否相同。
- equals 方法是用于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是否相同,它比较的两个对象是独立的。
- ==方法决定引用值是否指向同一对象 ,equals方法在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。
Set 里的元素是不能重复的,元素重复与否先调用hashCode方法,如果不相同,证明不相等。如果相同,再调用equals方法,如果equals方法相同,证明相等,不相同,证明不相等。
集合中是否包含某一个元素用contains来判断。
九.你所知道的集合类都有哪些主要方法?
我记的不是方法名,而是思想,我知道它们都有增删改查的方法,但这些方法的具体名称,我记得不是很清楚,对于set,大概的方法是add,remove, contains;
对于map,大概的方法就是put,remove,contains等,因为,我只要在eclispe下按点操作符,很自然的这些方法就出来了。我记住的一些思想就是List类会有get(int index)这样的方法,因为它可以按顺序取元素,而set类中没有get(int index)这样的方法。
List和set都可以迭代出所有元素,迭代时先要得到一个iterator对象,所以,set和list类都有一个iterator方法,用于返回那个iterator对象。
map可以返回三个集合,一个是返回所有的key的集合,另外一个返回的是所有value的集合,再一个返回的key和value组合成的EntrySet对象的集合,map也有get方法,参数是key,返回值是key对应的value。
十.两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
对。
如果对象要保存在HashSet或HashMap中,它们的equals相等,那么,它们的hashcode值就必须相等。
如果不是要保存在HashSet或HashMap,则与hashcode没有什么关系了,这时候hashcode不等是可以的,例如arrayList存储的对象就不用实现hashcode,当然,我们没有理由不实现,通常都会去实现的。