hashmap中的clone为什么是shallow copy of this map

public Object clone() {
        HashMap<K,V> result = null;
try {
    result = (HashMap<K,V>)super.clone();
} catch (CloneNotSupportedException e) {
    // assert false;
}
        result.table = new Entry[table.length];
        result.entrySet = null;
        result.modCount = 0;
        result.size = 0;
        result.init();
        result.putAllForCreate(this);

        return result;
    }
新建Entry,把原来Entry中数据放到新的Entry中。新的HashMap与旧的HashMap操作没有关系了,为什么还是shallow?

回答: hashmap中的clone为什么是shallow copy of this map

  1. javadoc上说得很清楚呀
    引用
        /**
         * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and
         * values themselves are not cloned.

         *
         * @return a shallow copy of this map
         */

hashmap 中的Entry链问题

  1. Q
       引用网上的一段话:引用当程序试图将一个key-value对放入HashMap中时,程序首先根据该 key 的 hashCode() 返回值决定该 Entry 的存储位置:如果两个 Entry 的 key 的 hashCode() 返回值相同,那它们的存储位置相同。如果这两个 Entry 的 key 通过 equals 比较返回 true,新添加 Entry 的 value 将覆盖集合中原有 Entry 的 value,但key不会覆盖。如果这两个 Entry 的 key 通过 equals 比较返回 false,新添加的 Entry 将与集合中原有 Entry 形成 Entry 链,而且新添加的 Entry 位于 Entry 链的头部

    我的疑问是,这段话要怎么理解
    因为当我定义
    map.put(1,"a");
    map.put(1,"b");
    


    此时map的size实际是1,map.get(1)为b也就是说后put的元素把前面的覆盖了。
    所以我想知道的是这个Entry里有多个元素,该怎么理解?
  2. A
    entry应该指的就是键值对吧

HashMap中如何得到keyset的

  1. Q
      看了HashMap的源码后知道是new KeySet(),但是entry中的key是如何被add到这个keyset中的,请大神请教
      public Set<K> keySet() {
            Set<K> ks = keySet;
            return (ks != null ? ks : (keySet = new KeySet()));
        }

        private final class KeySet extends AbstractSet<K> {
            public Iterator<K> iterator() {
                return newKeyIterator();
            }
            public int size() {
                return size;
            }
            public boolean contains(Object o) {
                return containsKey(o);
            }
            public boolean remove(Object o) {
                return HashMap.this.removeEntryForKey(o) != null;
            }
            public void clear() {
                HashMap.this.clear();
            }
        }
  2. A


      KeySet这个类并不是真正意义上的Set集合,它并没有真正实现Set接口的所有函数,只是提供了一个Iterator ,所以他的用处只是用来遍历, 而他的iterator()函数最终却是由KeyIterator来实现,而KeyIterator是对HashMap的HashMapEntry<K, V>[] table来进行迭代遍历的,所以其实说到这看起来 KeySet 本身什么都没做。
      回到开始的一句话 ,KeySet本身不是真正意义上Set集合,不像HashSet有自己的存储变量空间。它的作用主要是用来提供对key的迭代操作。有点像用了代理模式,代理了KeyIterator类 ,当然KeySet也提供了一些其他基本操作,但真正实现都是调用HashMap实现。
      看到这KeySet类就像把对key的操作进行了封装,而具体实现全部由外部实现。
      


    如果我直接就是Set<XXX> set = xxx.keySet();
    那set中有值吗? 
    如果我不调用xxx.keySet().iterator()的情况下

    可能你被KeySet这个名字误导了,他的作用不是用来作为集合存储,而是作为代理来封装对key的操作,这跟是否调用xxx.keySet().iterator()无关,简单来说其实就是个工具类

如何使用struts2的标签迭代出HashMap中的List的记录?

  1. Q
    我Action中有一个HashMap,里面存放的是以ID为key,List为value的数据,请问怎样才能使用struts2的标签迭代出里面的数据?
    我目前是这样写的:
    <s:iterator value="answerHashMap">
           <s:iterator value="<s:property value="subjectId"/>">
                  <s:property value="answerContent"/><br>
           </s:iterator>
    </s:iterator>
    


    weblogic控制台报出异常:
    weblogic.servlet.jsp.JspException: (line 124): Non-matching extension tags //[ null; Line: 124]

    问题补充:
    xuxiaolei (中级程序员):

    我要想区HashMap里面的指定key的value呢?
  2. A
    我要想区HashMap里面的指定key的value呢
    取hashMap指定key的value用hashMap['list']

    然后迭代value值用下面的语句
    <ww:iterator value="hashMap['list']">
        <ww:property /> <BR>
    </ww:iterator>

如何从android手机中把自己的数据库给COPY出来

  1. Q
    自己写个APK,安装在android手机,程序运行时会创建一个SQLITE的数据库;
    用eclipse,可以看到数据库的位置,我把手机插入电脑,打USB连接后,却不能在手机中找到数据库文件(APK绝对是安装在SD卡上的),有人说要有ROOT的权限。不知如何实现,如果要写一个程序来实现,请高手指点思想,列出相关重点函数,谢谢

  2. A
    数据库存储默认路径为/data/data/databases,你在这下面找找;
    改变默认路径:
    final String DATABASE_PATH = Environment.getExternalStorageDirectory() + "/" + "xxx/";
    mDb = SQLiteDatabase.openOrCreateDatabase(DATABASE_PATH + DATABASE_NAME ,null);

