在复合对象的 HashMap 中找不到键
因此,我在 Java 中使用 3 个成员创建了自己的复合键
public class MyOwnKey{
int location;
int length;
String [] tokens;
}
现在我使用构造函数创建了两个对象
String [] tokens = "Stackoverflow is great".split("\\s+");
Object key1 = new MyOwnKey(0,0,tokens)
tokens = "Web is great".split("\\s+");
Object key2 = new MyOwnKey(0,0,tokens)
现在,我将键添加到 HashMap 中 HashMap 映射 = new HashMap(); 映射.put(key1,1);
现在,这就是问题所在 当我包含 key 时,它给出 false;
**map.containsKey(key2) //returns false whereas it should return true.**
这样才有意义:
key1.equals(key2) returns true
并且 hashcode 代码也是相等的。 key1.hashCode() == key2.hashCode()。
我已经实现了我自己版本的 hashCode、toEquals() 和 toCompare()。
不确定是什么问题。
这是代码
import java.io.DataOutput;
import java.io.DataInput;
import java.io.IOException;
import org.apache.hadoop.io.WritableComparable;
public class PatternGeneratorKey implements WritableComparable<Object> {
private String [] tokens;
int location;
int length;
StringBuffer _toString = null;
public PatternGeneratorKey(){
tokens = new String[1];
location =0;
length=1;
}
public PatternGeneratorKey(int location, int length, String [] tokens){
this.location = location;
this.length = length;
this.tokens= new String[tokens.length];
for(int i = 0; i < tokens.length;i++){
this.tokens[i] = tokens[i];
}
}
public int compareTo(Object o) {
if (!(o instanceof PatternGeneratorKey))
return -1;
return this.compareTo((PatternGeneratorKey) o);
}
public void write(DataOutput out) throws IOException {
out.writeInt(tokens.length);
for(int i = 0; i<tokens.length;i++){
out.writeUTF(tokens[i]);
}
out.writeInt(location);
out.writeInt(length);
}
public void readFields(DataInput in) throws IOException {
int l = in.readInt();
tokens = new String[l];
for(int i = 0; i < l ; i++){
tokens[i] = in.readUTF();
}
location = in.readInt();
length = in.readInt();
}
public int compareTo(PatternGeneratorKey k) {
if(this.tokens.length - this.length != k.tokens.length - k.length){
return this.tokens.length - this.length -( k.tokens.length - k.length);
}
if(this.location != k.location){
return this.location - k.location;
}
int i = 0 , j= 0;
for(i = 0, j=0 ; i < this.tokens.length && j < k.tokens.length;){
if(i == this.location ){
i = i + length;
continue;
}
if( j == k.location){
j = j + k.length;
continue;
}
if(!this.tokens[i].equalsIgnoreCase(k.tokens[j])){
return this.tokens[i].compareTo(k.tokens[j]);
}else{
i++;
j++;
}
}
//TODO: add comparison on left out phrase
return 0;
}
public int hashCode() {
int hashCode=0;
for(int i = 0; i < tokens.length;){
if(i == location ){
i = i + length;
continue;
}
hashCode += tokens[i++].hashCode();
}
hashCode+= location + tokens.length;
return hashCode;
}
public String toString(){
if(_toString == null){
_toString = new StringBuffer();
for(int k = 0; k < tokens.length ;k++){
if(k==location){
_toString.append(":").append(" ");
k=k+length-1;
}else{
_toString.append(tokens[k]).append(" ");
}
}
}
return _toString.toString();
}
public boolean equals(PatternGeneratorKey k) {
if(this.tokens.length - this.length == k.tokens.length - k.length
&& this.location == k.location){
//assume second one is larger
String tokens[] = k.tokens;
int length = k.length;
int location = k.location;
String [] tokens1 = this.tokens;
int length1 = this.length;
int location1 = this.location;
//make the local variable point to the largest of the two
if( this.tokens.length > k.tokens.length){
tokens = this.tokens;
length = this.length;
location = this.location;
tokens1 = k.tokens;
length1 = k.length;
location1 = k.location;
}
int i = 0 , j= 0;
for(i = 0, j=0 ; i < tokens.length;){
if(i == location ){
i = i + length;
continue;
}
// if( j >= location1 && j<= location1 + length1 -1){
if( j == location1){
j = j + length1;
continue;
}
if(!tokens[i++].equalsIgnoreCase(tokens1[j++])){
return false;
}
}
return true;
}else{
return false;
}
}
}
这是我正在测试的代码
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.hadoop.io.Text;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String value = "gm used cars";
// Compile all the words using regex
String[] tokens = value.toString().split("\\s+");
//to find pattern we need atleast two words in the query
if(tokens.length <=1){
return;
}
Map<PatternGeneratorKey,List> map = new HashMap<PatternGeneratorKey, List>();
for(int l = 1 ; l < tokens.length; l++){
for(int i = 0 ; i < tokens.length - (l-1); i++){
String hit = new String(getPhrase(l, i, tokens));
PatternGeneratorKey key1 = new PatternGeneratorKey(i, l, tokens);
List list = null;
for(int k = 0;k< tokens.length;k++){
System.out.println("i:" + i + ",l:" + l + ",tokens:" + tokens[k]);
}
System.out.println("hashcode:" + key1.hashCode());
if(!map.containsKey(key1)){
list = new ArrayList<String>();
map.put(key1, list);
}else{
list = (List) map.get(key1);
}
list.add(hit);
}
}
value = "ford used cars";
String[] tokens2= value.toString().split("\\s+");
PatternGeneratorKey key2 = new PatternGeneratorKey(0, 1, tokens);
//run a sliding window for length 1 to tokens length -1
for(int l = 1 ; l < tokens2.length; l++){
//genereate token pairs with sliding window.
for(int i = 0 ; i < tokens2.length - (l-1); i++){
//hit a single token or a + b if there are two.
String hit = new String(getPhrase(l, i, tokens2));
PatternGeneratorKey key1 = new PatternGeneratorKey(i, l, tokens2);
System.out.println();
System.out.println(key1.toString() + "|" + key2.toString() + "|"+ key1.equals(key2));
for(int k = 0;k< tokens2.length;k++){
System.out.println("i:" + i + ",l:" + l + ",tokens:" + tokens2[k]);
}
System.out.println("hashcode:" + key1.hashCode());
List list = null;
if(!map.containsKey(key1)){
list = new ArrayList<String>();
map.put(key1, list);
}else{
list = (List) map.get(key1);
}
list.add(hit);
}
}
value = "ford used cars";
tokens= value.toString().split("\\s+");
PatternGeneratorKey key1 = new PatternGeneratorKey(0,1,tokens);
tokens2 = "gm used cars".split("\\s+");
key2 = new PatternGeneratorKey(0,1,tokens2);
System.out.println(key1.equals(key2));
System.out.println(key2.equals(key1));
System.out.println(key1.hashCode() );
System.out.println(key2.hashCode() );
System.out.println(map);
}
private static String getPhrase(int l, int i, String[] tokens){
StringBuffer strin = new StringBuffer();
int index = 0;
for(index = i ; index < i+l;index++){
if(index < i+l-1){
strin.append(tokens[index]).append("+");
}
else
{
strin.append(tokens[index]);
}
}
return strin.toString();
}
}
So, I made my own composite key in Java with 3 members
public class MyOwnKey{
int location;
int length;
String [] tokens;
}
Now I create two objects using the constructor
String [] tokens = "Stackoverflow is great".split("\\s+");
Object key1 = new MyOwnKey(0,0,tokens)
tokens = "Web is great".split("\\s+");
Object key2 = new MyOwnKey(0,0,tokens)
Now, I add the key in HashMap
HashMap map = new HashMap();
map.put(key1,1);
Now, this is the problem
when I do contains key, it gives false;
**map.containsKey(key2) //returns false whereas it should return true.**
Just so that it makes sense:
key1.equals(key2) returns true
and the hashcode codes are also equal. key1.hashCode() == key2.hashCode().
I have implemeneted my own version of hashCode, toEquals() and toCompare().
Not sure what's the problem.
Here is the code
import java.io.DataOutput;
import java.io.DataInput;
import java.io.IOException;
import org.apache.hadoop.io.WritableComparable;
public class PatternGeneratorKey implements WritableComparable<Object> {
private String [] tokens;
int location;
int length;
StringBuffer _toString = null;
public PatternGeneratorKey(){
tokens = new String[1];
location =0;
length=1;
}
public PatternGeneratorKey(int location, int length, String [] tokens){
this.location = location;
this.length = length;
this.tokens= new String[tokens.length];
for(int i = 0; i < tokens.length;i++){
this.tokens[i] = tokens[i];
}
}
public int compareTo(Object o) {
if (!(o instanceof PatternGeneratorKey))
return -1;
return this.compareTo((PatternGeneratorKey) o);
}
public void write(DataOutput out) throws IOException {
out.writeInt(tokens.length);
for(int i = 0; i<tokens.length;i++){
out.writeUTF(tokens[i]);
}
out.writeInt(location);
out.writeInt(length);
}
public void readFields(DataInput in) throws IOException {
int l = in.readInt();
tokens = new String[l];
for(int i = 0; i < l ; i++){
tokens[i] = in.readUTF();
}
location = in.readInt();
length = in.readInt();
}
public int compareTo(PatternGeneratorKey k) {
if(this.tokens.length - this.length != k.tokens.length - k.length){
return this.tokens.length - this.length -( k.tokens.length - k.length);
}
if(this.location != k.location){
return this.location - k.location;
}
int i = 0 , j= 0;
for(i = 0, j=0 ; i < this.tokens.length && j < k.tokens.length;){
if(i == this.location ){
i = i + length;
continue;
}
if( j == k.location){
j = j + k.length;
continue;
}
if(!this.tokens[i].equalsIgnoreCase(k.tokens[j])){
return this.tokens[i].compareTo(k.tokens[j]);
}else{
i++;
j++;
}
}
//TODO: add comparison on left out phrase
return 0;
}
public int hashCode() {
int hashCode=0;
for(int i = 0; i < tokens.length;){
if(i == location ){
i = i + length;
continue;
}
hashCode += tokens[i++].hashCode();
}
hashCode+= location + tokens.length;
return hashCode;
}
public String toString(){
if(_toString == null){
_toString = new StringBuffer();
for(int k = 0; k < tokens.length ;k++){
if(k==location){
_toString.append(":").append(" ");
k=k+length-1;
}else{
_toString.append(tokens[k]).append(" ");
}
}
}
return _toString.toString();
}
public boolean equals(PatternGeneratorKey k) {
if(this.tokens.length - this.length == k.tokens.length - k.length
&& this.location == k.location){
//assume second one is larger
String tokens[] = k.tokens;
int length = k.length;
int location = k.location;
String [] tokens1 = this.tokens;
int length1 = this.length;
int location1 = this.location;
//make the local variable point to the largest of the two
if( this.tokens.length > k.tokens.length){
tokens = this.tokens;
length = this.length;
location = this.location;
tokens1 = k.tokens;
length1 = k.length;
location1 = k.location;
}
int i = 0 , j= 0;
for(i = 0, j=0 ; i < tokens.length;){
if(i == location ){
i = i + length;
continue;
}
// if( j >= location1 && j<= location1 + length1 -1){
if( j == location1){
j = j + length1;
continue;
}
if(!tokens[i++].equalsIgnoreCase(tokens1[j++])){
return false;
}
}
return true;
}else{
return false;
}
}
}
And, this is the code I am testing on
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.hadoop.io.Text;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String value = "gm used cars";
// Compile all the words using regex
String[] tokens = value.toString().split("\\s+");
//to find pattern we need atleast two words in the query
if(tokens.length <=1){
return;
}
Map<PatternGeneratorKey,List> map = new HashMap<PatternGeneratorKey, List>();
for(int l = 1 ; l < tokens.length; l++){
for(int i = 0 ; i < tokens.length - (l-1); i++){
String hit = new String(getPhrase(l, i, tokens));
PatternGeneratorKey key1 = new PatternGeneratorKey(i, l, tokens);
List list = null;
for(int k = 0;k< tokens.length;k++){
System.out.println("i:" + i + ",l:" + l + ",tokens:" + tokens[k]);
}
System.out.println("hashcode:" + key1.hashCode());
if(!map.containsKey(key1)){
list = new ArrayList<String>();
map.put(key1, list);
}else{
list = (List) map.get(key1);
}
list.add(hit);
}
}
value = "ford used cars";
String[] tokens2= value.toString().split("\\s+");
PatternGeneratorKey key2 = new PatternGeneratorKey(0, 1, tokens);
//run a sliding window for length 1 to tokens length -1
for(int l = 1 ; l < tokens2.length; l++){
//genereate token pairs with sliding window.
for(int i = 0 ; i < tokens2.length - (l-1); i++){
//hit a single token or a + b if there are two.
String hit = new String(getPhrase(l, i, tokens2));
PatternGeneratorKey key1 = new PatternGeneratorKey(i, l, tokens2);
System.out.println();
System.out.println(key1.toString() + "|" + key2.toString() + "|"+ key1.equals(key2));
for(int k = 0;k< tokens2.length;k++){
System.out.println("i:" + i + ",l:" + l + ",tokens:" + tokens2[k]);
}
System.out.println("hashcode:" + key1.hashCode());
List list = null;
if(!map.containsKey(key1)){
list = new ArrayList<String>();
map.put(key1, list);
}else{
list = (List) map.get(key1);
}
list.add(hit);
}
}
value = "ford used cars";
tokens= value.toString().split("\\s+");
PatternGeneratorKey key1 = new PatternGeneratorKey(0,1,tokens);
tokens2 = "gm used cars".split("\\s+");
key2 = new PatternGeneratorKey(0,1,tokens2);
System.out.println(key1.equals(key2));
System.out.println(key2.equals(key1));
System.out.println(key1.hashCode() );
System.out.println(key2.hashCode() );
System.out.println(map);
}
private static String getPhrase(int l, int i, String[] tokens){
StringBuffer strin = new StringBuffer();
int index = 0;
for(index = i ; index < i+l;index++){
if(index < i+l-1){
strin.append(tokens[index]).append("+");
}
else
{
strin.append(tokens[index]);
}
}
return strin.toString();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您的问题是由于
equals(PatternGeneratorKey)
没有覆盖equals(Object)
(但它重载了equals(Object)
,这样,当key1
和key2
是PatternGeneratorKey 类型的变量时,
!)。key1.equals(key2)
返回true
由于
HashMap
调用equals(Object)
来检查键是否相等,因此您的方法永远不会被调用,因此您需要实现equals(Object)
。Your problem is caused by the fact that
equals(PatternGeneratorKey)
doesn't overrideequals(Object)
(but it overloadsequals(Object)
, so thatkey1.equals(key2)
returnstrue
whenkey1
andkey2
are variables of typePatternGeneratorKey
!).Since
HashMap
callsequals(Object)
to check keys for equality, your method never gets called, so you need to implementequals(Object)
instead.hashCode() 或 equals() 中存在错误。向我们展示代码。
疯狂猜测:在您的代码中 key1.equals(key2) 并不意味着 key2.equals(key1) 。
You have a bug in either hashCode() or equals(). Show us the code.
Wild guess: in your code key1.equals(key2) doesn't mean key2.equals(key1).
您为
equals(MyOwnKey)
创建了重载,而不是覆盖equals(Object)
。在
equals()
和hashCode()
上使用@Override
注释。它会在编译时捕获这个相当常见的错误。You created an overload for
equals(MyOwnKey)
instead of overridingequals(Object)
.Use the
@Override
annotation onequals()
andhashCode()
. It will catch this fairly common error at compile time.HashMap#containsKey 覆盖 AbstractMap#containsKey - 因此条件的方式存在细微差别:
“当且仅当此映射包含键 k 的映射时返回 true,使得 (key==null ? k==null : key .equals(k))”
已实现。
对于不重写 containsKey() 的 AbstractMap 子类,那么您很可能只需正确实现 equals() 就可以摆脱困境。但是,对于 HashMap,您需要正确实现 hashCode() 并满足适当的标识。
无论如何 - 向我们展示代码。
HashMap#containsKey overrides AbstractMap#containsKey - so there's a subtle difference in the way that the condition:
"Returns true if and only if this map contains a mapping for a key k such that (key==null ? k==null : key.equals(k))"
is implemented.
For a subclass of AbstractMap which doesn't override containsKey() then you may well be able to get away with just implementing equals() correctly. However, for a HashMap, you need to have the implementation of hashCode() correct and satisfying the appropriate identity as well.
In any case - show us the code.
你还没有真正实现 equals 。
public boolean equals(PatternGeneratorKey k) {
不是 HashMap 使用的。它正在寻找 public boolean equals(Object obj) {}
You haven't actually implemented equals.
public boolean equals(PatternGeneratorKey k) {
is not what HashMap uses. It's looking for public boolean equals(Object obj) {}