简体   繁体   中英

Java MultiMap Not Recognizing Key

I'm trying to store multiple values for a key in a data structure so I'm using Guava (Google Collection)'s MultiMap.

Multimap<double[], double[]> destinations = HashMultimap.create();
destinations = ArrayListMultimap.create();

double[] startingPoint = new double[] {1.0, 2.0};
double[] end = new double[] {3.0, 4.0};
destinations.put(startingPoint, end);

System.out.println(destinations.containsKey(startingPoint));

and it returns false.

Note: Key-values are being stored in the multimap as the destinations.size() increases when I put something there.It also does not happen when keys are String instead of double[] .

Any idea what the problem is?

Edit: Many thanks to Jon Skeet I now implemented the class:

class Point {

    double lat;
    double lng;

    public boolean equals(Point p) {

        if (lat == p.lat && lng == p.lng)
            return true;
        else
            return false;
    }

    @Override
    public int hashCode() {

        int hash = 29;
        hash = hash*41 + (int)(lat * 100000);
        hash = hash*41 + (int)(lng * 100000);

        return hash;
    }

    public Point(double newlat, double newlng) {
        lat = newlat;
        lng = newlng;
    }
}

And now I have a new problem. This is how I'm using it:

Multimap<Point, Point> destinations = HashMultimap.create();
destinations = ArrayListMultimap.create();

Point startingPoint = new Point(1.0, 2.0);
Point end = new Point(3.0, 4.0);
destinations.put(startingPoint, end);

System.out.println( destinations.containsKey(startingPoint) );
System.out.println( destinations.containsKey(new Point(1.0, 2.0)) );

The first one returns true, the second one returns false. It gives me an error if I put @Override before the equals method.Any Idea what the problem is now?

Thanks:)

Edit2: It now behaves exactly as expected when I changed equals to this:

@Override
public boolean equals(Object p) {

    if (this == p)
        return true;
    else if ( !(p instanceof Point) )
        return false;
    else {
        Point that = (Point) p;
        return (that.lat == lat) && (that.lng == lng);
    }
}

Thanks everyone.

You're using arrays as the hash keys. That's not going to work - Java doesn't override hashCode and equals for arrays. (The Arrays class provides methods to do this, but it's not going to help you here.) Admittedly I'd expect it to work in this specific case, where you're using the exact same reference for both put and containsKey ... When I test your code, it prints true . Are you sure you can reproduce it with exactly your code?

For example, while I'd expect it to work for the code you've given, I wouldn't expect this to work:

// Logically equal array, but distinct objects
double[] key = (double[]) startingPoint.clone();
System.out.println(destinations.containsKey(key));

It sounds like you shouldn't really be using double[] here - you should create a Point class which has two double variables, and overrides equals and hashCode .

Additionally, using double values in hash keys is usually a bad idea anyway, due to the nature of binary floating point arithmetic. That's going to be a problem even using the Point idea above... it should be okay if you don't need to actually do any arithmetic (if you're just copying values around) but take great care...

The problem is that you cannot hash "equal" arrays and get the same result each time. For example:

public static void main(String[] args) {
     System.out.println(new double[]{1.0, 2.0}.hashCode());
     System.out.println(new double[]{1.0, 2.0}.hashCode());
}

will result something like

306344348
1211154977

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM