什么是集合:
一个用来存储多个元素的容器。
集合和数组的区别:
- 数组长度不变,能存储基本数据类型和引用数据类型。
- 集合长度可变,只能存储引用数据类型。
引用数据类型:
基本类型 | 基本类型包装类 |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
转化的规律:
基本上都是首字母大写,特别的:
- int ==> Integer
- char ==> Character
集合的分类:
- 单列集合(Collection): 每次存储元素只存储一个元素。
- 双列集合(Map): 每次存储元素时要存储两个元素。
数据缓冲池
当使用引用类型Integer时,元素并不是存在常量池中的,而是重新创建new出来的(引用类型)。但是存储Integer存在数据缓冲池的概念,即:第一次创建都一定是new出来的,但是如果元素是在-128——127之间,就会存储在数据缓冲池中,第二次就不用创建对象,直接使用。如果不在-128——127这个范围内,则每次都需要重新创建对象。
collection集合
继承体系:
Collection: 父接口。 (所有单列集合的父类)
1) List:子接口 (有索引)
- ArrayList:实现类
- LinkedList:实现类
- Vector(过时了,只需了解):实现类
2)Set:子接口 (没有索引)
- HashSet:实现类
- LinkedHashSet:实现类
Collection集合常用方法:
public boolean add(E e)
- 添加元素 添加成功返回true,否则false。
- List的add方法,全部返回true。方法里面就是return true。
public void clear()
- 将集合元素清空
boolean remove(E e)
- 删除指定的元素,删除成功返回true,否则false。
- 如果有多个相同的元素,默认只会删除第一个。
boolean contains(E e)
- 判断集合中是否包含指定的元素,包含返回true,否则false。
public boolean isEmpty()
- 判断集合是否为空(元素个数是否为零),是返回true,否则false。
public int size()
- 获得元素个数。
public Object[] toArray()
- 将集合中的元素添加到数组返回。
- 集合转数组。
实例代码:
public class CollectionDemo01 {
public static void main(String[] args){
// 创建集合对象
Collection<String> c = new ArrayList<>();
// 添加元素
c.add("aaa");
c.add("bbb");
c.add("aaa");
c.add("ccc");
System.out.println(c);
// 删除元素:aaa
System.out.println(c.remove("aaa")); // true
// 判断集合是否包含元素:aaa
System.out.println(c.contains("aaa")); // true
// 集合转数组
Object[] objs = c.toArray();
System.out.println(Arrays.toString(objs)); // [bbb, aaa, ccc]
// 清空集合元素
c.clear();
System.out.println(c);
// 判断集合是否为空
System.out.println(c.isEmpty());
}
}
单列集合的小结:
List:有序,有索引,元素可重复。
- ArrayList:底层结构:数组,增删慢,查询快,线程不安全,效率高 。
- LinkedList:底层结构:链表,增删快,查询慢,线程不安全,效率高 。
Set:无序,无索引,元素不可重复。
- HashSet:底层结构:哈希表:数组+链表+红黑树,线程不安全,效率高 。
- LinkedHashSet:底层结构:哈希表+链表,能够保证存取有序,线程不安全,效率高 。
单列集合的选择:
如果要求元素可重复,则在List体系下选择 。
- 如果只执行查询操作,则选择ArrayList 。
- 如果需要执行增删操作,则选择LinkedList 。
如果要求元素不可重复,则在Set体系下选择
- 如果要求存取顺序一致,则选择LinkedHashSet,否则选择HashSet 。
List集合
List集合的概述:
List是一个接口,只要实现了该接口的类都是List类单列集合。
List集合的特点:
有序(存取顺序一致),有索引,元素可重复。
List集合的遍历方法:
- 普通for
- 迭代器
- 增强for
List接口中特有的方法:(要注意索引越界的问题)
public void add(int index, E element)
- 将元素添加到指定的位置。
- 如果index = List.size() 不会报错,作用与add(E element)一样。
public E get(int index)
- 根据索引获得指定位置元素。
public E remove(int index)
- 删除指定位置的元素,返回被删除的元素
- 如果是删除List<Integer>里的元素,无论是根据元素或索引元素,都是数字。当输入数字时,会根据索引删除。若想根据元素删除,则要把数字写成包装类。
- 例:Integer.valueOf(元素)
public E set(int index, E element)
- 将指定位置的元素修改为指定的值。
示例代码:
public class ListDemo01 {
public static void main(String[] args){
// 创建集合对象
List<Integer> list = new ArrayList<>();
// 添加元素
list.add(1);
list.add(2);
list.add(3);
System.out.println(list); // [1,2,3]
// 将元素4添加到索引为2的位置
list.add(2,4);
System.out.println(list);// [1,2,4,3]
// 根据索引获得指定位置元素
System.out.println(list.get(3)); // 3
// 删除指定位置的元素
System.out.println(list.remove(3));// 3
System.out.println(list); // [1,2,4]
// 将指定位置的元素修改为指定的值
list.set(2, 5);
System.out.println(list); // [1,2,5]
// 删除指定的元素,删除成功返回true,否则false
System.out.println(list.remove(Integer.valueOf(9))); // true
System.out.println(list); // [2,5]
}
}
ArrayList
特点:
- 有序(存取顺序一致),有索引,元素可重复。
- 底层结构是数组: 增删慢,查询快,线程不安全,效率高。
- 一开始创建创建容量为10的数组,每次扩容1.5倍。
所在包:
java.util
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 class LinkedListDemo01 {
public static void main(String[] args){
// 创建LinkedList集合对象
LinkedList<String> list = new LinkedList<>();
// 添加元素
list.add("aa");
list.add("bb");
list.add("cc");
// 根据索引获得元素
System.out.println(list.get(0));
//将元素添加到链表头
list.addFirst("dd");
// 将元素添加到链表尾部
list.addLast("ee");
System.out.println(list); // [dd,aa,bb,cc,ee]
// 获得链表头元素
System.out.println(list.getFirst());// dd
// 获得链表尾元素
System.out.println(list.getLast());// ee
System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐");
// 删除链表头元素
System.out.println(list.removeFirst()); // dd
System.out.println(list.removeFirst()); // aa
System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐");
// 删除链表尾元素
System.out.println(list.removeLast()); // ee
System.out.println(list.removeLast()); // cc
}
}
链表根据索引获得元素从链表头还是链表尾开始遍历查询:
- 当索引小于集合个数的一半,则从链表头开始遍历查询。
- 当索引大于等于集合个数的一半,则从链表尾部开始遍历查询。
Set集
特点:
无序(存取顺序不一致),无索引,元素不可重复。
- Set集合没有特有的方法,都是用Collection父接口的方法。
- Set是一个接口,只要实现了该接口的类都是Set类单列集合。
Set集合常用子类:
- HashSet
- LinkedHashSet
Set集合遍历方式:
- 增强for
- 迭代器
- 因为没有索引,所以不能用普通for。
HashSet和LinkedHashSet选择:
如果要求存取顺序一致,则选LinkedHashSet,否则推荐HashSet。
HashSet集合
HashSet集合的特点:
- JDK1.8之前:哈希表是数组和链表的结合体。
- JDK1.8之后:哈希表时数组+链表+红黑树。
HashSet如何存储元素:
HashSet 存储元素的过程是根据对象的哈希值来确定元素在集合中的存储位置,底层主要依赖于元素的:
hashCode 与 equals 方法。所有当存储自定义对象时,如果希望两个对象成员变量值都相同时只存储一个,则需
要在自定义类中重写 hashCode 与 equals 方法。
LinkedHashSet集合
LinkedHashSet集合特点:
- 继承HashSet,能够保证存取顺序一致。
- 底层结构是:哈希表+链表。
Map集合
注意事项:
Map的Key和Value都只能存储引用类型数据。
Map集合概述:
- Map ==> 映射(一个对应一个)。
- Map是一个接口,只要实现了该接口的类都是双列集合。
- 双列集合每次存储元素时都需要存储两个元素,一个元素称为键,一个元素称为值,简称键值对。
- 特点:键必须唯一,值可以重复。
Map集合常用实现类:
- HashMap
- LinkedHashMap
- Hashtable(过时了) 原因:线程安全,效率低。
Map接口中的常用方法:
V put(K key, V value) 增改方法
- 存储键值对。
- 如果键存在,则使用新值替换旧值,返回旧值。
- 如果键不存在,则返回null。
V get(Object key)
- 根据键获得对应的值。
- 如果键不存在,则返回null。
V remove(Object key)
- 根据键删除键值对,返回键对应的值,如果键不存在,返回null。
Boolean remove(Object key,Object value)
- 如果有对应的键值对,则删除,然后返回true。
- 如果没有对应的键值对,则返回false。
int size()
- 获得键值对个数。
void clear()
- 清空集合,删除所有键值对。
boolean containsKey(Object key)
- 判断集合中是否包含对应的键,包含返回true,否则false。
boolean isEmpty()
- 判断集合是否为空,键值对个数是否为零,是返回true,否则false。
Map的值不能直接修改,若要修改,可put一样的键,不同的值。
各方法的示例代码:
public class MapDemo01 {
public static void main(String[] args){
// 创建Map集合
Map<String,String> map = new HashMap<>();
// 添加键值对
String name = map.put("001", "jack");
System.out.println("name = " + name); // null
name = map.put("001", "rose");
System.out.println("name = " + name); // jack
map.put("002", "laowang");
System.out.println(map);
System.out.println("‐‐‐‐‐‐‐‐‐‐‐");
// 根据键获得值
System.out.println(map.get("001"));
// 根据键删除键值对
System.out.println(map.remove("001"));
System.out.println(map);
System.out.println("‐‐‐‐‐‐‐‐‐‐‐");
// 获得键值对个数
System.out.println(map.size());
System.out.println("‐‐‐‐‐‐‐‐‐‐‐");
// 判断集合是否包含指定的键
System.out.println(map.containsKey("002"));
// 清空集合
map.clear();
System.out.println(map); // {}
// 判断集合是否为空
System.out.println(map.isEmpty());
}
}
Map集合遍历键找值方式
Map集合的遍历方式1:通过键找值方式遍历:
- 调用Map集合的keySet方法获得键集合。
- 通过增强for或迭代器遍历键集合。
- 通过调用Map集合的get方法根据键获得值。
Map集合与遍历相关的方法:
- Set<K> keySet() 获得键集合
示例代码:
public class MapDemo02 {
public static void main(String[] args){
// 创建Map集合
Map<String,String> map = new HashMap<>();
// 存储键值对
map.put("001", "jack");
map.put("002", "rose");
map.put("003", "lily");
map.put("004", "lucy");
// 获得键集合
Set<String> keySet = map.keySet();
// 使用增强for遍历键集合
for (String key : keySet) {
// 根据键获得值
String value = map.get(key);
System.out.println(key+"="+value);
}
System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐");
// 获得键集合对应的迭代器对象
Iterator<String> it = keySet.iterator();
while (it.hasNext()){
// 获得键
String key = it.next();
// 获得值
String value = map.get(key);
System.out.println(key+"="+value);
}
}
}
Map集合的遍历方式2:通过键值对对象遍历:
- 调用Map集合的entrySet方法获得Entry对象集合。
- 使用增强for或迭代器遍历Entry对象集合。
- 调用Entry对象的getKey和getValue方法获得键和值。
Map集合中与遍历相关的方法:
- Set<Entry<K,V>> entrySet() 获得Entry对象集合
Entry对象概述:
- 每一个键值对都对应一个Entry对象。
- Entry对象又称为键值对对象。
Entry对象常用方法:
- K getKey(); 获得键
- V getValue(); 获得值
示例代码:
public class MapDemo03 {
public static void main(String[] args){
// 创建Map集合
Map<String,String> map = new HashMap<>();
// 存储键值对
map.put("001", "jack"); // "001".hashCode() = 1010 % 16 = 1
map.put("002", "rose"); // "002".hashCode() = 2010 % 16 = 1
map.put("003", "lily");
map.put("004", "lucy");
// 获得Entry对象集合
Set<Entry<String,String>> entrySet = map.entrySet();
// 使用增强for遍历集合
for(Entry<String,String> entry:entrySet){
// 获得键和值
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"="+value);
}
System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐");
// 使用迭代器遍历
Iterator<Entry<String, String>> it = entrySet.iterator();
while (it.hasNext()){
// 获得Entry对象
Entry<String, String> entry = it.next();
System.out.println(entry);
/*// 获得键和值
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"="+value);*/
}
}
}
HashMap集合
HashMap集合的特点:
底层结构是:哈希表。
HashMap集合存储自定义对象:
- 底层依赖hashCode和equals方法。
- 如果自定义对象作为键们需要重写hashCode和equals方法才能实现去重效果。
- 如果自定义对象作为值,不需要重写hashCode和equals方法。
LinkedHashMap集合
LinkedHashMap集合特点:
- 继承HashMap,能够保证存取有序。
- 底层结构:哈希表+链表。
JDK9对集合添加元素的优化
概述:
- 通常,我们在代码中创建一个集合(例如,List 或 Set ),并直接用一些元素填充它。 实例化集合,几个 add方法调用,使得代码重复。
- Java 9,添加了几种集合工厂方法,更方便创建少量元素的集合、map实例。新的List、Set、Map的静态工厂方法可
以更方便地创建集合的不可变实例。
示例代码:
public class HelloJDK9 {
public static void main(String[] args) {
Set<String> str1=Set.of("a","b","c");
//str1.add("c");这里编译的时候不会错,但是执行的时候会报错,因为是不可变的集合
System.out.println(str1);
Map<String,Integer> str2=Map.of("a",1,"b",2);
System.out.println(str2);
List<String> str3=List.of("a","b");
System.out.println(str3);
}
}
注意事项:
- of()方法只是Map,List,Set这三个接口的静态方法,其父类接口和子类实现并没有这类方法,比如
HashSet,ArrayList。- 返回的集合是不可变的。
- 但是此方法有缺陷:存储Set集合时,当里面的元素有重复时就会报错;存储Map集合时,当里面存储的元素存在键值一样时,也会报错。