¡Como tú que amas la programación!
Aprenda los cursos prácticos de SpringBoot https://edu.csdn.net/course/detail/31433
Aprenda los cursos de introducción a SpringCloud https://edu.csdn.net/course/detail/31451
Prefacio
Cuando guardamos una gran cantidad de datos, primero pensamos en matrices. Pero la longitud de la matriz es fija y existe un problema si guarda una cantidad indeterminada de datos.
Este artículo lo llevará a comprender la arquitectura del marco de recopilación de Java, comprender la diferencia entre las interfaces List, Set y Map, y centrarse en el uso, la estructura de datos y los principios de implementación de ArrayList, LinkedList, HashSet y HashMap.
Sistema de marco colectivo
Características de la interfaz:
- La interfaz de Colección
define los métodos generales de la colección, tales como: agregar, eliminar, número de colecciones - La interfaz de lista
se puede ordenar y se pueden agregar datos duplicados
No se puede acceder a la interfaz configurada por separado y los datos no se pueden repetir
Pares clave-valor de interfaz de mapa , a los que se accede mediante claves
Los principales métodos de la interfaz de Colección:
método | Introducción |
---|---|
suma booleana (objeto obj) | Agregar un objeto |
boolean addAll (Colección c) | Agregar todos los objetos de otra colección |
booleano eliminar (Objeto obj) | Eliminar un objeto |
boolean removeAll (Colección c) | Eliminar todos los objetos de una colección |
vacío claro () | Eliminar todos los objetos |
int tamaño () | Número de objetos guardados |
booleano contiene (Objeto obj) | Determinar si existe un objeto |
Objeto [] toArray () | Devuelve los objetos de la colección como una matriz |
Interfaz de lista
Puede operar por subíndice, puede agregar datos duplicados, puede ordenar los
métodos principales:
método | Introducción |
---|---|
añadir vacío (índice int, objeto obj) | Agregar un objeto en una ubicación determinada |
Obtener objeto (índice int) | Devolver un objeto en una posición determinada |
Objeto eliminar (índice int) | Eliminar un objeto en una posición determinada |
Conjunto de objetos (índice int, objeto obj) | Reemplazar un objeto en una posición determinada |
Lista subLista (int inicio, int fin) | Interceptar parte de la colección |
int indexOf (Objeto) | Devuelve la posición del objeto en la colección. |
booleano contiene (Objeto obj) | Determinar si existe un objeto |
Clase ArrayList
La clase ArrayList es la clase de implementación de la interfaz List y es una colección que se usa mucho durante el desarrollo.
La estructura de datos de ArrayList es:
matriz unidimensional
Las ventajas y desventajas de ArrayList:
- Ventajas: velocidad de acceso rápida, espacio de almacenamiento continuo, posicionamiento directo a través de subíndices
- Desventajas: rendimiento deficiente de eliminación e inserción, necesidad de mover muchos datos hacia adelante o hacia atrás
Método de creación:
ArrayList arrayList = new ArrayList();
o
ArrayList arrayList = new ArrayList(默认容量);
agregando datos:
add(Object 数据) 添加数据到末尾,参数是Object类型,可以添加任何类型的数据。
add(int 下标,Object 数据) 在特定位置添加数据
addAll(Collection 集合) 添加一个集合中所有数据
cambiar los datos:
set(int 下标,Object 数据) 修改特定位置上数据
Datos de acceso:
get(下标) 返回某个下标上的数据
Numero de datos:
int size() 数据个数
borrar datos:
remove(int 下标) 删除特定位置上的数据
clear() 删除所有数据
Atraviesa la colección:
foreach loop
for(Object obj : list){
System.out.println("集合中的数据:"+obj);
}
Ordinario para bucle
int size = list.size();
for(int i = 0;i < size;i++){
Object obj = list.get(i);
System.out.println("集合中的数据:"+obj);
}
Análisis de código fuente ArrayList:
¿cómo guardar datos? Matriz unidimensional de tipo de objeto
transient Object[] elementData;
¿Cuál es la longitud inicial de la matriz? 10
private static final int DEFAULT_CAPACITY = 10;
¿Cómo se expande ArrayList de forma dinámica? Si el número de datos excede la capacidad original, la capacidad se amplía a 1,5 veces la capacidad original y luego los datos se copian en la nueva matriz.
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //扩容1.5倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
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); //复制数据到新数组中
}
Colección de vectores
La colección Vector es similar a ArrayList:
- Las estructuras de datos son todas matrices unidimensionales
- El método es exactamente el mismo
diferencia:
- ArrayList no es seguro para subprocesos, Vector es seguro para subprocesos
- El rendimiento de ArrayList es mayor
Colección genérica
¿Qué podría estar mal con el siguiente código?
List list = new ArrayList();
list.add(100);
list.add("123");
int n = (int)list.get(1); //存在类型转换的错误
String s = (String)list.get(0); //存在类型转换的错误
Para las colecciones no genéricas, no hay restricción en el tipo de datos agregados Cuando los datos se extraen para la conversión de tipos, existe un problema de incompatibilidad de tipos.
El uso de colecciones genéricas puede resolver este problema.
Método de creación:
ArrayList<类型> arrayList = new ArrayList<类型>();
P.ej:
ArrayList<String> arrayList = new ArrayList<String>();
ArrayList<Integer> arrayList = new ArrayList<Integer>();
后面的类型可以省略
ArrayList<Integer> arrayList = new ArrayList<>();
ventaja:
- Solo se puede agregar un tipo de datos, no es fácil cometer errores
- Sin conversión de tipo, mejora el rendimiento
ArrayList<Person> arrList = new ArrayList<Person>();
arrList.add(new Person("张三",20));
arrList.add(new Person("张大三",21));
arrList.add(new Person("张小三",23));
arrList.add(new Person("张三三",26));
arrList.add(100); //编译错误,不允许添加其他类型
//读取Person对象
Person person = arrList.get(3);
person.hello();
//删除
arrList.remove(0);
//遍历
for(Person per : arrList){
per.hello();
}
Lista enlazada
La estructura de datos de LinkedList es:
lista doblemente enlazada
Las ventajas y desventajas de LinkedList:
- Ventajas: rápida eliminación y velocidad de inserción, solo es necesario modificar los puntos frontal y posterior, no es necesario mover datos
- Desventajas: La velocidad de acceso es lenta, debe ser hacia adelante y hacia atrás a su vez, y la eficiencia es baja.
Método LinkedList
método | Introducción |
---|---|
void addFirst (objeto obj) | Agrega el objeto en la primera posición |
void addLast (Objeto obj) | Agregar un objeto en la última posición |
Objeto removeFirst () | Eliminar el objeto en la primera posición |
Objeto removeLast () | Eliminar el objeto en la última posición |
Objeto getFirst () | Coloca el objeto en la primera posición |
Objeto getLast () | Obtener la última posición del objeto |
empuje vacío (objeto obj) | Apilar, primero en entrar, último en salir |
Objeto emergente () | Fuera de la pila, primero en entrar, último en salir |
Exploración del código fuente de LinkedList
//内部类,保存数据和前后指针
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
Insertar elemento
//在succ节点前,插入新节点
void linkBefore(E e, Node<E> succ) {
final Node<E> pred = succ.prev; //succ前一个节点
//创建新节点,prev指向succ前面节点,next指向succ
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode; //succ的prev指向新节点
if (pred == null)
first = newNode; //前面没有节点,新节点就是首节点
else
pred.next = newNode; //否则succ前面节点的next指向新节点
size++; //数量加1
modCount++;
}
Insertar elemento
//删除x节点
E unlink(Node<E> x) {
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) { //x前面节点的next指向x节点的后面节点
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) { //x后面节点的prev指向x节点的前面节点
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
Establecer interfaz
El conjunto no puede agregar datos duplicados y no se puede acceder a los datos internos por separado
Las clases de implementación de uso común de la interfaz Set son:
- Conjunto desordenado HashSet
- TreeSet ordenará automáticamente el conjunto
- LinkedHashSet puede mantener el conjunto de agregar orden
HashSet
Desordenada, la ubicación de almacenamiento se calcula mediante el algoritmo hash
. Los datos agregados a la colección deben implementar el hashCode y los métodos equals. La
implementación inferior es HashMap, y los datos se almacenan en la clave de HashMap
public class HashSet<E> extends AbstractSet<E>
{
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
...
}
Interfaz de mapa
Datos de acceso a la estructura de pares clave-valor, fáciles de encontrar y eficientes.
Métodos comunes:
método | Introducción |
---|---|
V poner (tecla K, valor V) | Almacenar el par "clave-valor" especificado en el mapa |
V get (clave de objeto) | Devuelve el valor asignado por la clave especificada |
V eliminar (tecla de objeto) | Eliminar este par "clave-valor" del mapa de acuerdo con la clave especificada |
boolean containsKey (clave de objeto) | Determinar si este mapa contiene la clave especificada |
boolean containsValue (valor del objeto) | Determine si este mapa contiene el valor especificado |
boolean isEmpty () | Determinar si hay elementos en este mapa |
int tamaño () | Obtener el número de pares "clave-valor" en el mapa |
vacío claro () | Borrar todos los pares "clave-valor" en el mapa |
Establecer keySet () | Devuelve la colección de claves contenidas en este mapa |
Valores de colección () | Devuelve la colección de valores en este mapa. |
HashMap
El acceso a los datos en forma de tabla hash utiliza muchas colecciones.
Método de creación:
HashMap<键类型,值类型> hashmap = new HashMap<>();
Instrucciones:
//创建HashMap保存人的对象
HashMap<String,Person> map = new HashMap<String,Person>();
Person person1 = new Person("张三",20);
Person person2 = new Person("李四",22);
Person person3 = new Person("王五",20);
//添加人到集合中
map.put(person1.getName(), person1);
map.put(person2.getName(), person2);
map.put(person3.getName(), person3);
//通过键访问值
map.get("张三").hello();
//删除
map.remove("李四");
//添加重复的键,将新的值覆盖原来的值
map.put("李四", new Person("李四",33));
System.out.println("长度:" + map.size());
//遍历所有的键
for(String key : map.keySet()){
System.out.println("键: " + key);
}
//遍历所有的值
for(Person per : map.values()){
per.hello();
}
//遍历所有的键和值
for(String key : map.keySet()){
System.out.println("键: " + key);
map.get(key).hello();
}
Características de HashMap
- Si se agrega una clave duplicada, el valor agregado posteriormente reemplazará el valor anterior.
- Los datos se almacenan en un algoritmo hash, no en el orden de adición
- La clave agregada debe implementar los métodos hashCode y equals
Estructura de datos de HashMap
Matriz unidimensional + lista enlazada individualmente + árbol rojo-negro
Proceso HashMap de guardar datos
- Al agregar datos de pares clave-valor, primero se llama al método hashCode de la clave para calcular el subíndice de matriz
- Si los datos del subíndice están vacíos, guárdelos directamente
- Si hay datos en el subíndice, los iguales de la clave llamada se comparan con la clave en esa posición.
- Si es igual a devuelve verdadero, los datos antiguos se sobrescribirán con los nuevos.
- Si es igual a devuelve falso, coloque los datos nuevos detrás de los datos antiguos para formar una lista vinculada
- Cuando la longitud de la lista vinculada excede 8, se convierte automáticamente en un árbol rojo-negro (optimización de java8)
Análisis de código fuente HashMap
//添加数据
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length; // 获得数组长度
if ((p = tab[i = (n - 1) & hash]) == null) //hashCode对数组长度-1取模获得下标i
tab[i] = newNode(hash, key, value, null); //该位置为空就直接添加数据
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k)))) //不为空就调用equals比较键
e = p; //键相同就赋值给e,后面直接覆盖value
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null); //键不相同就放到后面,形成链表
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash); //链表长度超过8,转换为红黑树
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value; //覆盖旧的value
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
Tabla de picadillo
El uso y la estructura de Hashtable y HashMap son los mismos.
Diferencias:
- HashMap no es seguro para subprocesos, Hashtable es seguro para subprocesos
- HashMap puede agregar claves y valores nulos, Hashtable no puede agregar claves y valores nulos
TreeMap
特点:添加数据后,会自动对键进行排序
数据结构:红黑树
使用时需要注意:
- 键必须实现Comparable接口
- 键如果和已存在的键相等,TreeMap就放弃添加
LinkedHashMap
继承于HashMap,通过额外的链表保留键的添加顺序。
如何选择集合
在开发过程中,需要根据实际业务场景,结合集合的特点选择集合
- 可以排序,可以添加重复数据,可以随机访问 ----- List
- 对数据访问要求高 ----- ArrayList
- 对插入和删除要求高 ----- LinkedList
- 不能添加重复的数据,不需要随机访问 ------ Set
- 没有顺序 ----- HashSet
- 可以进行排序 ----- TreeSet
- 保留添加顺序 ----- LinkedHashSet
- 可以进行快速查找 ,以键值对保存------ Map
- 键没有顺序 ----- HashMap
- 键可以排序 ----- TreeMap
- 键保留添加顺序 ----- LinkedHashMap
结束
集合是Java的重点内容,尤其是ArrayList和HashMap这两个集合应用非常广泛,是否掌握了就通过作业检查了。
- 定义歌曲类,属性:歌曲名、歌手名、播放时长(int 类型),定义play方法显示歌曲信息。
1、添加10首歌到ArrayList集合中
2、遍历所有的歌曲,显示歌曲信息
3、输入歌曲名,在集合中查找该歌曲
4、输入整数索引,删除该位置的歌曲
5、找出播放时间最长的歌曲
6、将所有歌曲复制到LinkedList集合中 - Cambie la colección a HashMap, use el nombre de la canción como clave y la canción como valor.
1. Agregue 10 canciones a la colección.
2. Recorra todas las canciones y muestre la información de la canción.
3. Ingrese el nombre de la canción y busque el canción en la colección.
4. Ingrese el nombre de la canción, elimine la canción
Si necesita aprender otros conocimientos de Java, haga clic aquí Conocimiento ultra detallado de Java Resumen