Map接口——HashMap和Hashtable

本文介绍了 Java 中 Map 接口的基本概念及其主要实现类 HashMap 和 Hashtable 的特性与使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Map 接口—— HashMap Hashtable

作者: zccst

 

 

1.    Map 接口概述

java.util.Map 接口描述了映射结构, Map 接口允许以键集、值集合或键 - 值映射关系集的形式查看某个映射的内容。

Java 自带了各种 Map 类。 这些 Map 类可归为三种类型:

   1. 通用 Map ,用于在应用程序中管理映射,通常在 java.util 程序包中实现

          * HashMap

          * Hashtable

          * Properties

           * LinkedHashMap

          * IdentityHashMap

          * TreeMap

          * WeakHashMap

          * ConcurrentHashMap

   2. 专用 Map ,您通常不必亲自创建此类 Map ,而是通过某些其他类对其进行访问

          * java.util.jar.Attributes

          * javax.print.attribute.standard.PrinterStateReasons

          * java.security.Provider

          * java.awt.RenderingHints

          * javax.swing.UIDefaults

   3. 一个用于帮助实现您自己的 Map 类的抽象类

          * AbstractMap

 

接口中的重要方法如下:

1,  覆盖的方法

equals(Object o)               // 比较指定对象与此 Map 的等价性

hashCode()                     // 返回此 Map 的哈希码

 

2,  Map 更新方法,可以更改 Map 的内容。

put(Object key, Object value)  // 添加键值对,若键已存在,则覆盖旧值。

putAll(Map t)               // 将指定 Map 中的所有映射复制到此 map

remove(Object key)             // Map 中删除与 key 关联的 value

clear()                       // Map 中删除所有映射

 

3,  返回视图的 Map 方法:使用这些方法返回的对象,你可以遍历和删除 Map 的元素。

Set keySet()                // 返回 Map 中所包含键的 Set 视图。

// 删除 Set 中的 key 元素还将删除 Map 中相应的映射(键和值)

Collection values()         // 返回 map 中所包含值的 Collection 视图。

// 删除 Collection 中的 value 元素还将删除 Map 中相应的映射(键和值)

Set entrySet()             // 返回 Map 中所包含映射的 Set 视图(键值对)。

Set 中的每个元素都是一个 Map.Entry 对象,可以使用 getKey() getValue() 方法(还有一个 setValue() 方法)访问 Map.Entry 对象的键元素和值元素

 

关于 Map.Entry 接口

Map entrySet() 方法返回一个实现 Map.Entry 接口的对象集合。集合中每个对象都是底层 Map 中一个特定的键 / 值对。通过这个集合的迭代器,您可以获得每一个条目 ( 唯一获取方式 ) 的键或值并对值进行更改。

(1) Object getKey(): 返回条目的关键字

   (2) Object getValue(): 返回条目的值

   (3) Object setValue(Object value): 将相关映像中的值改为 value ,并且返回旧值

当条目通过迭代器返回后,除非是迭代器自身的 remove() 方法或者迭代器返回的条目的 setValue() 方法,其余对源 Map 外部的修改都会导致此条目集变得无效,同时产生条目行为未定义。

 

4,  Map 访问和测试方法:这些方法检索有关 Map 内容的信息但不更改 Map 内容。

get(Object key)             // 返回与指定键关联的值 及此对象,若无,返回 null

boolean containsKey(Object key)     // 如果 Map 包含指定键的映射,则返回 true

boolean containsValue(Object value)  // 若此 Map 将一个或多个键映射到指定值,返回 true

isEmpty()                // 如果 Map 不包含键 - 值映射,则返回 true

int size()                  // 返回 Map 中的键 - 值映射的数目

 

 

几乎所有通用 Map 都使用哈希映射。 这是一种将元素映射到数组的非常简单的机制,您应了解哈希映射的工作原理,以便充分利用 Map

