Java集合详解
所有集合所在的包:java.util
集合是java中提供的一种容器,可以用来存储多个数据。
集合按照其存储结构可以分为两大类,分别是单列集合 java.util.Collection 和双列集合 java.util.Map
扩展
集合的初始化大小与自动扩容机制以(ArrayList为例)
- 初始化大小:默认的构造器,将会以默认的大小来初始化内部的数组:public ArrayList();如果刚刚创建的arraylist集合的话 其默认的大小是为0;(注意:在jdk1.6中ArrayList中创建出来的集合默认大小是10)
- 自动扩容机制:如果当前集合没有添加任何值的情况下,其大小还是为0,当添加第一个数据到集合中时,java会重新初始化集合大小为10.当集合大小刚刚到10的时候,集合不会自动扩容,当添加第11个数据的时候,Arraylist继续扩容变为10*1.5=15;当添加第16个数据时,继续扩容变为15 * 1.5 =22个;
集合和数组既然都是容器,它们有啥区别呢?
- 数组的长度是固定的。集合的长度是可变的。
- 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。
集合接口
- Interface Collection<泛型> //继承了Iterable<泛型>接口
- Interface List<泛型> //继承了Collection<泛型>接口
- Interface Set<泛型> //继承了Collection<泛型>接口
- Interface Map<键,值>
接下来依次分析每个集合接口
Interface Collection<泛型>
Collection特点(并没说其子类):
1. 允许元素重复
2. 有先后顺序
3. 有索引值
Collection的分类情况:
Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合。
- public boolean add(E e) : 把给定的对象添加到当前集合中 。
- public void clear() :清空集合中所有的元素。
- public boolean remove(E e) : 把给定的对象在当前集合中删除。
- public boolean contains(E e) : 判断当前集合中是否包含给定的对象。
- public boolean isEmpty() : 判断当前集合是否为空。
- public int size() : 返回集合中元素的个数。
- public Object[] toArray() : 把集合中的元素,存储到数组中。
如需了解更多,自行翻看JDK字典
下面简单运用一下:
public class Demo1Collection {
public static void main(String[] args) {
// 使用多态形式
Collection<String> coll = new ArrayList<String>();
// 使用方法
// boolean add(String s) 添加功能
coll.add("小李广");
coll.add("扫地僧");
coll.add("石破天");
System.out.println(coll); // [小李广, 扫地僧, 石破天]
// boolean contains(E e) 判断o是否在集合中存在
System.out.println("判断扫地僧是否在集中"+coll.contains("扫地僧")); // true
//boolean remove(E e) 删除在集合中的o元素
System.out.println("删除石破天:"+coll.remove("石破天")); // true
System.out.println(coll); // [小李广, 扫地僧]
// size() 集合中有几个元素
System.out.println("集合中有"+coll.size()+"个元素"); // 2
// Object[] toArray()转换成一个Object数组
Object[] objects = coll.toArray();
// 遍历数组
for (int i = 0; i < objects.length; i++) {
System.out.print(objects[i]+" "); // 小李广 扫地僧
}
// void clear() 清空集合
coll.clear();
System.out.println("集合中内容为:"+coll); // []
// boolean isEmpty() 判断是否为空
System.out.println(coll.isEmpty()); // true
}
}
Interface List<泛型>
List的特点
- 它是一个元素存取有序的集合 ->有序指的是先后顺序,而非大小顺序
- 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素
- 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
List作为Collection集合的子接口,不但继承了Collection接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法,如下:
- public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上。
- public E get(int index) :返回集合中指定位置的元素。
- public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素。
- public E set(int index, E element) :用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
演示代码如下:
public class ListDemo {
public static void main(String[] args) {
// 创建List集合对象
List<String> list = new ArrayList<String>();
// 往尾部添加指定元素
list.add("图图");
list.add("小美");
list.add("不高兴");
System.out.println(list); // [图图, 小美, 不高兴]
// add(int index,String s) 往指定位置添加
list.add(1,"没头脑");
System.out.println(list); // [图图, 没头脑, 小美, 不高兴]
// String remove(int index) 删除指定位置元素 返回被删除元素
// 删除索引位置为2的元素 它会将返回的值返回
System.out.println(list.remove(2)); // 小美
System.out.println(list); // [图图, 没头脑, 不高兴]
// String set(int index,String s) 在指定位置 进行 元素替代
// 修改指定位置元素
list.set(0, "三毛");
System.out.println(list); // [三毛, 没头脑, 不高兴]
// String get(int index) 获取指定位置元素
// 跟size() 方法一起用 来 遍历的
for(int i = 0;i<list.size();i++){
System.out.print(list.get(i)+" "); // 三毛 没头脑 不高兴
}
System.out.println(); // 换行
//还可以使用增强for
for (String string : list) {
System.out.print(string+" "); //没头脑 不高兴
}
}
}
List的子类
ArrayList
- java.util.ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以 ArrayList 是最常用的集合。
- ArrayList 中可不断添加元素,其大小也自动增长。(参考上方扩展的自动扩容机制)
- 方法请看其父类LIst,Collection
LinkedList
- java.util.LinkedList 集合数据存储的结构是链表结构,而且还是双向链表,方便元素添加、删除的集合,但查找慢。
- LinkedList是List的子类,List中的方法LinkedList都是可以使用,LinkedList还有特有方法。
- public void addFirst(E e) :将指定元素插入此列表的开头。
- public void addLast(E e) :将指定元素添加到此列表的结尾。
- public E getFirst() :返回此列表的第一个元素。
- public E getLast() :返回此列表的最后一个元素。
- public E removeFirst() :移除并返回此列表的第一个元素。
- public E removeLast() :移除并返回此列表的最后一个元素。
- public E pop() :从此列表所表示的堆栈处弹出一个元素。
- public void push(E e) :将元素推入此列表所表示的堆栈。
- public boolean isEmpty() :如果列表不包含元素,则返回true
其中pop()等同于 removeFirst() ,push(E e)等同于addFirst(E e),只是更加面向对象化一点
代码演示如下:
public class Demo02ArrayVsLinked {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
list.add("王俊凯");
list.add("王源");
list.add("易烊千玺");
System.out.println(list); // [王俊凯, 王源, 易烊千玺]
list.addFirst("杨洋");
System.out.println(list); // [杨洋, 王俊凯, 王源, 易烊千玺]
list.addFirst("张一山");
System.out.println(list); // [张一山, 杨洋, 王俊凯, 王源, 易烊千玺]
list.addLast("胡一天");
System.out.println(list); // [张一山, 杨洋, 王俊凯, 王源, 易烊千玺, 胡一天]
System.out.println("开头元素:" + list.getFirst()); // 张一山
System.out.println("末尾元素:" + list.getLast()); // 胡一天
System.out.println(list); // [张一山, 杨洋, 王俊凯, 王源, 易烊千玺, 胡一天]
System.out.println("删掉的开头元素:" + list.removeFirst()); // 张一山
System.out.println(list); // [杨洋, 王俊凯, 王源, 易烊千玺, 胡一天]
System.out.println("删掉的开头元素:" + list.removeFirst()); // 杨洋
System.out.println(list); // [王俊凯, 王源, 易烊千玺, 胡一天]
System.out.println("删掉的开头元素:" + list.removeFirst()); // 王俊凯
System.out.println(list); // [王源, 易烊千玺, 胡一天]
System.out.println("================");
System.out.println("删掉末尾元素:" + list.removeLast()); // 胡一天
System.out.println(list); // [王源, 易烊千玺]
}
}
Vector(不做重点)
和ArrayList基本一样,底层也是数组,只是线程安全,所以性能不如ArrayList快。
Interface Set<泛型>
Set的特点
- Set 接口中元素无序
- 都会以某种规则保证存入的元素不出现重复
- 没有索引值
Set的实现类
HashSet
- HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于: hashCode 与 equals 方法。equals负责决定对象是否相同,hashCode负责进行哈希加速。
- HashSet是最为常用的Set集合,底层使用一种名叫“哈希表”的数据结构,特点就是特别快。底层其实是在复用HashMap。
LinkedHashSet
- 底层也是哈希表,但是额外还有链表,用来维护先后顺序。
TreeSet
- 有大小排序。
- 要求实现Comparable接⼝
Interface Map<键,值>
Map特点
- Map 中的集合称为双列集合,存放的是一对儿数据
- Map 中的集合不能包含重复的键,值可以重复;每个键只能对应一个值。由equals和hashCode方法,来确定Map的键不能重复。
- 遍历Map集合的方法一:通过keySet方法首先拿到所有的键。再根据get方法,得到每个键对应的值.
- 遍历Map集合的方法二:
- 首先直接获取所有的键值对儿:entrySet
- 根据键值对儿获取键:getKey
- 根据键值对儿获取值:getValue
常用的方法:
- public V put(K key, V value) : 把指定的键与指定的值添加到Map集合中。
注意事项
- 使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中;
- 若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。
- public V remove(Object key) : 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
- public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
- public Set<键> keySet() : 获取Map集合中所有的键,存储到Set集合中。
public Set<Map.Entry<K,V>> entrySet() : 获取到Map集合中所有的键值对对象的集合(Set集合)
(重要)
遍历集合方法一:
代码如下:
public class Demo02MapKeySet {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("王宝强", "马蓉");
map.put("贾乃亮", "李小璐");
map.put("陈羽凡", "白百何");
// 拿到所有的键
Set<String> keys = map.keySet();
for (String key : keys) {
String value = map.get(key);
System.out.println(key + "的老婆是" + value);
}
System.out.println("==========");
Set<String> keys2 = map.keySet();
Iterator<String> iter = keys2.iterator();
while (iter.hasNext()) {
String key = iter.next();
String value = map.get(key);
System.out.println(key + "的相好是" + value);
}
}
}
遍历集合方法二:
public class Demo03MapEntrySet {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("王宝强", "马蓉");
map.put("贾乃亮", "李小璐");
map.put("陈羽凡", "白百何");
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "的bitch是" + value);
}
}
}
Map的实现类
HashMap
- 底层有哈希表,所以查找键的速度特别快。HashSet底层就是在复用HashMap
- 由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
- 存储数据采用的哈希表结构,元素的存取顺序不能保证一致
- Map的键和值数据类型可以不同
LinkedHashMap
- 是HashMap的子类,速度也挺快,但是额外还有链表,从而维护先后顺序。
- 通过哈希表结构可以保证的键的唯一、不重复,需要重写键的
hashCode()方法、equals()方法。
TreeMap
- 键带有大小排序功能
- 注意事项:
如果自定义的类型作为TreeMap的value,没有要求。
但是自定义的类型作为TreeMap的key,就必须要实现Comparable接口。
例如:(Person构造略)
...
@Override
public int compareTo(Person o) {
return age - o.age;
}
...
public class Demo02TreeSetAndTreeMap {
public static void main(String[] args) {
Set<String> set = new TreeSet<>();
set.add("DDD");
set.add("BBB");
set.add("AAA");
set.add("CCC");
System.out.println(set); // [AAA, BBB, CCC, DDD]
System.out.println("=========");
Map<String, String> mapA = new TreeMap<>();
mapA.put("DDD", "value");
mapA.put("BBB", "value");
mapA.put("AAA", "value");
mapA.put("CCC", "value");
Set<Map.Entry<String, String>> entries = mapA.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + " - " + value);
}
System.out.println("=========");
Map<Person, String> mapB = new TreeMap<>();
mapB.put(new Person("鹿晗", 40), "北京");
mapB.put(new Person("吴亦凡", 35), "广州");
Set<Person> keys = mapB.keySet();
for (Person key : keys) {
String value = mapB.get(key);
System.out.println(key + " - " + value);
}
}
}