Comparación de varias formas de juzgar los mismos elementos de Hashmap, Hashset, Treemap y Treeset en Java
1.1 hashmap
Primero echemos un vistazo a cómo se almacenan los elementos en Hashmap. Cada elemento almacenado en el mapa es un par de valores clave como el valor clave, y se agrega a través del método PUT. Además, la misma clave solo tendrá un valor asociado en el mapa. El método Put se define en el mapa de la siguiente manera.
V Put (k key, valor v);
Se utiliza para almacenar un par de valores clave como el valor de la llave. El valor de retorno es el valor antiguo almacenado en el mapa por la clave. Si no existe antes, devolverá nulo. Así es como se implementa el método HashMap Put.
public v put (k key, v value) {if (key == null) return putfornullkey (valor); int hash = hash (clave); int i = indexfor (hash, table.length); para (entrada <k, v> e = table [i]; e! = null; e = e.next) {objeto k; if (e.hash == hash && ((k = e.key) == key || key.equals (k))) {v OldValue = e.Value; e.value = valor; E.RecordAccess (esto); devolver OldValue; }} modcount ++; Addentry (hash, clave, valor, i); regresar nulo; }De lo anterior podemos ver que al agregar la combinación de valor clave correspondiente, si la clave correspondiente ya existe, el valor correspondiente se cambiará directamente y se devolverá el valor anterior. Al juzgar si la clave existe, primero se compara primero el Código de la Clave, y luego el Código hash de la clave se compara con iguales o iguales. Es posible que no podamos verlo aquí. En el código anterior, comparamos el CCODE de MAP.Entry y el HASHCODE de la clave. De hecho, podemos ver que MAP.Entry hashcode es en realidad el hashcode de su clave. Si la clave correspondiente no existe originalmente, se llamará a Addentry para agregar el valor de la clave correspondiente al mapa. El hash de parámetro pasado por Addentry es el Código hash correspondiente a la clave. A continuación, echemos un vistazo a la definición del método de Addentry.
Void Addentry (int hash, k key, v value, int bucketIndex) {if ((size> = umbral) && (null! = table [bucketIndex])) {resize (2 * table.length); hash = (nulo! = clave)? hash (clave): 0; bucketIndex = indexfor (hash, table.length); } createEntry (hash, clave, valor, bucketIndex); } void createEntry (int hash, k key, v valor, int bucketIndex) {Entry <k, v> e = table [bucketIndex]; tabla [bucketIndex] = nueva entrada <> (hash, clave, valor, e); tamaño ++; }El núcleo de Addentry es llamar a CreateEntry para crear un objeto MAP.Entry que representa el valor clave correspondiente y almacenarlo. Obviamente, la tabla anterior es una matriz de map.entry. MAP.Entry utiliza un hash de propiedad para guardar el Código hash de la clave correspondiente. Echemos un vistazo al constructor de map.Entry llamado arriba.
Entrada (int h, k k, v v, entrada <k, v> n) {value = v; siguiente = n; clave = k; hash = h; }Obviamente, guarda el código hash correspondiente a la clave, valor y clave correspondiente.
Después de comprender cómo Hashmap almacena elementos, es más fácil ver cómo el hashmap almacena elementos. Hay dos métodos principales en Hashmap para determinar si los elementos son los mismos. Una es determinar si la clave es la misma, y la otra es determinar si el valor es el mismo. De hecho, al introducir cómo hashmap almacena elementos, hemos introducido cómo hashmap determina si la clave del elemento es la misma. Es decir, en primer lugar, el hashcode es el mismo y, en segundo lugar, las claves son iguales o iguales. La determinación de si la clave es la misma en el mapa se realiza a través del método ContansKey (), y su implementación en HashMap es la siguiente.
public boolean contiene key (clave de objeto) {return getEntry (clave)! = NULL; } Entrada final <k, v> getEntry (clave de objeto) {int hash = (key == null)? 0: hash (clave); para (entrada <k, v> e = table [indexfor (hash, table.length)]; e! = null; e = e.next) {objeto k; if (e.hash == hash && ((k = e.key) == key || (key! = null && key.equals (k)))) return e; } return null; }Es obvio que primero determina si el húsico de la clave es el mismo, y luego determina si la clave es igual o es igual.
El valor utilizado en MAP se juzga por el método ContinSValue, y su implementación en HashMAP es la siguiente.
public boolean ContinsValue (valor de objeto) {if (value == null) return contieneNullValue (); Entrada [] tab = table; for (int i = 0; i <tab.length; i ++) para (entrada e = tab [i]; e! = null; e = e.next) if (valor.equals (e.value)) return true; devolver falso; }Obviamente, el valor de la forma no nula se juzga por los iguales del valor, y la forma nula es tan larga como es igual, es decir, el valor en el elemento guardado es nulo.
1.2 hashset
Después de saber cómo hashmap almacena elementos y determina si los elementos son los mismos, es más fácil ver cómo hashset determina si los elementos son los mismos.
Los elementos en el hashset se guardan en realidad a través de hashmap. Cada objeto hashset contiene una referencia al objeto hashmap correspondiente. Al agregar y eliminar elementos al hashset, se realiza a través del hashmap que tiene. Al guardar un elemento, guardará el elemento correspondiente como la clave del hashmap. El valor correspondiente es un objeto constante, por lo que al guardarlo, utiliza la lógica de determinar si los elementos son los mismos. Al determinar si se incluye un elemento, también llama al método ContinsKey del hashmap celebrado para hacer juicios.
public boolean contiene (objeto o) {returnmap.containskey (o); }Los amigos interesados pueden consultar el código fuente de hashset.
1.3 Treemap
Los elementos almacenados en Treemap se ordenan y clasifican de acuerdo con la clave. Treemap tiene dos formas de ordenar elementos almacenados. Una es clasificar el comparador que posee, y el otro es clasificar la clave que implementa la interfaz comparable. Se prefiere el primer método. Cuando el comparador retenido (el valor predeterminado es nulo) es nulo, se usa el segundo método. Treemap tiene varios constructores, a través de los cuales se puede inicializar el comparador que posee. Primero veamos cómo Treemap guarda elementos. El método PUT se implementa de la siguiente manera.
public v put (k key, V value) {Entry <k, v> t = root; if (t == null) {compare (clave, clave); // escriba (y posible nulo) verifica root = nueva entrada <> (clave, valor, nulo); tamaño = 1; ModCount ++; regresar nulo; } int cmp; Entrada <k, v> padre; // Comparador dividido y comparador comparable Comparador <? Super K> CPR = Comparador; if (cpr! = null) {do {parent = t; CMP = CPR.Compare (Key, T.Key); if (cmp <0) t = t.left; elseif (cmp> 0) t = t.right; else return t.setValue (valor); } while (t! = null); } else {if (key == null) thronewew nullpointerException (); Comparable <? super k> k = (comparable <? Super k>) clave; do {parent = t; cmp = k.compareto (t.key); if (cmp <0) t = t.left; elseif (cmp> 0) t = t.right; else return t.setValue (valor); } while (t! = null); } Entrada <k, v> e = nueva entrada <> (clave, valor, parent); if (cmp <0) parent.left = e; el más parent.right = e; fixafterinsertion (e); tamaño ++; ModCount ++; regresar nulo; }De la implementación anterior podemos ver que el primer elemento se almacenará directamente. Los siguientes elementos se dividen en dos situaciones, uno es el caso en el que el comparador que se mantiene no está vacío, y el otro es el caso donde el comparador está vacío. Cuando el comparador no está vacío, el comparador determinará la ubicación del elemento almacenado. Una cosa importante es que cuando el resultado de comparar la clave del elemento existente con la clave del elemento almacenado actual es 0, se considerará que la clave del elemento almacenado actualmente ya existe en el mapa original, y luego el valor correspondiente a la clave original se cambia al nuevo valor, y luego el valor anterior se devuelve directamente. Cuando el comparador retenido está vacío, la ubicación del elemento se determinará mediante el método Compareto de la clave que implementa la interfaz comparable. Una cosa similar al uso de Comparador es que cuando la clave original se compara con la clave recién almacenada es 0, se considerará que la clave recién almacenada ya existe en el mapa original, y el valor de la clave original correspondiente se cambiará directamente, y el par de valores de clave ya no se almacenará. De hecho, la lógica de implementación principal del método ContinsKey que determina si el elemento existe es similar, y la implementación específica es la siguiente.
public boolean contiene key (clave de objeto) {return getEntry (clave)! = NULL; } Entrada final <k, v> getEntry (clave de objeto) {// Versión basada en comparación de descarga por el bien de rendimiento if (comparator! = null) return getentryusingComparator (clave); if (key == null) thronewew nullpointerException (); Comparable <? super k> k = (comparable <? Super k>) clave; Entrada <k, v> p = raíz; while (p! = null) {int cmp = k.compareto (p.key); if (cmp <0) p = p.left; Elseif (cmp> 0) p = p.right; de lo contrario return p; } return null; }Debido a que la lógica de Treemap para determinar si existe un elemento es determinar si el resultado después de comparar el comparador o comparable es 0, debemos tener particularmente cuidadoso al usar Treemap para implementar alguna lógica similar a los elementos iguales.
La lógica de Treemap contiene el valor es determinar si el valor correspondiente es igual? Similar al hashmap. Los amigos interesados pueden consultar el código fuente de Treemap.
1.4 Treeset
TreeSet también es una implementación de SET. Los elementos almacenados no se repiten y se ordenan. Por defecto, los elementos almacenados deben implementar la interfaz comparable, porque de forma predeterminada, los elementos se compararán como objetos comparables. TreeSet también se puede utilizar para comparar los elementos almacenados en él a través del comparador. Esto se puede lograr pasando en un objeto comparador o un treemap que contiene un objeto comparador al construir un conjunto de árboles. La implementación de TreeSet es similar a la de Hashset. También tiene una referencia a un mapa, pero no se refiere a un hashmap, sino a Treemap. La adición y eliminación de elementos en Treeset son implementados por el Treemap que tienen. Por lo tanto, de manera similar al hashset, la forma de determinar si los elementos en el árbol de árboles son los mismos es consistente con TreemAp, y también se determina a través del comparador o comparable, en lugar del método iguales tradicional. Los amigos interesados pueden consultar el código fuente de Treeset.
Gracias por leer, espero que pueda ayudarte. ¡Gracias por su apoyo para este sitio!