从数组中删除重复的元素,并考虑算法的执行效率

  1. Q
    写一个函数来从数组中删除重复的对象。维持秩序。例如,如果输入的数组[ 1,5,4,2,7,2,6,5 ],结果应该是[ 1,5,4,2,7,6 ]。实施时应执行速度的优化。
  2. A
    最快的算法肯定是O(n)
    具体做法是:
    1,准备一个HashMap或者HashTable
    2,循环你的输入数组,判断他是否在HashMap中,如果不是,输出,并且加入到HashMap中(比如:Map.put(1,true)),如果是在HashMap中则什么都不做。

    因为HashMap的读取和设置是O(1)的时间复杂度,所以加上循环整体的时间复杂度也是O(n)

关于Iterator接口的疑问,接口中的抽象方法是何时被实现的

  1. Q
    JDK api文档里面对Iterator定义的是一个接口,里面有几个常用方法。接口我的理解是一个特殊的类,里面的方法都是定义好未实现的抽象方法。但为什么调用HashSet里面的iterator()方法后,返回Iterator对象,就可以使用这个对象里面的方法了。方法不是抽象的么,是什么时候被实现了呢?还是Iterator本身是个接口,又是个实体类(api中没找到是个实体类)?
        这个疑问是在看Map接口中,如何输出Map中的内容时产生的,代码如下:
    Map<String,Integer> map = new HashMap<String,Integer>();
    map.put("张三",4);
    map.put("李四",2);
    map.put("王五",5);
    Set<Map.Entry<String,Integer>> set=map.entrySet();
    Iterator<Map.Entry<String,Integer>> it = set.iterator();
    while (it.hasNext())
      {
    	Map.Entry<String,Integer> m = it.next();
    	System.out.println(m.getKey()+"-->"+m.getValue());
      }
    

    Map.Entry本身是个接口,如何在
    Map.Entry<String,Integer> m = it.next();
    这句代码中得到实体类,且可以调用对象中方法。是否可以理解为如:
    Map m = new HashMap();
    当父类对象指向子类实例,调用跟子类同名方法时,只会调用子类已经实现过的方法。于此一样,it.next()方法返回一个Map.Entry对象实例,然后接口引用指向这个实例,但HashMap是个实体类,Map.Entry是个接口啊。再观察的时候,也发现Iterator也是此种情况。
    小弟肯定是有些关键东西忽略了,或者是理解出现的差错,望各位前辈能指点迷津。
    问题补充:网上搜了下,没找到相关的说明,有个地方说“Map.Entry是一个HashMap类的内部静态类。实现了Map.Entry接口。接受两个模板参数K和V.key和hash一旦在构造函数中被初始化,就不可改变,并且由于有next的存在,Entry可以构成一个单向链表”。如果所有类似Iterator、Map.Entry的接口,在对应实体类方法中返回对应的对象,那么这些疑问都好理解了。求解答
  2. A
    HashSet 等容器内部定义了一个实现 Iterator接口的类,
    iterator方法返回的就是这个 类的实例。

    这个可以在jdk的源码里看到。

购物车中只能添加一个商品,第二次添加就会把第一次给覆盖掉了,怎么办?

  1. Q
    action中的代码如下:
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    import javax.servlet.http.HttpServletRequest;
    import org.apache.struts2.ServletActionContext;
    import org.apache.struts2.interceptor.SessionAware;
    import com.opensymphony.xwork2.ActionSupport;
    import ez.store.pojo.Book;
    import ez.store.pojo.User;
    import ez.store.service.UserService;
    import ez.store.util.CartItem;
    public class OrderCartItemAction extends ActionSupport implements SessionAware{
    	private UserService userService;
    	private Map session;
    	private CartItem ci;
    	
    	public Map getSession() {
    		return session;
    	}
    
    	public void setSession(Map session) {
    		this.session = session;
    	}
    
    	public UserService getUserService() {
    		return userService;
    	}
    
    	public void setUserService(UserService userService) {
    		this.userService = userService;
    	}
    
    	// 用于将商品放到购物车里面
    	public String addBookToCart() {
    		HttpServletRequest request = ServletActionContext.getRequest();
    		Book book = (Book) session.get("book");
    		int score = user.getScore();
    		String bname = book.getBname();
    		double price = book.getPrice();
    		int amount = Integer.parseInt(request.getParameter("amount"));
    		ci=new CartItem();
    		Date date = new Date();
    		Map map = new HashMap();
    		ci.setBname(bname);
    		ci.setPrice(price);
    		ci.setAmount(amount);
    		map.put(date,ci);
    		session.put("list",map);
    		return "success";
    	}
    }
    

    然后就在jp页面接受"list"的值用c:if迭代,但是现在每次只能添加一个商品信息进购物车,且第二次添加的会把第一次添加的给覆盖掉。问题好像是因为每次调用这个action都会重新去new一次,但是就是不知道该如何解决?求指点。
    问题补充:int score = user.getScore();  这个话是多余的
  2. A

    List<CartItem> list = null;
    Object obj =  session.get("list");
    if(obj != null){
        list = (List<CartItem>) obj;
    }else{
        list = new ArrayList<CartItem>();
        session.put("list",list);
    }
    //list.add 商品
    ......

