Java Newbie learning about polymorphism - java

This equals() method will produce the same output if lines 3-5 are omitted (I numbered these lines). What is the point of these lines?
/** Return true if that Beetle has the same parts as this one. */
public boolean equals(Object that) {
3. if (this == that) {
4. return true;
5. }
if (that == null) {
return false;
}
if (getClass() != that.getClass()) {
return false;
}
Beetle thatBeetle = (Beetle) that;
return body == thatBeetle.body
&& eyes == thatBeetle.eyes
&& feelers == thatBeetle.feelers
&& head == thatBeetle.head
&& legs == thatBeetle.legs
&& tail == thatBeetle.tail;
}

Checking == reference equality is fast, and if true the object is being compared to itself -- so is by definition equal.
This is often used a first step when comparing objects, as it's much faster than comparing all the details. But it's more commonly used from the caller/client function, rather than inside the equals() implementation.
For example, in a linear search:
public int indexOfBeetle (Beetle beetle, List<Beetle> list) {
for (int i = 0; i < list.size(); i++) {
Beetle cand = list.get( i);
if (cand == beetle || cand.equals( beetle))
return i; // Found.
}
// Not Found.
return -1;
}

The operator == checks if the objects are the same instance in memory whereas when you override equals you usually want to perform a logical test.
Let's take an example:
public class Person {
private String name;
// Here there are constructor and getters and setters
}
Now let's run these lines:
Person a = new Person();
Person b = a;
Person c = new Person();
If you compare these instances with == this is what you'll get:
a == a ==> true
a == b ==> true
a == c ==> false
Now, let's set the name:
a.setName("Joe"); // This also sets b because they're the same object
c.setName("Joe");
If our equals looks like this:
public boolean equals (Object other) {
if(other == this) return true;
if(other instanceof Person == false) return false;
if(this.getName().equals(((Person) other).getName())) return true;
}
So we'll now get that a.equals(c) is true even though a==c is false.
So, why do we have the first line? - Some objects' equality is more expensive to compute and by checking this condition at the beginning you might spare some unnecessary computations

Doing that are you checking if the two objects are pointing to the same memory address. Using .equals without it you will achieve the same result because if they are pointing to the same memory address, it's obviously they are equals. But doing that it's much more faster, that's why most developers put this lines on .equals

Related

Question on overriding equals & calling equals recursively

So I overwrote an equals function that works with Nodes that contain objects. and it looks like this.
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
// Checks if obj is from the same class as this Deque.
if (obj.getClass() != this.getClass()) return false;
#SuppressWarnings("unchecked")
// If obj is from the same class, casts object to DoublyLinkedDeque.
DoublyLinkedDeque<T> object = (DoublyLinkedDeque<T>) obj;
Node other = object.front;
Node self = this.front;
// Checks the info of every Node in this Deque with the other.
while (self != null && other != null) { // Checks
if (!(self.info.equals(other.info))) return false;
self = self.next;
other = other.next;
}
// Otherwise, checks if the front of both Deques is null.
return (self == null && other == null);
}
And it works but I'm not sure how the second invocation of equals work. Specifically how does my code check if the info field (that contains objects) of two nodes are equal without calling super.equals? Nothing in my function has the capability to check if two objects are equal as far as I know, can someone explain this?

Compare two ArrayList irrespective of order - Java