哈希映射结构由一个存储元素的内部数组组成。 由于内部采用数组存储,因此必然存在一个用于确定任意键访问数组的索引机制。 实际上,该机制需要提供一个小于数组大小的整数索引值(即余数)。 该机制称作哈希函数。 Java 基于哈希的 Map 中,哈希函数将对象转换为一个适合内部数组的整数。 您不必为寻找一个易于使用的哈希函数而大伤脑筋: 每个对象都包含一个返回整数值的 hashCode() 方法。 要将该值映射到数组,只需将其转换为一个正值,然后在将该值除以数组大小后取余数即可。

哈希函数将任意对象映射到一个数组位置,但如果两个不同的键映射到相同的位置,情况将会如何? 这是一种必然发生的情况。 在哈希映射的术语中,这称作冲突。 Map 处理这些冲突的方法是在索引位置处插入一个链接列表,并简单地将元素添加到此链接列表。

 

图示:

 哈希工作原理

 

2.    接口实现类 HashMap

java.util.HashMap 类实现了 java.util.Map 接口。

HashMap 结构不保证其中元素(映射信息)的先后顺序,并且允许使用 null 值和 null 键。当集合中不存在当前检索的键所对应的映射值是, HashMap get() 方法会返回空值 null ,而不会运行出错。

影响 HashMap 性能的两个参数:

1,  初始容量( initial Capacity )。

