hashmap是线程安全的吗的key可以为null吗

JAVA知识(37)
结论:HashMap对象的key、value值均可为null。
& & & & & &HahTable对象的key、value值均不可为null。
且两者的的key值均不能重复,若添加key相同的键值对,后面的value会自动覆盖前面的value,但不会报错。
public class Test {
public static void main(String[] args) {
Map&String, String& map = new HashMap&String, String&();//HashMap对象
Map&String, String& tableMap = new Hashtable&String, String&();//HashTable对象
map.put(null, null);
System.out.println(&hashMap的[key]和[value]均可以为null:& + map.get(null));
tableMap.put(null, &3&);
System.out.println(tableMap.get(null));
} catch (Exception e) {
System.out.println(&【ERROR】:hashTable的[key]不能为null&);
tableMap.put(&3&, null);
System.out.println(tableMap.get(&3&));
} catch (Exception e) {
System.out.println(&【ERROR】:hashTable的[value]不能为null&);
}运行结果:
hashMap的[key]和[value]均可以为null:null
【ERROR】:hashTable的[key]不能为null
【ERROR】:hashTable的[value]不能为null
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6159次
排名:千里之外
原创:59篇
转载:26篇
(6)(32)(4)(1)(2)(10)(4)(3)(11)(10)(5)tianya23 的BLOG
用户名:tianya23
文章数:863
评论数:64
访问量:1956695
注册日期:
阅读量:5863
阅读量:12276
阅读量:416144
阅读量:1103638
51CTO推荐博文
& 在使用map的时候,大家肯定会想到key-value,key用于检索value的内容。在正常情况下,可以不允许重复;但是其实重复在java中分为2中情况,一是内存地址重复,另一个是不同的地址但内容相等,而IdentityHashMap用于后者,即内容相等。 & &更详细的解释如下:此类利用哈希表实现 Map 接口,比较键(和值)时使用引用相等性代替对象相等性。换句话说,在
IdentityHashMap 中,当且仅当 (k1==k2) 时,才认为两个键 k1 和
k2 相等(在正常 Map 实现(如 HashMap)中,当且仅当满足下列条件时才认为两个键
k1 和 k2 相等:(k1==null ? k2==null : e1.equals(e2)))。
此类不是 通用 Map 实现!此类实现 Map 接口时,它有意违反 Map
的常规协定,该协定在比较对象时强制使用 equals 方法。此类设计仅用于其中需要引用相等性语义的罕见情况。
class&Person{&&&&&private&String&name&;&&&&&private&int&age&;&&&&&public&Person(String&name,int&age){&&&&&&&&&this.name&=&name&;&&&&&&&&&this.age&=&age&;&&&&&}&&&&&public&boolean&equals(Object&obj){&&&&&&&&&if(this==obj){&&&&&&&&&&&&&return&true&;&&&&&&&&&}&&&&&&&&&if(!(obj&instanceof&Person)){&&&&&&&&&&&&&return&false&;&&&&&&&&&}&&&&&&&&&Person&p&=&(Person)obj&;&&&&&&&&&if(this.name.equals(p.name)&&this.age==p.age){&&&&&&&&&&&&&return&true&;&&&&&&&&&}else{&&&&&&&&&&&&&return&false&;&&&&&&&&&}&&&&&}&&&&&public&int&hashCode(){&&&&&&&&&return&this.name.hashCode()&*&this.age&;&&&&&}&&&&&public&String&toString(){&&&&&&&&&return&&姓名:&&+&this.name&+&&,年龄:&&+&this.age&;&&&&&}&};&
HashMap情况:
public&class&IdentityHashMapDemo01{&&&&&public&static&void&main(String&args[]){&&&&&&&&&Map&Person,String&&map&=&null&;&&&&&&&&&&map&=&new&HashMap&Person,String&()&;&&&&&&&&&map.put(new&Person(&张三&,30),&zhangsan_1&)&;&&&&&&&&&&map.put(new&Person(&张三&,30),&zhangsan_2&)&;&&&&&&&&&&map.put(new&Person(&李四&,31),&lisi&)&;&&&&&&&&&&&&Set&Map.Entry&Person,String&&&allSet&=&null&;&&&&&&&&&&&&allSet&=&map.entrySet()&;&&&&&&&&&Iterator&Map.Entry&Person,String&&&iter&=&null&;&&&&&&&&&iter&=&allSet.iterator()&;&&&&&&&&&while(iter.hasNext()){&&&&&&&&&&&&&Map.Entry&Person,String&&me&=&iter.next()&;&&&&&&&&&&&&&System.out.println(me.getKey()&+&&&--&&&&+&me.getValue())&;&&&&&&&&&}&&&&&}&};&
结果:相同的key内容,value会被覆盖
姓名:李四,年龄:31&--&lisi&姓名:张三,年龄:30&--&zhangsan_2&
IdentityHashMap情况
public&class&IdentityHashMapDemo02{&&&&&public&static&void&main(String&args[]){&&&&&&&&&Map&Person,String&&map&=&null&;&&&&&&&&&&map&=&new&IdentityHashMap&Person,String&()&;&&&&&&&&&map.put(new&Person(&张三&,30),&zhangsan_1&)&;&&&&&&&&&&map.put(new&Person(&张三&,30),&zhangsan_2&)&;&&&&&&&&&&map.put(new&Person(&李四&,31),&lisi&)&;&&&&&&&&&&&&Set&Map.Entry&Person,String&&&allSet&=&null&;&&&&&&&&&&&&allSet&=&map.entrySet()&;&&&&&&&&&Iterator&Map.Entry&Person,String&&&iter&=&null&;&&&&&&&&&iter&=&allSet.iterator()&;&&&&&&&&&while(iter.hasNext()){&&&&&&&&&&&&&Map.Entry&Person,String&&me&=&iter.next()&;&&&&&&&&&&&&&System.out.println(me.getKey()&+&&&--&&&&+&me.getValue())&;&&&&&&&&&}&&&&&}&};&
结果:相同的key内容(由于是new出来的,内存地址不同但内容相同),但value不会被覆盖
姓名:张三,年龄:30&--&zhangsan_2&姓名:张三,年龄:30&--&zhangsan_1&姓名:李四,年龄:31&--&lisi&
了这篇文章
类别:┆阅读(0)┆评论(0)map containsKey与get方法区别经典总结
前提是:Map可以出现在k与v的映射中,v为null的情况, 所以containsKey出现更加必要
Map集合允许值对象为null,并且没有个数限制,所以当get()方法的返回值为null时,可能有两种情况,一种是在集合中没有该键对象,另一种是该键对象没有映射任何值对象,即值对象为null。因此,在Map集合中不应该利用get()方法来判断是否存在某个键,而应该利用containsKey()方法来判断,例如下面的例子。
下面的代码首先创建一个由HashMap类实现的Map集合,并依次向Map集合中添加一个值对象为null和&马先生&的映射;然后分别通过get()和containsKey()方法执行这两个键对象;最后执行一个不存在的键对象。关键代码如下:
src\com\mwq\TestCollection.java关键代码:
public static void main(String[] args) {
Map&Integer, String& map = new HashMap&Integer, String&();
map.put(220180, null);
map.put(220181, &马先生&);
System.out.println(&get()方法的返回结果:&);
System.out.print(&------ & + map.get(220180));
System.out.print(&&&& & + map.get(220181));
System.out.println(&&&& & + map.get(220182));
System.out.println(&containsKey()方法的返回结果:&);
System.out.print(&------ & + map.containsKey(220180));
System.out.print(&&&& & + map.containsKey(220181));
System.out.println(&&&& & + map.containsKey(220182));
src\com\mwq\TestCollection.java完整代码:
package com.
import java.util.HashM
import java.util.M
public class TestCollection {
public static void main(String[] args) {
System.out.println(&开始:&);
Map&Integer, String& map = new HashMap&Integer, String&();
map.put(220180, null);
map.put(220181, &马先生&);
System.out.println(&get()方法的返回结果:&);
System.out.print(&------ & + map.get(220180));
System.out.print(&&&& & + map.get(220181));
System.out.println(&&&& & + map.get(220182));
System.out.println(&containsKey()方法的返回结果:&);
System.out.print(&------ & + map.containsKey(220180));
System.out.print(&&&& & + map.containsKey(220181));
System.out.println(&&&& & + map.containsKey(220182));
System.out.println(&结束!&)
执行上面的代码,在控制台将输出如下信息:
get()方法的返回结果:
------ null&&& 马先生&&& null
containsKey()方法的返回结果:
------ true&&& true&&&&& false3042人阅读
Java(40)
在HashMap中添加key==null的Entry时会调用putForNullKey方法
下面是HashMap的put方法:
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry&K,V& e = table[i]; e != e = e.next) {
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.
e.recordAccess(this);
return oldV
modCount++;
addEntry(hash, key, value, i);
}当key==null时就会调用putForNullKey方法
下面是putForNullKey的源码:
private V putForNullKey(V value) {
for (Entry&K,V& e = table[0]; e != e = e.next) {
if (e.key == null) {
V oldValue = e.
e.recordAccess(this);
return oldV
modCount++;
addEntry(0, null, value, 0);
}直接去遍历table[0]Entry链表,寻找e.key==null的Entry或者没有找到遍历结束
如果找到了e.key==null,就保存null值对应的原值oldValue,然后覆盖原值,并返回oldValue
如果在table[0]Entry链表中没有找到就调用addEntry方法添加一个key为null的Entry
下面是addEntry的源码:
void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size &= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
createEntry(hash, key, value, bucketIndex);
}这个方法首先判断是否要扩容,当现在hashmap中的Entry数大于等于扩容临界值(capacity*load factor)并且index对应的地方没有Entry就扩容
hashmap每次扩容的大小为2倍原容量,默认容量为16,hashmap的capacity会一直是2的整数幂。
下面是resize扩容源码:
void resize(int newCapacity) {
Entry[] oldTable =
int oldCapacity = oldTable.
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
Entry[] newTable = new Entry[newCapacity];
transfer(newTable, initHashSeedAsNeeded(newCapacity));
table = newT
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
关键是空表扩容后的拷贝到新表的方法transfer方法,下面是源码:
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.
for (Entry&K,V& e : table) {
while(null != e) {
Entry&K,V& next = e.
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] =
遍历原表table ,从table[0]开始,e=table[0],不为null就创建一个临时Entry next引用e.的下一个Entry,然后把e放到新表中,头插到table[i]中,i由indexFor方法决定i(h&newCapacity),然后让e=next,继续遍历拷贝。
扩容之后继续插入要插入的Entry,这个时候就要重新hash了,因为旧表已经扩容了,若果key为nul任然是0。
然后进行真正的插入,调用& createEntry(hash, key, value, bucketIndex),下面是源码:
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry&K,V& e = table[bucketIndex];
table[bucketIndex] = new Entry&&(hash, key, value, e);
}进行头插,创建一个新的entry,new Entry&&(hash,key,value,e)
* Creates new entry.
Entry(int h, K k, V v, Entry&K,V& n) {
新的entry复制到table[bucketIndex],并next引用原来的table[bucketIndex],完成。
在这里key是null,所以bucketIndex=0,现在的table[0]就是null key Entry。
如果不需要进行扩容,直接在table[0]进行头插就可以了。
上面分析了null key的插入过程,其实也包括了所有键值插入的过程。
1.先在table[0]的链表中寻找null key,如果有null key就直接覆盖原来的value,返回原来的value;
2.如果在table[0]中没有找到,就进行头插,但是要先判断是否要扩容,需要就扩容,然后进行头插,此时table[0]就是新插入的null key Entry了。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:90013次
积分:1915
积分:1915
排名:第18670名
原创:79篇
转载:175篇
评论:14条
(1)(10)(5)(4)(4)(7)(1)(3)(14)(34)(63)(45)(9)(45)(6)(1)(3)

我要回帖

更多关于 oracle随机取n条数据 的文章

 

随机推荐