Below are two list Some1 and Some which actually has same object data but different in order of elements in object and order of objects in array. My concern is below has to return true. Please favour
List<Some> lome1=new ArrayList<Some>();
Some some1 = new Some();
some1.setTime(1000);
some1.setStartTime(25);
some1.setEndTime(30);
lome1.add(some1);
Some some2 = new Some();
some2.setStartTime(125);
some2.setEndTime(130);
some2.setTime(100);
lome1.add(some2);
List<Some> lome2=new ArrayList<Some>();
Some some3 = new Some();
some3.setStartTime(125);
some3.setEndTime(130);
some3.setTime(100);
lome2.add(some3);
Some some = new Some();
some.setStartTime(25);
some.setTime(1000);
some.setEndTime(30);
lome2.add(some);
Attempts which failed due to order:
With deepEquals:
if(Arrays.deepEquals(lome1.toArray(),lome2.toArray()) ){
System.out.println("equal");
}
else {
System.out.println("not equal");
}
With hashset, both gave different hash value though data is same
if(new HashSet<>(lome1).equals(new HashSet<>(lome2)) ){
System.out.println("equal");
}
else {
System.out.println("not equal");
}
Check if object is contained in another
boolean x=true
for(Some d: lome1) {
if(!lome2.contains(d)) {
x = false;
}
}
if(x){
System.out.println("equal");
}
else {
System.out.println("not equal");
}
First Override hashcode and equals for Some Object, It may look like this,
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Some that = (Some) o;
return startTime == that.startTime &&
endTime == that.endTime &&
time == that.time
}
#Override
public int hashCode() {
return Objects.hash(startTime, endTime, time);
}
Once equals and Hashcode is set then different object with same values will give the same hashcode thus .equals() will return true
Now for the list use
list1.containsAll(list2) && list2.containsAll(list1);
Comparing the two lists as HashSets is probably the best approach, since that works irrespective of the order.
However, your HashSet comparison is dependent on you implementing the equals() and hashCode() functions in your "Some" class. You've not provided the source for that, so I'm guessing you've missed that. Without overriding those methods in your class, the JRE doesn't know that two Some objects are the same or not.
I'm thinking something like this:
#Override
public int hashCode() {
return getTime() + getStartTime() + getEndTime();
}
#Override
public boolean equals(Object o) {
if (o instanceof Some) {
Some other = (Some)o;
if (getTime() == other.getTime()
&& getStartTime() == other.getStartTime()
&& getEndTime() == other.getEndTime()) {
return true;
}
}
return false;
}
The containsAll() API provided by java collection.
lome1.containsAll(lome) should do the trick.
For Java 1.8+ you could check that each element of first list is in the second and vice versa:
boolean equals = lome1.stream().allMatch(e -> lome2.contains(e)) &&
lome2.stream().allMatch(e -> lome1.contains(e));
Do Something like this
List<User> list = new ArrayList<>();
list.add(new User("User","20"));
list.add(new User("Some User","20"));
List<User> list1 = new ArrayList<>();
list1.add(new User("User","20"));
list1.add(new User("Some User","20"));
List<User> storeList = new ArrayList<>();
for (User user: list){
for (User user1:list1){
if (user.getName().equals(user1.getName()) && user.getAge().equals(user1.getAge()))
storeList.add(user);
}
}
boolean check = !storeList.isEmpty();
//OR
check = storeList.size() == list.size();
System.out.println(check);

hashset return false when should return true

