集合:属于容器类,存放的都是引用类型。集合的产生是由于数组的长度是定长的,一旦创建长度就会固定,但是集合的长度是不固定的,可以动态的插入删除。
数组相当于string,集合相当于StringBuilder/StringBuffer。
集合之间的继承关系
List子接口下面有三个类分别是ArrayList、LinkedList、Vector
List是collection的子接口,ArrayList是类,继承了List的接口。
Collection collection = new ArrayList(); //向上转型
Object obj = list.get(0); //向上转型
常用功能:
.add() 添加
.size() 统计集合中的对象数
.remove() 移除
.isEmpty() 判断是否为空
.contains() 判断是否包含某一个对象。
.clear() 清空集合中的所有对象内容
List list = new ArrayList(); //List中有index 而Collection没有
通过索引值操作的一些功能:
.add() 通过索引值添加
.set() 通过索引值设置
.get() 通过索引值获得对象内容
.size() 统计集合中的对象数
.indexOf() 返回对象的索引值
.remove() 通过索引值或者对象进行删除
.isEmpty() 判断是否为空
.contains() 判断是否包含某一个对象
.clear() 清空集合中的所有对象内容
有了索引值即可进行遍历,Collection里面有的方法List继承过来,List都有。
从jdk1.7之后的写法
List<String> string = new ArrayList<>(); //标准写法
总结:List 添加的对象 可以重复,并且有序
(面试)ArrayList和LinkedList的区别:
- 都实现list接口
- ArrayList是针对数组的封装,实现了数组的动态扩容。 LinkedList是针对链表的封装
- LinkedList插入和增加的操作效率比ArrayList高,但是查询的操作ArrayList较高。从使用上来讲,如果以 查询为主,选择ArrayList,如果频繁的插入,优先选 择LinkedList。
(面试)ArrayList和vector的区别:
- 都继承于同一个类Abstractlist
- ArrayList JDK1.2 非线程安全(单线程推荐使用)性能更 高。支持输出
- Vector JDK1.0 线程安全,性能相对较低。支持输出: foreach,listIterator,Enumeration.内部
问题: 其他集合中存放phone对象是否需要实现compara接口?
在linkedlist和Arraylist集合中,不需要实现compara接口,并且按添加对象的先后排序。
Set:不可重复
Set接口存放的数据是无序的(相对于添加顺序),不可以重复的。和数学中的“集合”概念相对应。
Set接口常用实现类:
1. HashSet 不可重复,无序
2.TreeSet 不可重复,有序,但是不一定按照ASCII值排序
3. LinkedHashSet
HashSet存取原理:
存入元素:
- 先比较对象的哈希码值 (调用hashCode())
- 如果没有该哈希值存在,直接存入
- 如果已经存在,则要加入的新对象跟已经存在于列表中的所有对象依次比较(调用equals()),不相等则加入,否则舍弃。
取出对象:
- 根据对象的哈希码值计算出它的存储索引,在散列表的相应位置上进行少量的比较即可找出该对象。
- 基于哈希散列,Set存、取、删都有较高的效率
HashSet操作:
HashSet不记录添加数据的顺序,且加入的元素不能重复,否则覆盖。
注意:加入HashSet集合的自定义类型的对象通常需要重写hashCode()和equals()方法。
TreeSet
TreeSet同样不记录添加数据的顺序,但是可以对存入的元素进行排序(基于红黑树实现),输出也会按照排序后的顺序。
因此,存入TreeSet的元素,必须是“可排序的”。
LinkedHashSet
LinedHashSet根据元素的哈希码进行存放,同时用链表记录元素的插入顺序。
HashSet 和TreeSet 的区别:
- TreeSet里面无法放置空对象,而HashSet可以放置空对象 null。
- TreeSet和HashSet都可以放置空内容“”,并且都放在第一 位。
Set小结
- Set的上述3个实现类,插入元素都不可以重复
- HashSet采取哈希值存储,不记录元素插入的位置,也不排序
- TreeSet采取红黑树存储,不记录元素插入的位置,但是可以排序
- LinkedHashSet采取哈希值存储,并使用链表记录元素插入的位置,不排序
Map
- Map接口用来存储“键-值”映射对。JDK API中Map接口的常用实现类:
- HashMap
- TreeMap
- Hashtable(不常用)
- Map中存储的“键-值”映射对是通过键来唯一标识,Map的“键”底层采用Set来存放。
- 因此,存入Map中的“键”如果是自定义类,应该重写hashCode()和equals()方法,确保键的唯一
- 常用String作为Map的"键"。
HashMap
HashMap内部对“键”使用Set进行散列存放。因此,根据“键”取“值”的效率较高,也是Map接口使用频率较高的一个实现类。
HashMap遍历
遍历key
map.keySet()
iterator
增强for
map.entrySet()
iterator
增强for
遍历key+value:获取key之后,通过get(key)
遍历value:除上述之外,还可以直接使用values()
Map.Entry接口
Map.Entry是Map内部定义的一个static接口,专门用来保存key-value对的内容。
- 可以通过entrySet()方法取到Entry对象,然后使用getKey(),getValue()获取键、值
- 一般情况下,map多用于存放、查找数据,遍历输出的情况较少。
TreeMap
TreeMap内部使用红黑树结构对“key”进行排序存放,所以放入TreeMap中的“key-value”对的“key”必须是“可排序”的。
HashMap、TreeMap、HashTable的使用结论
HashMap中的结论:(起源JDK1.2)
- Key相同,value会被覆盖
- Key和value都可以为null
- HashMap也是无序的
TreeMap结论:(起源JDK1.2)
- 有序的(不一定按照ASCII排序),跟TreeSet相像
- 有序的都不能放入空对象,TreeMap中Key不能为null。
- 有序,指的是key是“可排序的”一般情况下,key都是string,所以key的排序是通过ascii排序
HashTable结论:(起源JDK1.0)
- HashTable的key和value都不能为空。
在单线程中用hashmap多一点
(面试)Hashtable和HashMap的区别?
- Hashtable(注意大小写)在JDK1.0就有了,HashMap是JDK1.2引入的,操作基本和Hashtable相同,建议使用HashMap
- Hashtable是同步的(线程安全的),不能有null键,也不能有null值,否则运行时报空指针异常
- HashMap是不同步的(线程非安全的),能存储最多一个null键,任意多个null值
Map小结
- Map的上述3个实现类,插入键值对的“键”都不可以重复,否则覆盖(为什么?)
- HashMap的键采取哈希值存储,不记录元素插入的位置,也不排序
- TreeMap的键采取红黑树存储,不记录元素插入的位置,但是可以排序
- LinkedHashMap的键采取哈希值存储,并使用链表记录元素插入的位置,不排序
选择使用集合
存放要求
- 无序,无下标,不可重复,不能随机访问-Set
- 有序,有下标,可重复,可以随机访问-List
- “key-value”对,较多存放,较少遍历-Map
读和改(插入删除)的效率
- Hash*-两者都较高
- ArrayList-读(指定下标随机访问)快,插入/删除元素慢
- LinkedList-读(指定下标随机访问)慢,插入/删除元素快