简体   繁体   中英

Can we change behavior of equals method dynamically?

I have one class having two variables named as x and y . In this class I have overrided the equals and hashCode methods to compare two object of this class. But our requirement is to compare two object of this class sometimes on the basis of x and sometimes on the basis of y . Is it possible dynamically in Java?

Edit: I have one more class named as B, in this class there is two method m1 and m2 and I want to compare the above class object in such a way that when we call from m1 (for sorting) the above objects will be compared on the basis of x (means compare object by compare x variable) and when we call from m2 (for sorting) then we compare according to y.

Changing behavior based on last method to call your method is possible, but you shouldn't do it for a lot of reasons.

  • it violates the equals contract, thus breaking the functionality of several algorithms designed to handle collections
  • result of the comparison cannot be anymore known without knowing the caller, which is a hard dependency that's prone to break

However, if you insist you need it, you can do like

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
if (stackTraceElements.length < 3)
{
    // do something when last method to call is not available
    // probably you'll want to return something
}
String callerMethod = stackTraceElements[2].getMethodName();
if (callerMethod.equals("m1"))
{
    // something
} else
{
    // something else
}

This example is simplified as it assumes the method calling this method is the candidate - it can be some method further down the call stack.

As noted, this is not recommended. Rather use different kind of comparators for the purpose, and give a relevant comparator to the sort method to have different kind of sorting per context.

Depending on the complexity of the comparison, you can either do this within the class or use two seperate comparator classes.

public boolean equals(Object other){
    if(condition == true){
        return x==x;
    }else{
        return y==y;
    }
}

or

public boolean equals(Object other){
    if(condition == true){
        return new CompareX(this, other).compare();
    }else{
        return new CompareY(this, other).compare();
    }
}

You have to extend the comparison logic to a valid one, of course.

Oh and, the same principle applies to the hashCode.

It's not possible, to change the behaviour of equals dynamically. You have to use Comparator to provide the comparison from the outside of the class.

Since Java8 with Lambdas it is easy to use Comparators .

There is a method comparing . You can create Comparators out of Methods, which you want to compare.

// A comparator comparing on x
Comparator<A> comp1 = comparing (a -> a.x); 
// A comparator comparing on the output of m1
Comparator<A> comp2 = comparing (A::m1);
// A comparator comparing on the output of m1 and when equals, comparing on x
Comparator<A> comp2 = comparing (A::m1).thenComparing (a -> a.x);

From the external point you can decide, which comparator to use.

There's a new way to sort your data in Java8, too:

List<A> data;
data.stream ().sorted (comparing (a -> a.x));

Of course you have to be allowed to use Java8 for this.

If you can add flag setting code to m1 and m2 you can modify eis answer to get rid of the kludgy stacktrace stuff.

It is still kludgy.

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