Java编程思想(2nd)学习笔记(9)-2

原创 2003年11月06日 00:33:00

一.     HashMap的工作原理及实现

1.    如何实现一个Map

1.1          Map相关的知识

1.1.1             Map.Entry接口

一个实现了Map.Entry接口的类代表的是一个Map中的条目(一个key-value pair)。所以一个Map中必须要有一个实现了Map.Entry接口的类,并用这个类来存放Map中的key-value pair

1.1.2             public abstract Set entrySet()函数

1)     entrySet()函数返回一个Set,并且Set中的每一个元素都是一个Map.Entry类型的对象。在entrySet()函数中要把Map中所有的key-value pairMap.Entry封装后存入Set中的。

2)     当对Map进行修改操作后,entrySet()函数都会被调用。所以对Map的修改也会产生对这个Set的修改。

3)     当用这个Setiterator进行操作时,不能进行addaddAll的操作。

1.2          实现一个简单的Map的实例

import java.util.*;

/**<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 * MPair类实现了Map.Entry

 */

class MPair

    implements Map.Entry, Comparable{

    Object key, value; //keyvalue分别用来存放Map中的keyvalue

    MPair(Object k, Object v){

        key = k;

        value = v;

}

//下面方法实现了Map.Entry接口中的方法

    public Object getKey() { return key; }

    public Object getValue() { return value; }

    public Object setValue(Object v){

        Object result = value;

        value = v;

        return result;

}

//下面方法实现了Comparable接口中的方法

    public boolean equals(Object o){

        return key.equals(((MPair)o).key);

    }

    public int compareTo(Object rv){

        return ((Comparable)key).compareTo(((MPair)rv).key);

    }

}

class SlowMap extends AbstractMap{

    private ArrayList

        keys = new ArrayList(),

        values = new ArrayList();

    public Object put(Object key, Object value){

        Object result = get(key);

        if(!keys.contains(key)){ //1

            keys.add(key);

            values.add(value);

        }

        else

            values.set(keys.indexOf(key), value);

        return result;

    }

    public Object get(Object key){

        if(!keys.contains(key)){

            return null;

        }

        else

            return values.get(keys.indexOf(key));

}

//Mpair封装Map中的key-value pair并存入Set

    public Set entrySet(){

        Set entries = new HashSet();

        Iterator

            ki = keys.iterator(),

            vi = values.iterator();

        while(ki.hasNext())

            entries.add(new MPair(ki.next(), vi.next()));

        return entries;

    }

}

public class ExplicitStatic{       

    public static void main(String[] args){

        SlowMap m = new SlowMap();

        for( int i=1; i<10; i++)

            m.put("km" + i, "m" + i);

        System.out.println(m);       

    }

}

                     在上面代码的(1)处,我们要从ArrayList中查找出是否具有key值,而这个查找过程线性查找,且key不具任何顺序,所以速度会很慢。

1.3          如何对Map用迭代器进行操作

其它容器可以通过iterator()函数来生成对象的迭代器,但Map是不能生成的。如果要用迭代器对Map进行操作,则要通过entrySet()函数。用entrySet()函数生成的迭代器不能对Map进行addaddAll的操作。

   public class ExplicitStatic{       

    public static void main(String[] args){   

        HashMap m = new HashMap();

        for( int i=1; i<10; i++)

            m.put("km" + i, "m" + i);

        System.out.println("User for loop");

        for( int i=1; i<=m.size(); i++ )

            System.out.println("km" + i + " = " + m.get("km" + i));

        System.out.println("User Iterator loop");

        Iterator it = m.entrySet().iterator();

        while(it.hasNext()){

            Map.Entry entry = (Map.Entry)it.next();

            System.out.println(entry.getKey() + " = " + entry.getValue());

        }

    }

}

2.    HashMap相关的几个函数

1)        hashCode()函数

