Primero, la estructura de la clase de implementación del Mapa
Mapa: datos de doble columna, almacenamiento de datos con pares clave-valor
1. HashMap: como la principal clase de implementación de Map, el subproceso es inseguro, de alta eficiencia y almacena la clave y el valor nulos
2. LinkedHashMap: para garantizar que al atravesar el elemento del mapa, la
razón transversal se pueda implementar en el orden de adición : en la parte inferior de HashMap Sobre la base de la estructura anterior, se agregan un par de punteros para señalar el elemento anterior y el siguiente elemento. Para las operaciones transversales frecuentes, la eficiencia de este tipo de ejecución es mayor que HashMap
3. TreeMap: asegúrese de que los pares clave-valor agregados estén ordenados para lograr la clasificación Atravesar. De acuerdo con la clasificación natural o personalizada de las claves, la parte inferior utiliza árboles rojos y negros Características: ordenada, alta eficiencia de consulta
4. Hashtable: existía en la era jdk1.0, seguridad de subprocesos, baja eficiencia, no puede almacenar claves nulas y valor
5 Propiedades: una subclase de Hashtable, comúnmente utilizada para procesar archivos de configuración. Tanto la clave como el valor son
la capa inferior del tipo de cadena HashMap: matriz + lista vinculada (jdk7) // matriz + lista vinculada + árbol negro rojo (jdk8)
En segundo lugar, la comprensión de la estructura del mapa (HashMap)
1. La clave en el mapa: no ordenada, no repetible, use set para almacenar todas las claves-> la clase donde se encuentra la clave debe anular equals () y hashCode ()
2. El valor en el mapa: no ordenado, puede Repita, use la colección para almacenar todos los valores -----------> la clase donde se va a reescribir el valor es igual a ()
3, un par clave-valor: clave-valor constituye un objeto de entrada (entrada en Mapa : Desordenado, no repetible, use set para almacenar todas las entradas)
3. ¿El principio de implementación subyacente de HashMap? Tome jdk7 como ejemplo:
HashMap map = new HashMap ();
Después de la creación de instancias, la capa inferior crea una tabla de entrada de matriz unidimensional [] de longitud 16.
... Para realizar múltiples métodos de venta ...
map.put (clave, valor);
Primero, llame al hashCode () de la clase donde se encuentra la clave para calcular el valor hash de la clave. Después de cierto algoritmo, el valor hash se almacena en la matriz de entrada.
Si los datos en esta ubicación están vacíos, el valor-clave se agrega con éxito. - Éxito 1
Si los datos en esta ubicación no están vacíos (existe uno o más datos en esta ubicación y existe en forma de una lista vinculada), compare el valor hash de la clave y el uno o más datos existentes:
Si el valor hash de la clave es diferente del valor hash de los datos existentes, entonces el valor clave se agrega con éxito 2
Si el valor hash de la clave es el mismo que el valor hash de uno de los datos existentes (clave1-valor1), continúe comparando: llame al método igual (clave1) de la clase donde se encuentra la clave
para la comparación:
si devuelve falso: el valor clave se agrega en este momento Éxito - Éxito 3
Si devuelve verdadero: reemplace valor1 con la misma clave1 con valor
2 y 3: en este momento, el valor clave y los datos originales se almacenan en forma de una lista vinculada.
En el proceso de adición continua, la expansión de la capacidad estará involucrada. Cuando se excede el valor crítico y la posición actual no está vacía, el método predeterminado de expansión de la capacidad es duplicar la capacidad original y copiar los datos originales.
Jdk8 y jdk7 son diferentes en la implementación de la capa inferior:
1. new HashMap (): la capa inferior no crea una matriz de longitud 16.
2. Cuando la matriz en la parte inferior de jdk8 es Nodo [], ya no es Entrada [] (Nodo <K, V> [] table;)
3. Cuando se llama al método put por primera vez, la capa inferior crea una matriz de 16
put V pública ( K key, V value) {
// Llame a hash para crear un array
return putVal (hash (key), key, value, false, true);
}
4. La estructura subyacente de jdk7 es: array + lista vinculada jdk8 La estructura subyacente: array + Lista vinculada + árbol rojo-negro
4.1. Al formar una lista vinculada, vaya hacia arriba y hacia abajo (jdk7: el nuevo elemento apunta al elemento anterior jdk8: el elemento antiguo apunta al nuevo elemento)
4.2. Cuando el elemento en una determinada posición de índice de la matriz es una lista vinculada Cuando el número de formularios existe> 8 y la longitud de la matriz actual es> 64,
todos los datos en la posición de índice ahora se almacenan utilizando árboles rojos y negros. (Alta eficiencia, el árbol binario se puede buscar por la mitad)
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
static final int TREEIFY_THRESHOLD = 8
// Se muestra que el código fuente subyacente se expande cuando es menor que 64, y se almacena como un árbol rojo-negro cuando es mayor que 64
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
resize();
static final int MIN_TREEIFY_CAPACITY = 64
4.3 Las constantes principales del código fuente en la capa inferior de
HashMap : DEFAULT_INITIAL_CAPACITY: la capacidad predeterminada de HashMap: 16
DEFAULT_LOAD_FACTOR: el factor de carga predeterminado de HashMap: 0.75
umbral: el valor crítico de expansión = factor de capacidad de llenado: 16 0.75 => 12
TREETFY_THRESHOLD: la longitud de la lista es mayor que la longitud del bucket Cambie el valor predeterminado a árbol rojo-negro: 8
MIN_TREEIFY_CAPACITY: La capacidad mínima de la tabla hash cuando se activa el nodo en el cubo: 64
Cuarto, el principio de implementación subyacente de LinkedHashMap (subclase de HashMap)
La estructura subyacente de LinkedHashMap es la misma que HashMap, porque LinkedHashMap hereda de HashMap, la diferencia es: LinkedHashMap proporciona un objeto de entrada en el interior, reemplaza Node en HashMap
源码:
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;//可以记录添加元素的先后顺序
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
5. Los métodos definidos en el Mapa:
Agregar, eliminar, modificar operaciones
Poner objeto (clave de objeto, valor de objeto): agrega (o modifica) el valor clave especificado al objeto de mapa actual
void putAll (Mapa m): almacena todos los pares clave-valor en m
Object remove (Object key) en el mapa actual : elimina el par clave-valor especificado y devuelve el valor
void clear (): borra todos los datos en el mapa actual
Operaciones de consulta de elementos:
Object get (Object object): obtiene el valor correspondiente a la clave especificada
boolean usesKey (Object key): si contiene la clave especificada
boolean usesValue (Object value): si contiene el valor especificado
int size (): vuelve al mapa El número de pares clave-valor
boolean isEmpty (): determina si el mapa actual está vacío
boolean igual (Object obj): determina si el mapa actual y el objeto de parámetro obj son iguales
El método de la operación de vista meta
Set keySet (): devuelve todos los
valores de la colección de conjuntos de claves (): devuelve todo el conjunto de valores de la colección
Set entrySet (): devuelve todos los pares clave-valor Set set
public class MapTest {
//LinkedHashMap:有序,不可重复
@Test
public void test1(){
Map map = new LinkedHashMap();
map.put(123,"AA");
map.put(123,"AA");
map.put(456,"BB");
map.put(789,"CC");
map.put(147,"DD");
System.out.println(map);
}
@Test
public void test(){
Map map = new HashMap();
// map = new Hashtable();//java.lang.NullPointerException,不能存储null的key和value
map.put(null,null);
}
//map方法--- 添加、删除、修改操作
@Test
public void test2(){
Map map = new HashMap();
//添加
map.put("AA",123);
map.put(25,123);
map.put("AA","BB");//修改覆盖
map.put(123,"BB");
System.out.println(map);//{AA=BB, 25=123, 123=BB}
Map map1 = new HashMap();
map1.put("CC",123);
map1.put("DD",123);
map.putAll(map1);//{AA=BB, CC=123, DD=123, 25=123, 123=BB}
System.out.println(map);
//删除
Object value = map.remove("CC");
System.out.println(value);//123
System.out.println(map);//{AA=BB, DD=123, 25=123, 123=BB}
//clear()
map.clear();//map = {}
System.out.println(map.size());//0
}
//元素查询的操作
@Test
public void test3(){
Map map = new HashMap();
//添加
map.put("AA",123);
map.put(25,123);
map.put("AA","BB");//修改覆盖
map.put(123,"BB");
System.out.println(map.get(25));//1233,不存在为null
boolean isExist = map.containsKey("BB");
System.out.println(isExist);//false
boolean isFlag = map.containsValue(123);
System.out.println(isFlag);//true
map.clear();
Map ma1 = new HashMap();
//添加
ma1.put("AA",123);
ma1.put(25,123);
ma1.put("AA","BB");//修改覆盖
ma1.put(123,"BB");
Map ma2 = new HashMap();
//添加
ma2.put("AA",123);
ma2.put(25,123);
ma2.put("AA","BB");//修改覆盖
ma2.put(123,"BB");
System.out.println(map.isEmpty());//true
System.out.println(ma1.equals(ma2));//true
}
@Test
public void test5(){
// 元视图操作的方法
Map map = new HashMap();
//添加
map.put("AA",123);
map.put(25,123);
map.put("AA","BB");//修改覆盖
map.put(123,"BB");
//遍历所有的key集合,keySet()
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//遍历所有的value集合:values
Collection values = map.values();
for (Object obj :values){
System.out.println(obj);
}
//遍历所有的key-value
//方式一、entrySet()
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while (iterator1.hasNext()){
Object obj = iterator1.next();
//entrySet集合中的元素都是entry
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() +"-------------->"+entry.getValue());
}
//方式二、
Set keySet = map.keySet();
Iterator iterator2 =keySet.iterator();
while (iterator2.hasNext()){
Object key = iterator2.next();
//entrySet集合中的元素都是entry
Object value = map.get(key);
System.out.println(key +"-------------->"+ value);
}
}
Seis, el uso de TreeMap
Agregue clave-valor a TreeMap, la clave debe ser un objeto creado por la misma clase, porque debe clasificarse de acuerdo con la clave: clasificación natural, clasificación personalizada
Primero, personalice una clase de Persona para la prueba de datos
public class Person implements Comparable {
public String name;
public int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//重写equals()方法,比较判断contains()中的比较问题
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (age != person.age) return false;
return name != null ? name.equals(person.name) : person.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
//按照姓名从小到大排列,年龄从小到大排序
@Override
public int compareTo(Object o) {
if (o instanceof Person){
Person person = (Person)o;
// return this.name.compareTo(person.name);
int compare = this.name.compareTo(person.name);
if (compare !=0){
return compare;
}else {
return Integer.compare(this.age,person.age);
}
}else {
throw new RuntimeException("输入的类型不匹配!");
}
}
}
Ordenamiento natural
@Test
public void test(){
TreeMap map = new TreeMap();
Person p1 = new Person("Tom",12);
Person p2 = new Person("Jerry",45);
Person p3 = new Person("Jack",32);
Person p4 = new Person("Rose",18);
Person p5 = new Person("Tm",12);
map.put(p1,88);
map.put(p2,88);
map.put(p3,88);
map.put(p4,88);
map.put(p5,88);
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while (iterator1.hasNext()){
Object obj = iterator1.next();
//entrySet集合中的元素都是entry
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() +"-------------->"+entry.getValue());
}
}
Clasificación personalizada
@Test
public void test2(){
TreeMap map = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Person && o2 instanceof Person){
Person p1 = (Person)o1;
Person p2 = (Person)o2;
return Integer.compare(p1.getAge(),p2.getAge());
}
throw new RuntimeException("输入的类型不一致!");
}
});
Person p1 = new Person("Tom",12);
Person p2 = new Person("Jerry",45);
Person p3 = new Person("Jack",32);
Person p4 = new Person("Rose",18);
Person p5 = new Person("Tm",12);
map.put(p1,88);
map.put(p2,88);
map.put(p3,88);
map.put(p4,88);
map.put(p5,88);
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while (iterator1.hasNext()){
Object obj = iterator1.next();
//entrySet集合中的元素都是entry
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() +"-------------->"+entry.getValue());
}
}
7. Propiedades: una subclase de Hashtable, comúnmente utilizada para procesar archivos de configuración. clave y valor son de tipo String
public static void main(String[] args) throws Exception{
Properties prop = new Properties();
FileInputStream stream = new FileInputStream("jdbc.properties");
prop.load(stream);//加载流对应的文件
String name = prop.getProperty("name");
String pwd = prop.getProperty("pwd");
System.out.println("name = "+ name + ",pwd = " + pwd);
stream.close();
}
Preguntas de la entrevista:
1. El principio de implementación subyacente de
HashMap 2. ¿Las similitudes y diferencias entre HashMap y Hashtable?