集合的概念
集合是一个容器,可以容纳其他类型的数据,前面所讲的数组就是一个集合。
所有的集合相关的类和接口都在java.util
包下
特点
- 集合不能直接存储基本数据类型(但是代码上不需要体现,因为Java中有自动装箱)
- 另外集合不能直接存储Java对象,而是存储其
内存地址
也叫做引用
- 不同集合,底层对应不同的数据结构
- 数据结构就是数据存储的结构,常见的结构有:
数组、二叉树、连败哦、哈希表
等。
分类
Java中的集合分为两类
一类是以当个方式存储元素:java.util.Collection
另一类是以键值对
的方式存储元素:java.util.Map
图中已经展现出各个集合的特点。
总结常用集合
集合 | 存储结构 |
---|---|
ArrayList | 数组 |
LinkedList | 双向链表 |
HashSet | 底层是HashMap,其存储的元素等于HashMap的key |
TreeSet | 底层是TreeMap,其存储的元素等于TreeMap的key |
HashMap | 哈希表 |
Properties | 线程安全,key和value只能存储String类型,常用做配置类 |
TreeMap | 二叉树,key可以自动按大小排序 |
Collection
Collection集合没有泛型
时,可以存储Object的所有子类
但是存在泛型
之后,只能存储泛型的类型
注意:不能存放基本数据类型和对象本身,只能存储封装类或对象的内存地址。
常用的方法
常用方法 | 说明 |
---|---|
boolean add(E e) | 向集合中添加一个元素,添加成功返回true |
boolean remove(Object o) | 删除某个元素,底层会调用equals方法进行对比,成功返回true |
int size() | 返回集合中元素的个数 |
boolean contains(Object o) | 判断集合中是否包含改元素,底层调用equeals(),包含返回ture |
boolean isEmpty() | 判断集合是否为空,为空返回true |
void clear() | 清空改集合 |
Object[] toArray() | 将集合转换为数组 |
演示:
public class Test{
public static void main(String[] args){
//多态,夫类型引用指向子类型对象
Collection c = new ArrayList();
//向集合中添加一个元素1
/*注意Java在中存在自动装箱机制,实际上是:
Integer i = new Integer(1);
*/
c.add(1);
//获取当前集合的元素个数,当前为1
int size = c.size();
//判断当前集合中是否包含1,结果是ture
boolean isContains = c.contains(1);
//清空集合
c.clear();
//判断集合是否为空,结果为ture
boolean isEmpty = c.isEmpty();
}
}
Iterator 迭代器
只有Collection集合才能被迭代器迭代,Map集合不可以使用
常用方法 | 说明 |
---|---|
boolean hasNext() | 判断当前指向的元素后是否还存在元素 |
E next() | 返回当前指向的元素,并且指向下一个元素 |
remove() | 删除迭代器当前指向的元素 |
使用方法:
main(){
//首先需要准备一个Conllection的集合
Collection collections = new ArrayList();
collections.add("元素1");
...
collections.add("元素n");
//获取迭代器对象,改方法继承自Iterator接口
Iterator<String> it = collections.iterator();
//判断当前元素后是否还有元素
while (iterator.hasNext()) {
//使用一个变量接收该元素后,并指向下一个元素
String element = iterator.next();
//打印前面接收的元素
System.out.println(element);
}
}
注意:在迭代的过程中,要删除集合中元素时,请使用迭代器的remove
方法。
直接使用Collection中的方法,需要重新获取一个新的迭代器。
List子类
List作为Collection的子类,存在一些特有的方法
这些方法根据该集合的特点而来
方法 | 说明 |
---|---|
void add(int index, E element) | 向指定下标处添加元素 |
E get(int index) | 获取指定下标的元素 |
E set(int index, E elemtnt) | 修改指定下标的元素 |
int indexOf(Object o) | 返回列表中第一次出现指定元素的索引,如果没有返回-1 |
int lastIndexOf(Object o) | 返回列表中最后出现的指定元素的索引,如果没有返回-1 |
E remove(int index) | 删除指定索引的元素 |
ArrayList
特点:
- ArrayList不是线程安全的
- 默认的初始化容量是10
- 底层先创建一个长度为0的数组,添加第一个元素时长度变为10
- 集合的底层时一个Object数组
构造方法:
new ArrayList();//默认初始化方式
new ArrayList(20);//指定初始大小
new ArrayList(一个集合);
//比如将HashSet转化为ArrayList
数组的扩容:
- 增长到原容量的1.5倍
面试题:ArrayList的优缺点
- ArrayList使用最多,与数组的特点相同
- 数组检索效率高//以后经常检索
(由于每个元素占用的空间大小相同,内存地址连续,知道首元素的地址,可根据偏移量计算出目标元素的内存地址)
缺点:
- 数组无法存储大数据量
- 随机增删元素效率低
- 末尾增删不受影响
LinkedList
特点:
- 底层存储在双向链表中
- 由三部分组成:
上一个节点的内存地址、数据、下一个节点的内存地址
- 没有初始化容量,
first
和last
都是null
Vector(使用很少,了解即可)
- 底层是数组
- 初始化容量是 10
- 扩容之后是原容量的二倍 10-20-40-80
- Vector 都是线程同步/线程安全的,都带有synchronized关键字,使用较少
Set集合中的元素都等同于Map集合的Key
Map
与Collection没有关系
其存储方式以key-value
的形式存储(key和value都是引用数据类型)
不能直接存储对象,只能存储对象的内存地址
Map接口中常用的方法
方法 | 说明 |
---|---|
V put(K key, V value) | 向集合中添加键值对 |
V get(Object key) | 通过key获取value |
V remove(Object key) | 通过key删除value |
Collection< V> values() | 获取所有的value |
Set< K> keySet() | 返回Map集合中所有的key |
Map集合遍历的方式
方式一:先获取所有的key,再通过key来获取value
Iterator<Integer> it = keys.interator();
while(it.hasNext()){
//取出一个key
Integer key = it.next();
//通过key获取value
String value = map.get(key);
System.out.println(key+"+"+value);
}
方式二:将Map集合转化为Set集合
效率较高!!适合大数据量
Set<Map.Entry<Integer,String>> set = map.entrySet();
Iterator<Map.Entry<Integer,String>> it2 = map.entrySet();
while(it.hasNext()){
Map.Entry<Integer,String> node = it2.next();
Integer key = node.getKey();
String value = node.getValue();
System.out.println(key+"="+value);
}
HashMap
特点:
- 集合的默认初始化容量是16,默认加载因子是0.75
- 初始化容量必须是2的倍数
- 扩容是原来的二倍
- 默认加载因子是HashMap集合容量达到75%时数组开始扩容
- 非线程安全
HashMap的源代码中有以下属性:
final int hash; //实际上是key的hashCode()
final K key
V value
Node < K,V> next;
HashMap 集合允许key值为 null
但是HashMap集合的key null 值只能有一个
了解内容:
如果hashcode();固定为某个值,会使hashMap变成单项列表
这种情况叫:散列分布不均匀
如果hashcode()全部不一样的,会使hashMap变成一维数组
也是散列分布不均匀
散列分布均匀需要重写hascode();有一定的技巧
【最终结论】
放在HashMap key部分的元素和HashSet的元素
需要同时重写equals();和hashcode();
Properties
特点:
- 继承Hashtable
- 初始化容量是11,默认加载因子是0.75
- 扩容是原容量乘以2再加一
- 线程安全
- key和value都是字符串,且不能为空
常用方法 | 说明 |
---|---|
String getProperty(String key) | 根据键值,获取属性 |
Object setProperty(String key, String value) | 调用 Hashtable 的方法 put |
TreeMap
特点:
- 底层是二叉树
- 无序不可重复,存入的值会自动按照大小排序(String按字典升序,Integer按大小升序)
- 对自定义的类进行排序时,需要声明比较规则。如果没有实现 java.lang.Comparable比较接口 JVM会报错