Object.hashCode()函数会为对象产生hash code。如果一个类没有实现hashCode()函数,那么在缺省情况下将返回它的对象的内存地址。

2)        equals()函数

Object.equals()在比较两个对象时,比较的是两个对象的内存地址。

3.    HashMap的工作原理

3.1          array来表现key的信息。每个keyhashCode()函数会为key产生一个hash code,而keyhash  code作为array的索引。如假设有一个名为bucketarrsy,姥一个hash code2key就被索引到bucket[2]key所对应的值也在bucket[2]中。

3.1          由于array中存放的是value值,而HashMap的元素个数可以是无限的,所以array中的元素指向的不是某个keyvalue,而是指向具有相同的hash codekeyvalue值(也就是说指向的是一串values值)。如假设array被定义为LinkedList []bucket = new LinkedList[10],那么bucket[2]中存放的是所有hash code值为2keyvalue

4.    自己实现一个简单的HashMap及其原理

4.1          put()方法中:

1)        首先通过key得出要插入的key-value pairhash code,并这个hash code作为索引在数组bucket中找出key所对应的元素。

2)        把要插入的key-value pair封装成实现了Map.Entry接口的类的一个对象。

3)        在操作1)所找出的数组元素(也是一个LinkedList)中查看是否有与要插入的key-value pairkey相同的元素,如果有,则对之进行更新;如果无,则把要插入的key-value pair数组元素中。

4.2          get()方法中

1)        首先通过key得出要查找的key-value pairhash code,并这个hash code作为索引在数组bucket中找出key所对应的元素。

2)        把要查找的key-value pairkey封装成实现了Map.Entry接口的类的一个对象。

3)        在操作1)所找出的数组元素(也是一个LinkedList)中查看是否有与要插入的key-value pairkey相同的元素,如果有,则返回key所对应的value;如果无,则返回一个null

4.3          一个实例

import java.util.*;

/**

 * MPair类实现了Map.Entry

 */

class MPair

    implements Map.Entry, Comparable{

    Object key, value;

    MPair(Object k, Object v){

        key = k;

        value = v;

    }

    public Object getKey() { return key; }

    public Object getValue() { return value; }

    public Object setValue(Object v){

        Object result = value;

        value = v;

        return result;

}

                         /**

                         * 当比较两个MPair对象时,比较的是它们的key

                         */

    public boolean equals(Object o){

        return key.equals(((MPair)o).key);

    }

    public int compareTo(Object rv){

        return (((Comparable)key).compareTo(((MPair)rv).key));

    }

}

class SimpleHashMap extends AbstractMap{

    private final static int SZ = 997;

    private LinkedList[] bucket = new LinkedList[SZ];

    /**

     * keyvalue封装成Map.Entry的实现类后插入到array

     */

    public Object put(Object key, Object value){

        Object result = null;

        //通过key得到要插入的key-value pairhash code

        int index = key.hashCode() % SZ;

        if(index < 0) index = - index;

        if(bucket[index] == null)

            bucket[index] = new LinkedList();

        //通过hash code找出要插入的key所对应的array中的元素

        LinkedList pairs = bucket[index];

        //把要插入的key-value pair封装成MPair

        MPair pair = new MPair(key, value);

        ListIterator it = pairs.listIterator();

        boolean found = false;

     //检查是否有与要插入的key相同的key存在,如果有,就对之进行更新

        while(it.hasNext()){

            Object iPair = it.next();

            if(iPair.equals(iPair)){

                result = ((MPair)iPair).getValue();

                it.set(pair);

                found = true;

                break;

            }

        }

        //如果无,则把新的key-value pair插入

        if(!found)

            bucket[index].add(pair);

        return result;

    }

    public Object get(Object key){

        int index = key.hashCode() % SZ;

        if(index < 0) index = -index;

        if(bucket[index] == null) return null;

        LinkedList pairs = bucket[index];

        ListIterator it = pairs.listIterator();

        MPair match = new MPair(key, null);

        while(it.hasNext()){

            Object iPair = it.next();

            if(iPair.equals(match))

                return ((MPair)iPair).getValue();               

        }

        return null;

    }

