本人最近做了1道题目,颇为疑惑
Given:
11. public class Person {
12. private int name;
13. public Person(String name) {
14. this.name = name;
15. }
16. public boolean equals(Object o) {
17. if( !o instanceof Person ) return false;
18. Person p = (Person) o;
19. return p.name.equals(this.name);
20. }
21. }
Which is true?
A. Compilation fails because the hashCode method is not overridden.
B. A HashSet could contain multiple Person objects with the same
name.
C. All Person objects will have the same hash code because the
hashCode method is not overridden.
D. If a HashSet contains more than one Person object with
name=”Fred”, then removing another Person, also with name=”Fred”,
will remove them all.答案是B但是我不这么认为,我知道的是HashSet和Set一样,是以equals方法来判断元素的唯一性的,也就是对于一个HashSet来说,任何其中的对象彼此调用 equals(Object) 方法都应该返回FALSE,概括来说,就是 相等的对象必须有相同的hashCode码,当然了,逆命题不成立,完全有可能2个对象有相同的hashCode(),但是不是相等对象
本题中:既然选择B,就是说,一个HashSet可以包含多个有相同name的Person对象,但是按照第16行---第20行,这些Person对象彼此调用equals(Object o) ,应该都返回true吧,那么不是和HashSet的唯一性矛盾了??
也许我钻牛角尖了,,希望大家给点意见。谢谢。。
Given:
11. public class Person {
12. private int name;
13. public Person(String name) {
14. this.name = name;
15. }
16. public boolean equals(Object o) {
17. if( !o instanceof Person ) return false;
18. Person p = (Person) o;
19. return p.name.equals(this.name);
20. }
21. }
Which is true?
A. Compilation fails because the hashCode method is not overridden.
B. A HashSet could contain multiple Person objects with the same
name.
C. All Person objects will have the same hash code because the
hashCode method is not overridden.
D. If a HashSet contains more than one Person object with
name=”Fred”, then removing another Person, also with name=”Fred”,
will remove them all.答案是B但是我不这么认为,我知道的是HashSet和Set一样,是以equals方法来判断元素的唯一性的,也就是对于一个HashSet来说,任何其中的对象彼此调用 equals(Object) 方法都应该返回FALSE,概括来说,就是 相等的对象必须有相同的hashCode码,当然了,逆命题不成立,完全有可能2个对象有相同的hashCode(),但是不是相等对象
本题中:既然选择B,就是说,一个HashSet可以包含多个有相同name的Person对象,但是按照第16行---第20行,这些Person对象彼此调用equals(Object o) ,应该都返回true吧,那么不是和HashSet的唯一性矛盾了??
也许我钻牛角尖了,,希望大家给点意见。谢谢。。
解决方案 »
- win7系统,jar不能运行,jdk,jre配好了
- 请教,已知primitive Class,如何求得对应的wrapper Class?
- java项目的开发过程
- Java的String类的对象可以是字符串常量,为什么不可以是字符串变量?
- 判断子进程是不是outOfMemoryError错误
- 关于Integer等包装类(外覆类)的问题
- 为什么不可以在外部创建内部静态类对象啊???
- 一段关于读取文本文件内容的简单代码,请教各位问题出在哪里?
- 关于Locale类型的对象的问题?
- 谁能提供JBULIDER的企业版的下载网站及其注册码,4.0,5.0,6.0都行!!!!!!
- 关于向JTextPane插入gif图片的问题
- 怎么使用UNICODE码呢??
2。HashSet内部使用了 HashMap,put方法是根据hashcode来计算存放位置的,自己想一下hash表的原理吧public V put(K key, V value) {
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;
}
} modCount++;
addEntry(hash, key, value, i);
return null;
}
关于第一点。。我也知道,题目本身就是这样的。这样根本通不过编译。。
关于2:我想,Hash表原理我是明白的。。(PS.高中就学信息学了)可是我还是不知道如何解决这题目,请详细讲解下好么?
*
*/
package com.sun.scjptest;import java.util.*;
/**
* @author super
*
*/
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public boolean equals(Object o) {
if( !(o instanceof Person) ) return false;
Person p = (Person) o;
return p.name.equals(this.name);
}
public static void main(String [] args){
Set<Person> set = new HashSet<Person>();
Person p1= new Person("郭靖");
Person p2= new Person("郭靖");
Person p3= new Person("黄蓉");
Person p4= new Person("郭襄");
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
System.out.println(set.size());
}
}运行结果 4果然,是同一个hashSet可以包含多个同名对象,比如 p1和p2,但是我就是不明白WHY????
因为使用的Object类的hashcode()来计算hash,所以不同的对象得到的hashcode肯定是不会冲突的,因为这个是根据地址来计算的。
这个值不同,放入的位置就不同
。。
ublic class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, SerializableThis class implements the Set interface, backed by a hash table (actually a HashMap instance). It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time. This class permits the null element.This class offers constant time performance for the basic operations (add, remove, contains and size), assuming the hash function disperses the elements properly among the buckets. Iterating over this set requires time proportional to the sum of the HashSet instance's size (the number of elements) plus the "capacity" of the backing HashMap instance (the number of buckets). Thus, it's very important not to set the initial capacity too high (or the load factor too low) if iteration performance is important.
我知道,的确hashCode在Object类的实现是按照比较内存地址来实现的。如果自己不覆盖,那么不同的对象,因为内存地址一定不同,当然是被HASH到不同的位置。。但是,我主要疑惑在于。HashSet首先必须实现Set接口阿,,那么Set的唯一性必须满足吧,但是如果比如我例子中的p1和p2,他们是equal的,但是被同时插入了hashSet中,这个是不是违背了唯一性原则
引用企鹅的程序分析,可以得知Set是根据hashCode()与equals()方法来判断Set中的2个对象时候
相等(需要2个条件都满足)。
我们知道Person p1= new Person("郭靖"); Person p2= new Person("郭靖"); 虽然看起来一样,
不过他们在堆栈中的存储位置肯定不同(因为是不同的对象嘛)而且equals()方法没有覆盖,也只是
Object根类的equals()方法 ,比较引用。
综合上面所说,再看一个程序:
import java.util.*;
class Persion{
private final int id;
public Persion(int id){
this.id=id;
}
public int hashCode(){
return 1;
}
public String toString(){
return super.toString()+id;
}
public boolean equals(Object o){
return true;
}
}
public class qdb{
public static void main(String[] args){
HashSet<Persion> hs1=new HashSet<Persion>();
hs1.add(new Persion(1));
hs1.add(new Persion(2));
System.out.println(hs1);
}
}
应该能明白啦~
我猜想是不是这个原因,,实际上,hashCode是第一道门槛,equals是第2道门槛,也就是说,在将元素添加到Set集合的过程中,是首先调用hashCode来判断,在hashCode返回相同的前提下,才调用equals来判断2个对象是否真实相等。而,我给的这段代码中,(虽然是个考试题故意设置的畸形代码),hashCode是沿用Object版本的,也就是比较内存地址,所以任何2个不同对象直接调用hashCode()方法就已经不相同了,也就是,在第一道门槛这里,运行时已经将他们当作不等对象了。根本无需等到第2道门槛利用equals来验证。打个比方来说,比如比较2个人首先看 名字是否相同,(中国同名的人太多了)【相当于hashCode方法】,在人名相同的前提下才进一步比较其他额外属性,比如爱好,血型,年龄『相当于equals方法』,正常情况下,同样的人和克隆人都能同时满足上述条件,但是,给出2人,只要他们名字不同,就直接认定是不同的人了,
我一开始就说了,这个程序没覆盖hashCode()但是覆盖了equals(),是一种畸形的程序
HashSet是如何判断对象是否唯一呢,还不是这句:
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
2个限制,hashCode()与equals()
你看过代码确定你真知道HashSet是如何确定唯一的么?
当然,对于JAVA 来说,&& 是按照短路运算进行的,如果e.hash ==hash都是false了,那么根本不用看 &&后面的东西,再复杂都没用。。所以,是先判断hashCode是否相同,相同的前提下才看后面的((k = e.key) == key || key.equals(k))
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public boolean equals(Object o) {
if(!(o instanceof Person) ) return false;
Person p = (Person) o;
System.out.println(p);
return p.name.equals(this.name);
}
public static void main(String[] args ){
Person a= new Person("kikalo");
Person b= new Person("kikalo");
Person c=(Person)a;
a.equals(b);
a.equals(c);
}}
感觉是不一样的啊