关于HashMap的put问题

  1. Q
    Map map = new HashMap();
    map.put("1",new Object());
    上面是把new出来的一个对象作为“值”放入了map中。

    可是下面的就不理解了:
    Object a = new Object();
    map.put("1",a);
    想问下放入map的到底是new出来的对象的引用(即:a),还是这个对象本身呢?
    求解!多谢!
    问题补充:stormtoy 写道对象的引用地址


    两种方式存储的都是对象的内存地址吗?
    可是我做了一个测试:
      byte a[] = new byte[1024*1024*30];   //大小30M
    然后把a放入了map,整个程序才循环了7次就报内存溢出的错误了。
    如果只是存放的对象的内存地址的话,不应该只能存放7个地址吧&


    问题补充:stormtoy 写道我想是因为你运行程序的jvm内存小于你使用的内存,所以出现内存溢出。你应该区分一下值传递和引用传递,值传递是拷贝一个副本到方法里,你方法里面怎么改不会影响到外边,引用传递传递的时对象的地址,调用方法外和内操纵都是同一份地址,所以这个对象改变了,将会影响到外面(因为你外面那个变量指向了这个对象)。




    那这两种方法到底有没有区别呢?是不是前者存在map里面的是对象,后这存入map的是对象的引用地址?
  2. A
    1.hashMap存储的都是地址:
    
    public class TShashMap {
    	public static void main(String[] args) {
    		Map ts = new HashMap();
    		TSA tsa = new TSA();
    		tsa.setAge(15);
    		tsa.setName("hashMap");
    		ts.put(1, tsa);
    		System.out.println((TSA)ts.get(1));
    		tsa.setAge(18);
    
    		System.out.println((TSA)ts.get(1));
    	}
    }
    class TSA {
    	private String name;
    	private int age;
    	
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String toString() {
    		return "name:" + name + " age:" + age;
    	}
    }
    

    楼主跑下上面的i.e就明白了
    2.你给的i.e,内存溢出是由于java虚拟机本身的原因,和内存没有关系。
    只要存入hashmap中的元素在1<<30之内,就OK

hashmap查找与hashcode

  1. Q
    Map map=new HashMap();
    String s1=new String("AA");
    String s3=new String("AA");
    String s4="AA";
    String s6="AA";
    map.put(s1,"Value");
    String s2=(String)map.get(s3);
    String s5=(String)map.get(s4);
    s1==s3 false   s4==s6 true //这里的==比较的应该不是hashcode吧
    s2,s5都可以得到值Value

    这里以下是查找key是否存在Entry[] table中
    if (key == null)
                return putForNullKey(value);
            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;
                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                    V oldValue = e.value;
                    e.value = value;
                    e.recordAccess(this);
                    return oldValue;
                }
    1: hashcode的API上解释是 将该对象的内部地址转换成一个整数来实现的。这里的内部地址是该对象在堆中的地址还是对象的引用存储在栈中的地址计算出来的?
    2: java中可以输出一个对象在堆中的地址吗?在同一个JVM进程中是否有可能不同的对象的引用输出相同的hashcode呢?
    3:为什么s1,s3,s4的hashcode都是相同的在我机子上是2080。不是说s1,s3的引用是指向堆中的对象的实例吗?s4是方法区中得字符串常量池?这里的hashcode是引用本身存储在栈中的地址呢还是其指向的对象在堆中的地址?
    4 :s1==s3 是比较哪个地址呢?
    5:hashMap中查找key时 int hash = hash(key.hashCode());
    不同的key经过hash()运算是否有可能的到相同的hash呢?
    e.hash == hash && ((k = e.key) == key || key.equals(k))这里一定要比较2个hash值相等吗?为什么
  2. A
    1,当然是对象在堆中的地址,因为引用可有很多,如果是引用的地址的话,那一个对象有多少个引用就有多少个hashcode,显然不对;
    2,对象地址是无法直接获取的,你拿了也没用,但是可以获得任何对象的hashcode,不是对象重载了hashCode()方法以后的,而是原生的:System.identityHashCode(Object x);
      通过System.identityHashCode出来的任何不同的对象的HashCode都是不同的,你通过Object.hashCode()返回的值发现不同的对象这个值相同是因为对象覆写了hashCode()方法。
    3,s1,s2,s3的hashcode相同是因为String类覆写了hashCode()方法,你看看源码就知道String的hahsCode只和String的内容(char[] value)有关,
    另外的解释是:他们相互equals返回true,所以hashCode()也应该相等();
    当然,System.identityHashCode(s1)与System.identityHashCode(s2)就不想等了。
    4,s1==s3比较的是System.identityHashCode(s1)和System.identityHashCode(s3)