2,  加载因子( Load Factor

常用方法:

(1) HashMap()               // 构建一个空的哈希映像

   (2) HashMap(Map m)           // 构建一个哈希映像,并且添加映像 m 的所有映射

   (3) HashMap(int initialCapacity)   // 构建一个拥有特定容量的空的哈希映像

   (4) HashMap(int initialCapacity, float loadFactor)  // 构建一个拥有特定容量和加载因子的空的哈希映像

 

例如:

public class Person implements java.lang.Comparable{

       private final int id;

       private String name;

       private int age;

      

       public Person(int id,String name,int age){

              this.id = id;

              this.name = name;

              this.age = age;

       }

       public int getId(){

              return id;

       }

       public void setName(String name){

              this.name = name;

       }

       public String getName(){

              return name;  

       }

       public void setAge(int age){

              this.age = age;

       }

       public int getAge(){

              return age;     

       }

       public String toString(){

              return "Id: " + id + "/tName: " + name + "/tAge: " + age;

       }    

       @Override

       public int compareTo(Object o){

              Person p = (Person)o;

              return this.id - p.id;             

       }

       @Override

       public boolean equals(Object o){

              boolean flag = false;

              if(o instanceof Person){

                     if(this.id == ((Person)o).id)

                            flag = true;

              }

              return false;          

       }    

}

 

import java.util.Set;

import java.util.HashMap;

import java.util.Collection;

import java.util.Iterator;

 

public class TestHashMap{

       public static void main(String[] args) {

              HashMap hm = new HashMap();

              hm.put(new Integer(1003),new Person(1003," 张三 ",15));

              hm.put(new Integer(1008),new Person(1008," 李四 ",25));

              hm.put(1015,new Person(1015," 王五 ",73));   // 自动封装

              hm.put(1001,new Person(1001," 赵六 ",49));

 

              System.out.println("---- 检索单个元素 ----");

              Person p = (Person)hm.get(1008);

              System.out.println(p);

             

              System.out.println("---- 遍历所有 /" /" (元素名) ----");

              Set names = hm.keySet();

              for(Object o : names){

                     System.out.println(o);

              }

             

              System.out.println("---- 遍历所有 /" /" (元素值) ----");

              Collection values = hm.values();

              for(Object o : values){

                     System.out.println(o);

              }

       }

}

输出结果:

---- 检索单个元素 ----

Id: 1008   Name: 李四   Age: 25

---- 遍历所有 " " (元素名) ----

1001

1003

1008

1015

---- 遍历所有 " " (元素值) ----

Id: 1001   Name: 赵六   Age: 49

Id: 1003   Name: 张三   Age: 15

Id: 1008   Name: 李四   Age: 25

Id: 1015   Name: 王五   Age: 73

 

 

3.    接口实现类 Hashtable

java.util.Hashtable HashMap 作用基本相同,也实现了 Map 接口,采用哈希表的方式将“键”映射到相应的值来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

 

Hashtable HashMap 的差别:

1,  Hashtable 中元素的键和值均不允许为 null ,而 HashMap 可以

2,  Hashtable 是同步的,即线程安全的,效率相对要低一些,适合在多线程环境下使用;而 HashMap 是不同步的,效率相对高一些,提倡在单线程环境下使用。

相同点是: Hashtable HashMap 的用法格式是完全相同的。

 

Hashtable 类的使用:

为了把对象保存到哈希表中,必须为每一对象分配一关键字。关键字可以为任意对象,但必须实现了 hashCode() equals() 方法。

Hash_1.put(“one”, new Integer(1));

Hash_1.put(“two”, new Integer(2));

Hash_1.put(“three”, new Integer(3));

把对象从哈希表删除,须使用 remove() 方法。

Hash_1.remove(“two”);  // 对象 Integer(2) 将从哈希表中删除,同时返回这个被删除的对象。如果指定的关键字不存在, remove() 返回 null

使用哈希表类的 get() containKey() 访问方法可以直接查找关键字。

Integer n = (Integer) Hash_1.get(“three”);

If (n != null){System.out.println(“three=” + n);}  // 如果查找的关键字不存在, get 返回 null

 

例如: MyKey.java Person.java TestTreeMap.java

(1)    MyKey.java

public class MyKey implements Comparable{

       private final int id;

       public MyKey(int id){

              this.id = id;    

       }    

       public int getId(){

              return id;

       }

       @Override

       public int compareTo(Object o){

              return this.id - ((MyKey)o).id;            

       }

       @Override

       public boolean equals(Object o){

              return (o instanceof MyKey) && (this.id == ((MyKey)o).id);          

       }

       @Override

       public int hashCode(){

              return new Integer(id).hashCode();      

       }    

}

 

(2)    Person.java

public class Person{

       private String name;

       private int age;

      

       public Person(String name,int age){

              this.name = name;

              this.age = age;

       }

       public void setName(String name){

              this.name = name;

       }

       public String getName(){

              return name;  

       }

       public void setAge(int age){

              this.age = age;

       }

       public int getAge(){

              return age;     

       }

       public String toString(){

              return "Name: " + name + "/tAge: " + age;

       }    

}

 

(3)    TestTreeMap.java

import java.util.Set;

import java.util.TreeMap;

import java.util.Iterator;

 

public class TestTreeMap{

       public static void main(String[] args) {

              TreeMap hm = new TreeMap();

              hm.put(new MyKey(1003),new Person("Tom",15));

              hm.put(new MyKey(1008),new Person("Billy",25));

              hm.put(new MyKey(1005),new Person("Kity",73));  

              hm.put(new MyKey(1001),new Person("Nancy",49));

 

              System.out.println("---- 检索单个元素 ----");

              Person p = (Person)hm.get(new MyKey(1008));

              System.out.println(p);

             

              System.out.println("---- 遍历所有元素 ----");

              Set names = hm.keySet();

              Iterator it = names.iterator();

              while(it.hasNext()){

                     MyKey key = (MyKey)it.next();

                     Person value = (Person)hm.get(key);

                     System.out.println(key.getId() + "/t" + value);

              }

       }

}

 

输出结果:

---- 检索单个元素 ----

Name: Billy   Age: 25

---- 遍历所有元素 ----

1001   Name: Nancy   Age: 49

1003   Name: Tom  Age: 15

1005   Name: Kity Age: 73

1008   Name: Billy   Age: 25

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值