I'm programming a Maze and I have some problems.
I have:
HashSet<State> closedList = HashSet<State>(); //it hold State objects
My State class look like this:
public class State implements Comparable<State>{
private double f;
private double g;
private String state;
private State prev;
.
.
.
closedList.add(state);
closedList().contains(state); // this equals true
but when I do this:
State temp = State(0,0,"");
temp.setStateName(state.getStateName());
closedList().contains(temp); // this equals false
I have implemented equals and hashCode in State:
#Override
public int hashCode(){
return state.hashCode();
}
#Override
public boolean equals(Object object){
if(this.state == object){
return true;
}
if(object == null || object.getClass() != this.getClass()){
return false;
}
return false;
}
closedList().contains(state); // this equals true
This is a red herring, it only returns true because HashSet checks with == before it makes a call to equals.
What you should try is something like this:
State temp = new State(0, 0, "");
System.out.println(temp.equals(temp));
And you will find this returns false. Why is that? Well let's follow the logic through.
First, you have this check:
if(this.state == object){
return true;
}
If you really intended this to be the way it is, it means you were expecting equals to be called with the String state as the argument, like this:
temp.equals(temp.getStateName())
(And it's the case the above call would return true.) This is incorrect, one would not expect equals to return true for unrelated classes (and in terms of the equals contract, it's the case this is not symmetric). I assume this is unintended and just like a mistake. You should think more carefully about what your code is doing when you are writing it.
Also you should be comparing Strings with equals, not ==.
Then there is this construct:
if(object == null || object.getClass() != this.getClass()){
return false;
}
return false;
This is pointless because first what it implies logically is this, returning false either way:
if(object == null || object.getClass() != this.getClass()){
return false;
} else {
return false;
}
And, second, combined with the earlier check it is not particularly logical:
if(this.state == object)
return true;
if(object.getClass() != this.getClass())
return false;
This is returning true if object is == to a String but returning false if object's class is not State. These are mutually exclusive.
So the equals implementation you wrote doesn't work. The correct equals to match your hashCode is like this:
#Override
public boolean equals(Object object){
if(object == null || object.getClass() != this.getClass()){
return false;
}
State other = (State)object;
return this.state.equals(other.state);
}
First check that the object is not null and that its class is State (you had that part right), then check that the state member is equal to the other object's state member.

Spring Expression Language (SpEL) in Spring Security to compare object use equals() or ==?

Spring Expression Language (SpEL) in Spring Security to compare object use equals() or ==?
For example(method equals () is not called!):
class SecurityObject {
public boolean equals(Object obj) {
//...
}
}
#PreAuthorize(" #secObject == #otherSecObject ")
public void securityMethod(SecurityObject secObject, SecurityObject otherSecObject) {
//...
}
This is normal!? I need to use #PreAuthorize(" #secObject.equals(#otherSecObject) ") everywhere?
UPDATE
Why in first case Spring Security calling .equals(), and the second not?
//TestObject
public class TestObject {
private static final Logger log = LoggerFactory.getLogger(TestObject.class);
private Long id;
public TestObject(Long id) {
this.id = id;
}
#Override
public int hashCode() {
int hash = 7;
hash = 71 * hash + Objects.hashCode(this.id);
return hash;
}
#Override
public boolean equals(Object obj) {
log.info("equals");
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final TestObject other = (TestObject) obj;
if (!Objects.equals(this.id, other.id)) {
return false;
}
return true;
}
}
//TestService
#PreAuthorize(" #one == #two ")
public String testEqualsInAnnotation(Long one, Long two) {
//...
}
#Override
#PreAuthorize(" #one == #two ")
public String testEqualsInAnnotation(TestObject one, TestObject two) {
//...
}
//Test
log.info("for Long");
Long one = new Long(500);
Long two = new Long(500);
log.info("one == two: {}", (one==two)? true : false); // print false
log.info("one equals two: {}", (one.equals(two))? true : false); // print true
testService.testEqualsInAnnotation(one, two); //OK
log.info("for TestObject");
TestObject oneObj = new TestObject(new Long(500));
TestObject twoObj = new TestObject(new Long(500));
log.info("oneObj == twoObj: {}", (oneObj==twoObj)? true : false); // print false
log.info("oneObj equals twoObj: {}", (oneObj.equals(twoObj))? true : false); // print true
testService.testEqualsInAnnotation(oneObj, twoObj); // AccessDeniedException: Access is denied
UPDATE 2
equals() never invoked at all
package org.springframework.expression.spel.ast;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue;
/**
* Implements equality operator.
*
* #author Andy Clement
* #since 3.0
*/
public class OpEQ extends Operator {
public OpEQ(int pos, SpelNodeImpl... operands) {
super("==", pos, operands);
}
#Override
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue();
Object right = getRightOperand().getValueInternal(state).getValue();
if (left instanceof Number && right instanceof Number) {
Number op1 = (Number) left;
Number op2 = (Number) right;
if (op1 instanceof Double || op2 instanceof Double) {
return BooleanTypedValue.forValue(op1.doubleValue() == op2.doubleValue());
} else if (op1 instanceof Long || op2 instanceof Long) {
return BooleanTypedValue.forValue(op1.longValue() == op2.longValue());
} else {
return BooleanTypedValue.forValue(op1.intValue() == op2.intValue());
}
}
if (left!=null && (left instanceof Comparable)) {
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) == 0);
} else {
return BooleanTypedValue.forValue(left==right);
}
}
}
As per spEL documentation, You need to create ExpressionParser instance, create an Expression instance and get the value like below
String name = "Nikola Tesla";
Expression exp = parser.parseExpression("name == 'Nikola Tesla'");
boolean result = exp.getValue(Boolean.class);
result evaluates to 'true'. That says when we need to compare any two objects, then we need to override the equals() method and pass the two objects in to parser#parseExpression("obj1 == obj2") and then call the exp#getValue(Boolean.class) to evaluate. In the similar way, the Expression instance can also have expression string containing Obj1.equals(Obj2) for checking the equality. so, both the ways of checking equality are possible with spEL.
You may have discovered this already, since it is in the OpEq code in 'Update 2' of the original post, but...
The comparison operators lt < gt > le <= ge >= eq == ne != are based on java's Comparable interface.
So, if you've got a custom type that you want to be able to compare using == or != in SpEL expressions, then you could write it to implement Comparable.
Of course, then you'll have to figure out some sane rule to decide which object is before the other when they're not equivalent.
That said, I can't find anything in Spring's current documentation indicating this.
rdm, I think you have to use permission evaluator to evaluate the expressions. I don't think you have really injected/passed values for the objects in the following expression.
#Override
#PreAuthorize(" #one == #two ")
public String testEqualsInAnnotation(TestObject one, TestObject two) {
//...
I tried to do the same thing, but I failed to pass values, hence couldn't able to evaluate the expressions. My suggestion is to implement your custom permission evaluator for the above expression, and inject/pass values from the evaluator. To generalize my idea, my suspect is the objects are null, that is why you couldn't able to evaluate it. Please let us know if you can really pass values of the objects inside here : #PreAuthorize(" #one == #two ")
Added:
I am using permission evaluator to evaluate expressions under #PreAuthorize(...) annotation. Because I couldn't able to pass values to the parameters as I explained above. If it is possible to pass/inject values, it will be good to reduce complexity that can come from using permission evaluator.
rdm or others, can you point me how to pass the values for the parameters under #PreAuthorize(...) if possible?
Sorry for asking another question on rdm's post, and thank you in advance for your help!.

Implementing the equals method in java

This is my implementation of the equals class for a Coor class which is just contains 2 ints x and y. would this be the proper way of implementing this method?
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
Coor temp = (Coor) obj;
if (temp.x == this.x && temp.y == this.y) {
return true;
} else {
return false;
}
}
You could add one more check for reflexive equality (equal to self):
public boolean equals(Object obj) {
// Reflexive equality: did I get passed myself?
if(this == obj){
return true;
}
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
Coor temp = (Coor) obj;
return temp.x == this.x && temp.y == this.y;
}
Yes, it would.
Also be sure to override your hashCode() method--never override one without doing the other as well, it will confuse the hell out of your collections.
Your case could use a hash where it simply shifts one of the ints 32 bits and adds it to the other creating a completely unique long (a perfect hash function in this case--no collisions)
Seems ok.
For brevity sake, you can do:
return temp.x == this.x && temp.y == this.y
Instead of
if (temp.x == this.x && temp.y == this.y) {
return true;
} else {
return false;
}
Also, please keep in mind the Object Contract (seriously!).
See the accepted answer here:
What issues should be considered when overriding equals and hashCode in Java?
This can save you a huge about of headache in the future.
Check this out:
http://www.javapractices.com/topic/TopicAction.do?Id=17
If that article is too much detail, then the short of it is:
Your implementation is correct, but you should keep some other things in mind:
You will also have to implement hashCode.
equals will no longer commpare the object's identity. Doesn't sound like that's a problem for you.
You could add the #Override annotation to your equals method.
Here’s a more straightforward way:
public boolean equals(Object other) {
return other instanceof Coor
&& ((Coor) other).x == x
&& ((Coor) other).y == y
}
I believe this would work, at a quick glance. I say this because:
It handles a null/improper types well.
Performing x.equals(y) would yield the same result as y.equals(x).
Performing x.equals(x) would return true.
Performing x.equals(y) == true and y.equals(z) == true implies that x.equals(z) == true
This question has certainly been asked many times before though. See here: Overriding equals and hashCode in Java. A book called Effective Java discusses this topic in great detail too, and the particular chapter is linked off of there.
There's only one source to read for how to override equals and hashCode: chapter 3 of Joshua Bloch's "Effective Java".
If you have a good IDE, like IntelliJ, it'll generate equals and hashCode the right way for you.

Categories