map中存储一个普通javabean和存储普通类型

代码如下

        User user=new User();
        user.setAge(24);
        Integer count=new Integer(1);
        String str=new String("I am a boy");
        Map<String, Object> map=new HashMap<>();
        map.put("count",count);
        map.put("str", str);
        count=(Integer) map.get("count");
        count=new Integer(count+1);
        str=(String) map.get("str");
        str="我是一个男孩!";
        map.put("user",user);
        user=(User) map.get("user");
        user.setAge(44);
        System.out.println(map.get("count")+"\t"+map.get("str")+"\t"+user);

输出结果为:
1 I am a boy User [username=null, password=null, age=44]
user的类

 package com.yd.action;

import java.io.Serializable;
import java.util.Map;

import org.apache.struts2.dispatcher.SessionMap;
import org.apache.struts2.interceptor.ApplicationAware;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;

public class User implements Serializable,RequestAware,SessionAware,ApplicationAware{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String username;
    private String password;
    private Integer age;
    private Map<String, Object> request,session,application=null;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public static long getSerialversionuid() {
        return serialVersionUID;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((age == null) ? 0 : age.hashCode());
        result = prime * result + ((password == null) ? 0 : password.hashCode());
        result = prime * result + ((username == null) ? 0 : username.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (age == null) {
            if (other.age != null)
                return false;
        } else if (!age.equals(other.age))
            return false;
        if (password == null) {
            if (other.password != null)
                return false;
        } else if (!password.equals(other.password))
            return false;
        if (username == null) {
            if (other.username != null)
                return false;
        } else if (!username.equals(other.username))
            return false;
        return true;
    }
    @Override
    public String toString() {
        return "User [username=" + username + ", password=" + password + ", age=" + age + "]";
    }
    /*
     * 处理登陆请求的方法
     * */
    public String loginControl(){
        String result="fail";
        if (this.getUsername()==null||this.getPassword()==null||this.getAge()==null) {
            return result;
        }
        if("yd".equals(this.getUsername())&&"a".equals(this.getPassword())){
            //在这个里面代表是登陆成功
            session.put("user", this);
            //如果application中有了count  那么就直接加一
            if(application.get("count")==null){
                application.put("count", 1);
            }else{
                Integer count=(Integer) application.get("count");
                count=count+1;
                application.put("count",count );
            }
            result="success";
        }
        return result;
    }
    /*
     * 处理退出登陆的请求
     * */
    public String loginOut(){
        Integer count=(Integer) application.get("count");
        count=count-1;
        /*
         * ?
         * */
        application.put("count", count);
        SessionMap<String, Object> sessionMap=(SessionMap<String, Object>) session;
        //使得session失效
        sessionMap.invalidate();
        return "success";
    }
    @Override
    public void setApplication(Map<String, Object> application) {
        this.application=application;
    }
    @Override
    public void setSession(Map<String, Object> session) {
        this.session=session;
    }
    @Override
    public void setRequest(Map<String, Object> request) {
        this.request=request;
    }
}

为什么普通类型包装类就需要重新put进入才能改变map里面的值?

你理解错了,count和str都指向了新的对象,并没有改变原值

普通类型指的是String /Integer等等?保持的是值不是对象

1、HashMap的数据结构(HashMap通过hashcode对其内容进行快速查找,是无序的)

数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端。

数组 :数组的存储区是连续的,占用内存严重,故空间复杂度很大。但数组的二分查找时间度小;数组的特点:寻址容易,插入和

删除困难。
链表 :链表的储存区离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度大;链表的特点:寻址困难,插入和删除容易。

哈希表

HashMap是由数组+链表组成;寻址容易,插入和删除容易。(存储单元数组Entry[],数组里面包含链表)

HashMap其实也是由一个线性的数组实现的。所以可以理解为其存储数据的容器就是一个线性容器;

HashMap里面有一个内部静态类Entry,其重要的属性有key,value,next,从属性key,value 就可以很明显的看出来 Entry就是

HashMap键值对实现的一个基础bean;也就是说HashMap的基础就是一个线性数组,这个数组就是Entry[],Map里面的内容都保存

在Entry[]中;
[java] view plain copy

/** 
 * The table, resized as necessary. Length MUST Always be a power of two. 
 */  

transient Entry[] table;  

2、HashMap的存取实现

2.1:存储

这里HashMap用了一个算法。

//存储时候:

int hash=key.hashCode(); //获取key的hashCode,这个值是一个固定的int值

int index=hash%Entry[].length;//获取数组下标:key的hash值对Entry数组长度进行取余
Entry[index]=value;

注意:如果两个key通过hash%Entry[].length得到的index相同,会不会覆盖?

是不会的。Entry类有一个next属性,作用是指向下一个Entry。打个比方, 第一个键值对A进来,通过计算其key的hash得到的

index=0,记做:Entry[0] = A。一会后又进来一个键值对B,通过计算其index也等于0,现在怎么办?HashMap会这样做:B.next =

A,Entry[0] = B,如果又进来C,index也等于0,那么C.next = B,Entry[0] = C;这样我们发现index=0的地方其实存取了A,B,C三个键值对,他

们通过next这个属性链接在一起。所以疑问不用担心。

也就是说Entry[]数组中存储的是最后插入的数据

[java] view plain copy

 public V put(K key, V value) {  
        if (key == null)  
            return putForNullKey(value); //null总是放在数组的第一个链表中  
        int hash = hash(key.hashCode());  
        int i = indexFor(hash, table.length);  
        //遍历链表  
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
            Object k;  
            //如果key在链表中已存在,则替换为新value  
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
                V oldValue = e.value;  
                e.value = value;  
                e.recordAccess(this);  
                return oldValue;  
            }  
        }  
        modCount++;  
        addEntry(hash, key, value, i);  
        return null;  
    }  


void addEntry(int hash, K key, V value, int bucketIndex) {  
    Entry<K,V> e = table[bucketIndex];  
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e); //参数e, 是Entry.next  
    //如果size超过threshold,则扩充table大小。再散列  
    if (size++ >= threshold)  
            resize(2 * table.length);  
}  

2.2:取值

获取key的hashcode指,通过hash值去hash%Entry[].length  获取Entry[hash%Entry[].length],定位到该数组元素之后,再遍历该元

素处的链表。
//取值时候:

int hash=key.hashCode();

int index =hash%Entry[].length;

return Entry[index];

[java] view plain copy

public V get(Object key) {  
    if (key == null)  
        return getForNullKey();  
    int hash = hash(key.hashCode());  
    //先定位到数组元素,再遍历该元素处的链表  
    for (Entry<K,V> e = table[indexFor(hash, table.length)];  
         e != null;  
         e = e.next) {  
        Object k;  
        if (e.hash == hash && ((k = e.key) == key || key.equals(k)))  
            return e.value;  
    }  
    return null;  



  当哈希表的容量超过默认容量时,必须要调整table的大小。当容量达到最大值时,该方法Integer.MAX_VALUE返回,这时,就需要创建

一张表,将原来的表映射到新表中。

3、HashMap、HashTable和ConcurrentHashMap的线程安全问题

HashMap:线程不安全的。
HashTable:锁住整张hash表,让线程独占。hashMap允许为空。通过分析Hashtable就知道,synchronized是针对整张Hash表的,即每次锁住整张表

让线程独占,安全的背后是巨大的浪费。

ConcurrentHashMap:一个更快的hashmap,它提供了好得多的并发性。多个读操作几乎总可以并发地执行。他是锁段(默认:把hash表分为16个

段),在get,put,remove等操作中,ConcurrentHashMap只锁定当前需要用到的段,只有在求size的时候才锁定整张hash表。