文章目录
一、数组
数组的缺点:
- 长度不可变
- 插入、删除元素操作比较繁琐
- 元素查找比较繁琐
- 元素类型单一
数组的优势
- 顺序存储,便于遍历
- 添加元素方便
二、集合框架
java中的集合框架不是一个类,而是提供了一组类
- 实线:表示继承(泛化)关系
- 虚线:表示实现关系
- 接口:Iterator, Collection, List, Set, SortedSet
- 实现类:Vector, ArrayList, LinkedList, HashSet, LinkedHashSet,TreeSet
- Iterator:可迭代的(可遍历的),所有集合元素都是可迭代的
- Collection:所有继承与Iterator,所有集合元素都是可迭代的
- List:存储元素特点是:有序可重复的,存储元素有下标
- 有序:指的是存进去这个顺序,取出来还是这个顺序,所以这里的顺序不是指按照大小顺序
- 可重复:元素可以重复
- Set:存储元素特点:无序不可重复的,无下标的
- 无序:表示存进去这个顺序,出来之后可能变了一个顺序
- 不可重复的:元素不可重复的
- ArrayList:集合底层采用了数组这种数据结构,它是非线程安全的
- LinkedList:底层采用了双向列表的数据结构
- Vector:集合底层采用了数组这种数据结构,它是线程安全的,它的所有方法都用synchronized关键字修饰,所以线程安全,但是效率低,现在保证线程安全有其他的方法了,所以这个集合就很少用了
- HashSet:实际上HashSet集合在new的时候,底层实际new了一个HashMap集合,向HashSet集合中存储元素,实际上是存储到HashMap集合中了,HashMap集合是一个哈希表结构
- TreeSet:实际上TreeSet集合在new的时候,底层实际new了一个TreeMap集合,向TreeSet集合中存储元素,实际上是存储到TreeMap集合中了,TreeMap集合是一个哈希表结构(因为TreeSet实现了SortedSet集合,所以TreeSet也会自动从小到大进行排序)
- SortedSet:由于继承了set集合,所以它的特点特使无序比可重复的,但是放到在SortedSet集合里的元素可以自动排序,我们称为可排序集合,放到该集合中的元素会按照大小顺序进行排序
Collection
List
概述:有序的Collection也称为序列,Collection下的所有实现类都实现了特定的方法,方便用户对列表中元素进行精准的控制
ArrayList
- 概述:ArrayList的底层是基于数组进行实现的,ArrayList集合中允许插入null值
- 构造器
- ArrayList():将集合初始值为默认大小
- ArrayList():将集合初始为指定大小,大小由用户通过参数进行指定
//将集合初始化为指定的大小(0个长度)
//this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
//private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
List<Integer> list1 = new ArrayList<>();
//将基础初始化为指定的大小
//实例化集合对象时尽量将集合初始化为指定的大小,这可以避免因为容量不足而导致频繁扩容
List<Integer> list2 = new ArrayList<>(10);
- 常用方法
//2、常用方法
//a、add():将元素添加到现有集合的末尾
list2.add(20);
//获取集合中的元素
//b、get():获取指定索引位置的元素(索引下标从0开始)
System.out.println(list2.get(0));
//c、set():设置指定索引位置元素的值(修改元素的值)
list2.set(0,99);
System.out.println(list2.get(0));
//d、contains():返回集合中是否包含指定值的元素
System.out.println(list2.contains(99));
//e、indexOf():返回元素在集合中首次出现的索引位置
System.out.println(list2.indexOf(99));
//f、lastIndexOf():返回元素在集合中最后一次出现的索引位置
System.out.println(list2.lastIndexOf(99));
//g、remove():移除指定值的元素对象
//注:如果参数为整型数值,则默认为索引值
list2.remove(99);
//remove():移除指定索引位置的元素对象
list2.remove(0);
//h、clear():移除集合中所有元素
list2.clear();
//i、isEmpty():返回当前集合对象是否为空对象
System.out.println(list2.isEmpty());
//j、size():返回列表的元素个数
System.out.println(list2.size());
//k、toArray():将一个list集合转为Object数组对象
Object[] arr = list2.toArray();
- 遍历ArrayList
List<Integer> list = new ArrayList<>();
//添加n个元素
list.add(2);
list.add(8);
list.add(11);
list.add(5);
//通过for循环进行遍历
for(int i = 0;i<list.size();i++)
System.out.println(list.get(i));
//通过增强for循环进行遍历
for(int i : list)
System.out.println(i);
//迭代器方式遍历集合对象
Iterator<Integer> iter = list.iterator();
//hasNext():返回一个布尔值,标识当前集合对象的遍历是否具有下一个元素
while(iter.hasNext()){
//next():返回当前集合的下一个元素
int v = iter.next();
System.out.println(v);
}
System.out.println(list.size());
- ArrayList的底层实现
public class ArrayList<E> implements List<E>{
/**
* Default initial capacity.
* 默认的初始容量,默认初始容量为10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
* 声明一个空数组对象
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*声明一个空数组对象
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
* 声明一个Object类型的数组对象用于存储集合的元素
*/
transient Object[] elementData; // non-private to simplify nested class access
}
- 集合对象的实例化
/**
* Constructs an empty list with an initial capacity of ten.
* 构造一个具有0个元素的空数组对象
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* Constructs an empty list with the specified initial capacity.
* 实例化一个具有指定长度的数组对象
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
}
}
- 添加元素
/添加元素
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//确认数组的大小
private void ensureCapacityInternal(int minCapacity) {
//判断当前数组对象是否是一个空数组对象
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//得到最大的容量
//从默认容量(10)、参数中选择较大的容量
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//检查是否需要扩容
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
//判断最大容量是否大于当前集合的容量
if (minCapacity - elementData.length > 0)
//如果大于当前集合容量(集合空间不足),则进行扩容
grow(minCapacity);
}
//执行扩容操作
private void grow(int minCapacity) {
// overflow-conscious code
//获取当前集合的容量
int oldCapacity = elementData.length;
//通过计算得到新的容量
//新容量=旧容量+(旧容量/2)
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果新容量小于需要容量(minCapacity)则新容量=最小需要的容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//如果新容量接近int类型的最大值(maxValue-8)
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//对存储元素的数组进行扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
Vector
- 概述:实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。
- 构造器
- Vector():创建一个空的集合对象
- Vector(int):创建一个指定容量的集合对象
- 常用方法
参考ArrayList - 集合对象的实例化
/*
* 构建一个具有指定容量的数组对象
*/
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
/**
*实例化一个具有10个容量的数组对象
*/
public Vector() {
this(10);
}
- 添加元素(源码)
public synchronized boolean add(E e) {
modCount++;
//检查是否需要对数组进行扩容
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
//判断所需要的最小容量是否大于数组长度
if (minCapacity - elementData.length > 0)
//执行扩容操作
grow(minCapacity);
}
//执行扩容操作
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
- ArrayList与Vector的异同
- 相同点:
- 6)ArrayList与Vector的底层都是基于数组进行实现的
- 不同点:
- Vector是线程安全的(现在用的很少了,虽然是线程安全的,但是效率会大大下降),ArrayList是非线程安全的
- 默认情况下,Vector的初始容量为10;ArrayList的初始容量为0
- 相同点:
LinkedList
- 概述:LinkedList底层是基于链表进行实现的,且允许所有元素的值为null,并且,改类提供了队列、栈的实现
- 常用方法
//实例化一个集合对象
List<Integer> list = new LinkedList<>();
//常用方法
//a、add():将元素添加到现有集合的末尾
list.add(20);
//b、get():获取指定索引位置的元素(索引下标从0开始)
System.out.println(list.get(0));
//c、set():设置指定索引位置元素的值(修改元素的值)
list.set(0,88);
System.out.println(list.get(0));
//d、contains():返回集合中是否包含指定值的元素
System.out.println(list.contains(20));
//e、indexOf():返回元素在集合中首次出现的索引位置
System.out.println(list.indexOf(88));
//f、lastIndexOf():返回元素在集合中最后一次出现的索引位置
System.out.println(list.lastIndexOf(88));
//g、remove():移除指定值的元素对象
//注:如果参数为整型数值,则默认为索引值
//list.remove(99);
//remove():移除指定索引位置的元素对象
list.remove(0);
//h、clear():移除集合中所有元素
list.clear();
//i、isEmpty():返回当前集合对象是否为空对象
System.out.println(list.isEmpty());
//j、size():返回列表的元素个数
System.out.println(list.size());
//k、toArray():将一个list集合转为Object数组对象
Object[] arr = list.toArray();
- 栈的实现
/**
* 栈是一种数据结构
* 栈的操作都在一端完成。
* 将数据添加到栈中称为(压)入栈,从栈中取出称为出栈
* 先入栈的数据在栈底,会最后被取出.所以栈的特点是:先进后出(FILO--First In Last Out)
* @author TerryLiu
*/
public class LinkedListDemo02 {
public static void main(String[] args) {
//实力化lie表对象
LinkedList<Integer> list = new LinkedList<>();
//数据压入到栈中
//a、push():将元素压入栈中
list.push(20);
list.push(78);
//数据出栈
//b、pop():将元素弹出栈外
//栈顶元素--78,栈底元素--20
//栈顶元素先出栈
System.out.println(list.pop());
System.out.println(list.size());
}
}
- 队列的相关操作
/**
* 队列是一种数据结构
* 队列的添加操作在队尾完成,而读取操作在队首完成
* 队列中先入队的数据也会最先被出队,所以队列是先进先出的(FIFO--First In First Out)
* @author TerryLiu
*/
public class LinkedListDemo03 {
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
list.add(99);
list.add(103);
list.add(2);
System.out.println(list.size());
//a、peek():返回但不移除队首元素
//peekFirst():返回队首元素
//peekLast():返回队尾元素
//System.out.println(list.peek());
//b、poll():返回并移除队首元素
//pollFirst():返回并移除队首元素
//pollLast():返回并移除队尾元素
System.out.println(list.poll());
System.out.println(list.size());
}
}
ArrayList、Vector、LinkedList的区别
区别
- ArrayList、Vector底层是基于数组进行实现的;LinkedList底层是基于链表进行实现的
- ArrayList、LinkedList底层是非线程安全的;Vector是线程安全的
- ArrayList、LinkedList的默认初始化大小为0;Vector默认大小为10
应用场景
- ArrayList、Vector适用于需要经常遍历、通过下标进行查询的场景
- LinkedList适用于频繁的插入,移除操作
Set
set集合的特点:
- 集合内元素是无序的(除了TreeSet)
- 集合内元素不可重复
- 集合内允许有null值
- 无法通过下标获取元素或进行遍历
HashSet
- 概述:Set接口的实现类,HashSet集合是Hash表支持的,HashSet是基于HashMap进行实现的,存储在HashSet内部的数据时无序不重复的。HashSet集合中允许出现null值。
- 常用方法
//实例化一个具有默认大小的Set集合对象
Set<Integer> set1 = new HashSet<>();
//实例化一个具有指定大小的Set集合
Set<Integer> set2 = new HashSet<>(10);
//常用方法
//a、add():向现有集合的末尾添加元素
set1.add(20);
//b、contains():返回当前集合中是否包含指定值的元素
System.out.println(set1.contains(20));
//c、isEmpty():返回当前集合是否为空集合
System.out.println(set1.isEmpty());
//d、size():返回当前集合的元素个数
System.out.println(set1.size());
//e、remove():移除集合中指定值的元素
set1.remove(20);
- 添加元素的特点
HashSet底层是基于HashMap进行实现的,而HashMap底层是基于数组+链表/红黑树进行实现的。添加元素的过程中是按照元素值的hashCode来进行添加的,添加过程中如果出现相同hashCode的值,则会调用equals()方法对元素的值进行比较。如果equals比较的值相等则认为元素值已经存在,不会在向集合中添加元素,否则,如果元素的值不相等则将元素添加到集合中。
TreeSet
- 概述:TreeSet是按照自然排序的方式对元素进行排序的。TreeSet中的数据是有序的,且底层是基于TreeMap进行实现的。
- 构造函数
- TreeSet():无参构造函数,使用默认的比较化器进行比较
- TreeSet:但惨构造函数,通过构造函数提供一个指定的比较化器
//使用无参构造器进行对象的构造
Set<Integer> set1 = new TreeSet<>();
//使用带参构造函数进行对象的构造(构造函数中提供自然排序比较化器)
Set<Integer> set2 = new TreeSet<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return 0;
}
@Override
public boolean equals(Object obj) {
return false;
}
});
- 常用方法
Set<Integer> set = new TreeSet<>();
//a、add():向现有集合中添加新元素
set.add(20);
//b、contains():集合中是否包含指定值的元素对象
System.out.println(set.contains(20));
//c、isEmpty():返回集合是否为空
System.out.println(set.isEmpty());
//d、size():返回集合中元素的个数
System.out.println(set.size());
//e、remove():移除指定值的元素
set.remove(20);
TreeSet<Integer> set = new TreeSet<>();
//为集合添加元素
set.add(20);
set.add(45);
set.add(0);
set.add(78);
set.add(-101);
//特有方法
//a、ceiling():返回集合中大于指定值的元素列表中最小元素对象
System.out.println(set.ceiling(7));
//b、floor():返回集合中小于指定值的元素列表中最大的元素对象
System.out.println(set.floor(7));
//与ceiling、floor相似
System.out.println(set.lower(7));
System.out.println(set.higher(7));
System.out.println("size:" + set.size());
//c、first():返回set集合中第一个元素(最小元素)
System.out.println(set.first());
//d、last():返回set集合中最后一个元素(最大元素)
System.out.println(set.last());
System.out.println("size:" + set.size());
list和Set的区别
- List是有序的列表;Set无序不可重复的
- List可以通过索引下标进行遍历和操作;Set无法通过索引下标进行遍历和操作
Map
概述:由键值对组成的集合。键和值一对一的映射。键不能出现重复,但值可以
HashMap
- 概述:HashMap是基于Hash表的Map接口进行实现,提供了所有可选映射操作,并提供了null值和null键,HashMap无法保证数据的顺序是恒久不变的
- 构造器
- HashMap():实例化一个具有默认容量的集合对象
- HashMap(int):实例化一个具有指定容量的集合对象
- 常用方法
//实例化一个具有指定大小的元素对象
Map<String,Integer> map = new HashMap<>();
//常用方法
//a、put():向集合内添加键值对
map.put("Tom",28);
map.put("Jerry",36);
//b、get():按Key读取映射的值
System.out.println(map.get("Jerry"));
//c、size():映射的键值对的个数
System.out.println(map.size());
//d、isEmpty():返回当前集合是否为空
System.out.println(map.isEmpty());
//e、containsKey():集合中是否包含指定值的键
System.out.println(map.containsKey("Tom"));
//e、containsValue():集合中是否包含指定值的值
System.out.println(map.containsValue(36));
//f、keySet():返回键的集合
Set<String> keys = map.keySet();
for(String k : keys){
System.out.println(k + " ----- " +map.get(k));
}
//g、values():返回值的集合
Collection<Integer> values = map.values();
for(int v : values)
System.out.println(v);
//h、remove():按照key值移除一个键值对的映射
map.remove("Tom");
//i、clear():移除所有的键值对映射
map.clear();
System.out.println(map.size());
- 修改Map的值
//创建一个Map集合对象
Map<Integer,String> map = new HashMap<>();
//向集合和添加元素
map.put(1,"Tome");
map.put(2,"Jerry");
map.put(3,"Lucy");
//修改key值为2的元素的值
map.put(2,"HanMeimei");
//遍历Map中的元素
//什么是Entry
// private static final class MapEntry implements Map.Entry {
// private Object key ;
// private Object value ;}
//Entry是Map集合中的一个元素对象,Entry内包含了k和v。
//Set<T>:T是set中元素的类型,在本示例中元素的类型为Entry类型
//Entry<T,E>:T是Entry中key的类型,E是Entry中value的类型
Set<Map.Entry<Integer,String>> entrySet = map.entrySet();
for(Map.Entry<Integer,String> e : entrySet){
System.out.println(e.getKey() + " =========== " + e.getValue());
}
HashTable
- HashTable实现了哈希表,该哈希表将键映射到值,任何非null对象都可以作为键或值
- 实例
//实例化一个HashTable对象
//默认初始容量11个
Map<Integer,String> map = new Hashtable<>();
map.put(1,"Tom");
System.out.println(map.containsKey(1));
- 源代码
public class Hashtable<K,V>{
/**
* The hash table data
* 哈希表的数据
* 定义一个Entry数组来存储键值对
*/
private transient Entry<?,?>[] table;
/**
* The total number of entries in the hash table.
* 哈希表中Entry(键值对)的个数
*/
private transient int count;
/**
* The table is rehashed when its size exceeds this threshold. (The
* value of this field is (int)(capacity * loadFactor).)
* 存储扩容的阈值(阈值根据加载因子进行计算)
* threshold = loadFactor * count
*
* @serial
*/
private int threshold;
/**
* The load factor for the hashtable.
* 加载因子,默认为0.75
*
* @serial
*/
private float loadFactor;
/**
* Constructs a new, empty hashtable with a default initial capacity (11)
* and load factor (0.75).
* 实例化HashTable对象
* HashTable的默认初始容量为11.填充因子为0.75
*/
public Hashtable() {
this(11, 0.75f);
}
}
- 添加元素
public synchronized V put(K key, V value) {
// Make sure the value is not null
//判断值是否为null,如果为null则抛出异常
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
//获取key的哈希值
int hash = key.hashCode();
//计算元素的存储位置
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
//获取指定索引位置的Entry对象
Entry<K,V> entry = (Entry<K,V>)tab[index];
//通过遍历的方式找到元素的位置
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
//以添加的方式添加元素对象到现有集合中
addEntry(hash, key, value, index);
return null;
}
添加元素到哈希表中
private void addEntry(int hash, K key, V value, int index) {
modCount++;
Entry<?,?> tab[] = table;
//判断是否已经达到阈值,如果达到则重新进行哈希计算
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
@SuppressWarnings("unchecked")
//获取指定索引位置的元素
Entry<K,V> e = (Entry<K,V>) tab[index];
//将元素赋值到指定索引位置
tab[index] = new Entry<>(hash, key, value, e);
count++;
}
HashTable和HashMap的区别
- HashMap的初始容量是16;HashTable的初始容量是11
- HashMap是非线程安全的;HashTable是线程安全的
- HashMap的底层是基于链表+数组或树形结构进行实现的;HashTable是基于哈希表进行实现的
- HashMap中的键和值允许出现null值;而HashTable的键和值不允许出现null值
TreeMap
- TreeMap的底层是基于红黑树进行实现的,映射对键按照自然排序的方式进行排序。TreeMap中的元素是有序的。
- 示例
//实例化Map对象
TreeMap<Integer,String> map = new TreeMap<>();
map.put(3,"Rose");
map.put(1,"Tom");
map.put(2,"Jerry");
//遍历集合对象
for(Integer k : map.keySet()){
System.out.println(k + " ==== " +map.get(k));
}
Properties
- 概述:表示一个持久的属性集。可以通过I/O流的方式对存储或读取属性集的数据。Properties实现了Map接口。
- 示例
Properties prop = new Properties();
//常用方法
//1*、load():以流方式读取属性列表
//prop.load();
//2、put():向现有属性集合中添加键值对
prop.put("name","Tom");
prop.put("url","jdbc:mysql://localhost:3306/oadb");
prop.put("user","root");
prop.put(20,"yes");
//3、读取属性值
//3、get():根据key值读取对应的属性值(返回值为Object类型)
System.out.println(prop.get("name"));
//4*、getProperty():根据key值读取对应的属性值(返回值为String类型)
System.out.println(prop.getProperty("name"));
Collections
- 概述:Collections是针对于Collection集合提供的一个工具类,类内包含一组操作集合对象的常用静态方法。
- 常用方法
//创建一个List集合对象
List<String> list = new ArrayList<>(5);
Set<String> set = new HashSet<>();
//向集合中添加元素
list.add("a");
list.add("b");
set.add("a");
//1、fill():使用指定值替换列表中的所有元素(只对List集合有效)
Collections.fill(list,"Tom");
System.out.println(list);
List<String> linkedList = new LinkedList<>();
//linkedList.add("1");
linkedList.add("b");
List<String> list2 = new ArrayList<>(5);
list2.add("1");
//2、copy():将原列表中所有元素复制到目标列表中
//要求:目标列表中元素的个数必须大于或等于原列表中元素的个数
Collections.copy(linkedList,list);
System.out.println(linkedList);
//3、disjoint():返回两个集合中是否具有相同的数据,如果有则返回false,否则返回true
System.out.println(Collections.disjoint(list,linkedList));
//4、emptyList()、emptySet()、emptyMap():返回一个空的集合对象
list = Collections.emptyList();
System.out.println(list.size());