    public Set entrySet(){

        Set entries = new HashSet();

        for(int i=0; i<bucket.length; i++){

            if(bucket[i] == null) continue;

            Iterator it = bucket[i].iterator();

            while(it.hasNext())

                entries.add(it.next());

        }

        return entries;

    }

}

public class ExplicitStatic{       

    public static void main(String[] args){   

        SimpleHashMap m = new SimpleHashMap();

        for( int i=1; i<10; i++)

            m.put("km" + i, "m" + i);

        System.out.println(m);

    }

}

Java编程思想(2nd)学习笔记(9)-3

一.     HashMap的一些其它讨论1.    关于HashMap中的key值的使用1.1.   以Java的库函数做为HashMap的key值时,可以直接使用。import java.util...
  • Nepalon
  • Nepalon
  • 2003年11月06日 00:29
  • 1412

Java编程思想(2nd)学习笔记(9)-1

第2章           持有你的对象一.     容器简介1.         容器的分类1.1.   Collection:一组各自独立的元素,即其内的每个位置仅持有一个元素。1)  List:...
  • Nepalon
  • Nepalon
  • 2003年11月06日 00:33
  • 1372

Java编程思想(2nd)学习笔记(8)-2

二.     Inner classes(内隐类)1.  内隐类的基本用法1)        如果要在外围class的non-static函数之外产生一个inner class对象,得以OuterCl...
  • Nepalon
  • Nepalon
  • 2003年10月28日 23:47
  • 1066

三.操作符——Java编程思想第4版学习笔记

3.1 更简单的打印语句 3.2 使用Java操作符 3.3 优先级 3.4 赋值 对一个对象进行操作时,真正操作的是对对象的引用。所以倘若”将一个对象赋值给另一个对象“,实际上是将”引用“从...
  • rectsuly
  • rectsuly
  • 2017年07月18日 19:38
  • 166

《java编程思想》学习笔记一

第二章 一切都是对象 每个基本类型都有默认值 boolean  false char '\u000'(null) byte  (byte)0 short  0 int 0 long  0L float...
  • LCYong_
  • LCYong_
  • 2017年03月10日 17:53
  • 254

Java编程思想(2nd)学习笔记(6)

第6章           重复运用classes一.继承(inheritance)1.  在derived class中overriding某个函数时,只能覆写base class中的接口,即bas...
  • Nepalon
  • Nepalon
  • 2003年10月24日 17:28
  • 1126

Java编程思想(2nd)学习笔记(2-5)

第2章           万事万物皆对象一.所有对象都必须由你建立1.  存储在哪里1)      寄存器:我们在程序中无法控制2)      stack:存放基本类型的数据和对象的referenc...
  • Nepalon
  • Nepalon
  • 2003年10月20日 10:50
  • 1139

Java编程思想第四版读书笔记——第十三章 字符串

Java编程思想第四版读书笔记——第十三章 字符串 1、不可变String 2、重载“+”与StringBuilder 3、无意识的递归 4、String上的操作 5、格式化的输出...
  • severusyue
  • severusyue
  • 2016年06月30日 20:01
  • 917

《java编程思想》学习笔记(一)

**1. { int x=12; { int x=96;//illegal } } 编译器将会报告变...
  • u013544829
  • u013544829
  • 2016年06月12日 23:58
  • 128

Java编程思想(2nd)学习笔记(7)

第2章           多态一.再探向上转型(upcasting)       将某个object reference视为一个“reference to base type“的动作,称为向上转型。...
  • Nepalon
  • Nepalon
  • 2003年10月24日 17:48
  • 1145
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java编程思想(2nd)学习笔记(9)-2
举报原因:
原因补充:

(最多只允许输入30个字)