This is what I wrote.
public class Test {
public static void main(String[] args) {
Object a1 = new A();
Object a2 = new Object();
System.out.println(a1.toString());
System.out.println((a1 == a2) + " " + (a1.equals(a2)));
}
}
class A {
int x;
public boolean equals(Object obj) {
A _obj = (A) obj;
return x == _obj.x;
}
public String toString() {
return "A's x is " + x;
}
}
How can I make 'false true' on the console? Except revising the main method. Revise only A method.
I tried to make change the Object a2 to an a2. How Can I change that in the A class?
The reason you're getting the error class java.lang.Object cannot be cast to class A is because the object you're comparing it to is not an instance of class A, so trying to cast the object as such will fail.
When implementing the .equals method, you should always perform these three checks first to ensure the safety of the object before you try comparing its properties:
if (obj == this) return true; If the two objects are the exact same object, meaning that they are the same instance, not just two objects with the same properties, immediately return true because there is no need to check the properties.
if (obj == null) return false; This prevents a NullPointerException by trying to access a property of a null object (such as when in your code you do return x == _obj.x)
if (!(obj instanceof A)) return false; If the object is not an instance of your class, the typecast will fail (as it did in your code) and this protects against that by returning false before trying to cast.
Finally, if the code reaches this point you can cast and compare the objects as you had done in your code:
A _obj = (A) obj;
return this.x == _obj.x;
Keep in mind that if the properties you are comparing are not primitives, you should use .equals on them
First of all, what do you mean by "making false true" exactly? I assume you want your code to run, but could you give us a bit more context of what you are trying to do?
The reason your code fails is that you are trying to cast your instance of an Object (a2) onto a reference of type A when you pass it into the equals method. But since a2 is actually a pure instance of Object and not of A, this cast fails. Even though Object is the baseclass for everything in Java, including your self defined A, you are casting in the wrong direction. An Object does not hold an attribute x so casting this way would be unsafe. Java's typechecking mechanism catches this and throws an error when you try to cast.
Have a look at a document explaining inheritance and casting to get the basics of this. E.g., this one.
Related
Say I create one object and add it to my ArrayList. If I then create another object with exactly the same constructor input, will the contains() method evaluate the two objects to be the same? Assume the constructor doesn't do anything funny with the input, and the variables stored in both objects are identical.
ArrayList<Thing> basket = new ArrayList<Thing>();
Thing thing = new Thing(100);
basket.add(thing);
Thing another = new Thing(100);
basket.contains(another); // true or false?
class Thing {
public int value;
public Thing (int x) {
value = x;
}
equals (Thing x) {
if (x.value == value) return true;
return false;
}
}
Is this how the class should be implemented to have contains() return true?
ArrayList implements the List Interface.
If you look at the Javadoc for List at the contains method you will see that it uses the equals() method to evaluate if two objects are the same.
I think that right implementations should be
public class Thing
{
public int value;
public Thing (int x)
{
this.value = x;
}
#Override
public boolean equals(Object object)
{
boolean sameSame = false;
if (object != null && object instanceof Thing)
{
sameSame = this.value == ((Thing) object).value;
}
return sameSame;
}
}
The ArrayList uses the equals method implemented in the class (your case Thing class) to do the equals comparison.
Generally you should also override hashCode() each time you override equals(), even if just for the performance boost. HashCode() decides which 'bucket' your object gets sorted into when doing a comparison, so any two objects which equal() evaluates to true should return the same hashCode value(). I cannot remember the default behavior of hashCode() (if it returns 0 then your code should work but slowly, but if it returns the address then your code will fail). I do remember a bunch of times when my code failed because I forgot to override hashCode() though. :)
It uses the equals method on the objects. So unless Thing overrides equals and uses the variables stored in the objects for comparison, it will not return true on the contains() method.
class Thing {
public int value;
public Thing (int x) {
value = x;
}
equals (Thing x) {
if (x.value == value) return true;
return false;
}
}
You must write:
class Thing {
public int value;
public Thing (int x) {
value = x;
}
public boolean equals (Object o) {
Thing x = (Thing) o;
if (x.value == value) return true;
return false;
}
}
Now it works ;)
Just wanted to note that the following implementation is wrong when value is not a primitive type:
public class Thing
{
public Object value;
public Thing (Object x)
{
this.value = x;
}
#Override
public boolean equals(Object object)
{
boolean sameSame = false;
if (object != null && object instanceof Thing)
{
sameSame = this.value == ((Thing) object).value;
}
return sameSame;
}
}
In that case I propose the following:
public class Thing {
public Object value;
public Thing (Object x) {
value = x;
}
#Override
public boolean equals(Object object) {
if (object != null && object instanceof Thing) {
Thing thing = (Thing) object;
if (value == null) {
return (thing.value == null);
}
else {
return value.equals(thing.value);
}
}
return false;
}
}
Other posters have addressed the question about how contains() works.
An equally important aspect of your question is how to properly implement equals(). And the answer to this is really dependent on what constitutes object equality for this particular class. In the example you provided, if you have two different objects that both have x=5, are they equal? It really depends on what you are trying to do.
If you are only interested in object equality, then the default implementation of .equals() (the one provided by Object) uses identity only (i.e. this == other). If that's what you want, then just don't implement equals() on your class (let it inherit from Object). The code you wrote, while kind of correct if you are going for identity, would never appear in a real class b/c it provides no benefit over using the default Object.equals() implementation.
If you are just getting started with this stuff, I strongly recommend the Effective Java book by Joshua Bloch. It's a great read, and covers this sort of thing (plus how to correctly implement equals() when you are trying to do more than identity based comparisons)
Shortcut from JavaDoc:
boolean contains(Object o)
Returns true if this list contains the specified element. More formally,
returns true if and only if this list contains at least one element e such
that (o==null ? e==null : o.equals(e))
record overrides equals
You said:
another object with exactly the same constructor input
… and …
Assume the constructor doesn't do anything funny with the input, and the variables stored in both objects are identical.
As other Answers explain, you must override the Object#equals method for List#contains to work.
In Java 16+, the record feature automatically overrides that method for you.
A record is a brief way to write a class whose main purpose is to communicate data transparently and immutably. By default, you simply declare the member fields. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString.
The logic of equals by default is to compare each and every member field of one object to the counterpart in another object of the same class. Likewise, the default implementations of hashCode and toString methods also consider each and every member field.
record Thing( int amount ) {} ;
That’s it, that is all the code you need for a fully-functioning read-only class with none of the usual boilerplate code.
Example usage.
Thing x = new Thing( 100 ) ;
Thing y = new Thing( 100 ) ;
boolean parity = x.equals( y ) ;
When run.
parity = true
Back to your List#contains question.
Thing x = new Thing( 100 );
List < Thing > things =
List.of(
new Thing( 100 ) ,
new Thing( 200 ) ,
new Thing( 300 )
);
boolean foundX = things.contains( x );
When run.
foundX = true
Bonus feature: A record can be declared locally, within a method. Or like a conventional class you can declare a record as a nested class, or as a separate class.
I have an assignment to implement a generic Pair interface that represents ordered pairs like (x,y). I'm trying to write the equals method, but I have to make the parameter a general object instead of a pair, so I don't know how to get the coordinates of it. I get a symbol not found error when I try to compile because the Object class doesn't have a fst and snd method. Should I be throwing an exception or something? Note: My professor gave us a template and I'm just filling in the methods, I don't think I'm allowed to change params or methods.
Here's relevant code:
public class Pair<T1,T2> implements PairInterface<T1,T2>
{
private T1 x;
private T2 y;
public Pair(T1 aFirst, T2 aSecond)
{
x = aFirst;
y = aSecond;
}
/**
* Gets the first element of this pair.
* #return the first element of this pair.
*/
public T1 fst()
{
return x;
}
/**
* Gets the second element of this pair.
* #return the second element of this pair.
*/
public T2 snd()
{
return y;
}
...
/**
* Checks whether two pairs are equal. Note that the pair
* (a,b) is equal to the pair (x,y) if and only if a is
* equal to x and b is equal to y.
* #return true if this pair is equal to aPair. Otherwise
* return false.
*/
public boolean equals(Object otherObject)
{
if(otherObject == null)
{
return false;
}
if(getClass() != otherObject.getClass())
{
return false;
}
T1 a = otherObject.fst();
T2 b = otherObject.snd();
if (x.equals(a) && y.equals(b))
{
return true;
}
else
{
return false;
}
}
These are the errors I get:
./Pair.java:66: cannot find symbol
symbol : method fst()
location: class java.lang.Object
T1 a = otherObject.fst();
^
./Pair.java:67: cannot find symbol
symbol : method snd()
location: class java.lang.Object
T2 b = otherObject.snd();
^
The parameter to the equals method is an Object, which is not guaranteed to have your methods fst or snd, hence the compiler error. To be able to call those methods, you need to have a Pair object.
It is standard practice to test the class of the object passed in, to see if it's even the same class as this, returning false if it's not the same class. Usually that is done with instanceof, followed by a cast if true. The cast allows the compiler to treat the object as if it is the class that you say it is. This allows the compiler to find the methods you want to call.
if(otherObject == null)
{
return false;
}
// Use instanceof
if(!(otherObject instanceof Pair))
{
return false;
}
// Cast - use <?, ?>; we don't know what they are.
Pair<?, ?> otherPair = (Pair<?, ?>) otherObject;
Object a = otherPair.fst();
Object b = otherPair.snd();
// Simplified return
return (x.equals(a) && y.equals(b));
after class comparison if(getClass() != otherObject.getClass()) return false;
you need to create new variable with proper type, like this:
Pair<T1,T2> pair = (Pair<T1,T2>)otherObject;
then you will be able to use pair and its methods
After you have ensured that getClass() != otherObject.getClass() is true, you may perform a safe cast to Pair<?, ?> pair = (Pair<?, ?>) otherObject;. Then, use your code as it is. Note: You cannot perform a safe cast to Pair<T1, T2>, as you only know that otherObject is an instance of Pair<?, ?>. Your comparison with .equals() should still work, however.
You have to cast the other object explicitly to be a pair, first (considering you already know it's a Pair object because the classes are the same), but you don't know what type it has, so you should use a wild card.
Pair<?, ?> otherPair = (Pair<?, ?>)otherObject;
//add null-checks if fst() or snd() is nullable
if(this.fst().equals(otherPair.fst()) && this.snd().equals(otherPair.snd()) {
return true;
} else {
return false;
}
You can pass any object type to equals(), so part of properly implementing equals is to check the type of the argument Object.
If you look at the java core classes, they usually start by checking == and then whether it's an instanceof the class implementing equals().
Generally speaking, you should check:
1) == equality, ie, whether the argument is a reference to the current object itself- if it is, the objects should be equal per equals(). This is computationally cheap.
2) whether the argument is null. This is also computationally cheap and if true, ensures that equals() returns false.
3) whether or not the argument object is an instance of the current object's class. If it isn't it can't be equal and the cast will fail anyway.
4) then cast it and start comparing the parts to one another
Lazy programmer tip- eclipse can automatically generate nice java equals() blocks using a wizard. It's in right click > source > generate hashcode() equals() and bam, it generates a proper equals() method.
Cast your otherObject to a Pair before calling its methods.
Pair<T1, T2> otherPair = (Pair) otherObject;
T1 a = otherPair.fst();
T2 b = otherPair.snd();
It's because you do not cast otherObject first, so JVM think it was of type Object. An Object does not have methods fst() and snd(), so it fails.
To solve, cast otherObject to Pair then call fst() and snd():
public boolean equals(Object otherObject)
{
if(otherObject == null)
{
return false;
}
if(getClass() != otherObject.getClass())
{
return false;
}
T1 a = ((Pair<T1, T2>)otherObject).fst();
T2 b = ((Pair<T1, T2>)otherObject).snd();
if (x.equals(a) && y.equals(b))
{
return true;
}
else
{
return false;
}
}
I have been reading a book called Thinking in Java on Java(I come from C background). I came across the following two set of codes
public class EqualsMethod {
public static void main(String[] args) {
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1.equals(n2));
}
}
//Output: true
I understand that this equal method is comparing the reference. But n1 and n2 are two object residing in ´two different "bubble" in the heap. So how come they are equal?
Another example code is
class Value {
int i;
}
public class EqualsMethod2 {
public static void main(String[] args) {
Value v1 = new Value();
Value v2 = new Value();
v1.i = v2.i = 100;
System.out.println(v1.equals(v2));
}
} /* Output:false
}
Why does this give false? Your in depth answer would be much anticipated. Thank you.
The behavior of equals in your custom classes is entirely up to you. If you override it, you decide when two objects of your class are considered equal to each other. If you don't override it, you get the default implementation of Object class, which checks if both references refer to the same object (i.e. checks if v1==v2 in your example, which is false).
Root of the issue :
You have not overrriden eqauals and hashCode and then JVM assigns a new hashCode to any object you create in the case of Value class
=================
Solution :
You will need to define the criteria on which the identities of the value object is measured i.e do the following
1) Override the equals method and specify that the equality is checked over the value of the instance variable i
2) Override Hashcode and use instance variable i for the hashCode comparison
== is used in the equals method in the object class to avoid unnecessary calculation if the two refrences point to the same object and if not go ahead with the calculation and comparisons
public boolean equals(Object anObject)
{
if (this == anObject) {
return true;
}
else{
// Do the calculation here to check the identity check
}
I understand that this equal method is comparing the reference.
Wrong. In the Object class, this method contains a referential comparison, but Integer has it's own implementation, which overrides the one provided by Object.
It compares the values of the two Integers, not their references.
Integer is valuable type. So comparing to Integer variables performing by comparing their values. Which are equal in your particular case.
Comparing two objects (reference type) performing by comparing the references, which are not equal.
You could write your own comparison logic by overloading the equals() method in your class.
Integer has the method equals() that compare the value, and your Value class doesn't. It makes the Value class with equals compare the "pointer", and they're different.
If you override the method equals in your class Value comparing the attribute i from the class, it would return true.
For example
public boolean equals(Object o){
return (this.i == ((Value) o).i) ? true : false;
}
Equals method in all Wrapper classes is overridden by default in java. That's is why first snippet works.
For your own classes, you have to provide an implementation of equals method.
By default the equal method in Java check if the two Object references are the same. You can #Override the method, and do what you want. So it is normal that you get False, because the two Object are different.
So how come they are equal?
Integer is an Object. On the other side int is a simple type.
Integer's equals() method compare int inside, because it's overriding Object equals() method. int's there has the same value.
Why does this give false?
Your Value class doesn't override equal's method, so then refferences are compared, exactly like when you write v1 == v2. In this case they are different Objects so it's false.
Because you have not override equals method. If you do not override it then it will check if the reference are equal or not and return accordingly.
You can refer equals() method defined in Integer class.
System.out.println(n1.equals(n2)) // this prints true because it refers to Integer equals method.
Similarly you will have to override it for your Value class like.
class Value {
int i;
#Override
public boolean equals(Object obj) {
boolean returnValue = false;
if (obj != null && obj instanceof Value) {
Value valObj = (Value) obj;
if (this.i == valObj.i) {
returnValue = true;
}
}
return returnValue;
}
}
Now System.out.println(v1.equals(v2)); prints true.
Hi your understanding of equals and == is completely wrong or opposite to what it actually is.
equals() method also checks for reference as == does, there is no difference between both of them unless you override the equals method.
== check for reference equality. For better understanding see Object class source code.
public boolean equals(Object obj) {
return (this == obj);
}
Why is it working in your case? is because Integer class overrides the equals method in it.
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
n
}
Now when you use your custom class to check equality what it is doing is basically calling.
v1==v2
How it can give you true? They both have different memory locations in heap.
If still things are not clear put break points in your code and run it in debug mode.
Let's say I have two objects, A and B where..
Object A=new Object();
Object B=A;
These objects by default each have two ints: int X and int Y. First, in both A and B,
(X == 0) && (Y == 0)
So, you would say those two are equal, as would Java. Now, let's say we change A.X so that A.X=2. Now, A and B are no longer equal since
A.X==2
..but..
B.X==0
Java, however, still says they are equal.
(A.equals(B)) == true
(B.equals(A)) == true
So, how do you get around that?
By doing this Object B=A;, you are not creating a new object, but B is pointing to A only. So its only one object.
So when you change A.X = 2, B.X is also 2 at its referring the same variable and hence equal.
You may verify this by printing B.X value.
I think everyone (except Mr Singh) is missing a point here:
Object A=new Object(); // Implication is that this is really a user-defined class
Object B=A;
You only have one object here. If you make a change to object A the same change will appear in object B, since they are the exact same object.
You need to override the .equals method of your class that contains the variables. Take a look at this question: How to override equals method in java
If Object is really your own class and not java.lang.Object (if it were then it would have those variables x and y) then it's really a bad class name choice.
Your class must override the .equals method as:
#Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(!(obj instanceof MyObject)) return false;
MyObject other = (MyObject) obj;
return other.x == this.x && other.y == this.y;
}
How do I compare Base class object with derived class object in derived class? I need to get true as output from the code below:
class Base {
int i;
String str;
}
class Derived extends Base{
double d;
String str1;
public static void main(String []a){
Base b= new Base();
Derived d = new Derived();
System.out.println("Equals! :"+d.equals(b));
}
}
It always gives me false as output. How can I compare base class with derived class?
Object equality is usually defined for objects of the same class, e.g.: You might want two objects Base b1, b2 to be equal if their str and i values are equal. Then you would need to define the equals() (and, typically, hashCode()) methods to test for this condition. For example:
public boolean equals(Object obj)
{
// test for identity
if (this == obj) return true;
// check that obj is not null, and that it is an instance of Base
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
// compare attributes
Base other = (Base) obj;
if (i != other.i) return false;
if (str == null && other.str != null) return false;
if (!str.equals(other.str)) return false;
return true;
}
In your case, since Base and Derived are different classes, with different attributes (Base has str and i, while Derived has str, i, str1, and d), you would need to define exactly when are a Base object and a Derived object supposed to be equal.
Well, to make it just return true is easy enough:
#Override
public boolean equals(Object other) {
return true;
}
However, I'd argue that that's not what you should be doing (even in a somewhat less trivial implementation).
I think the equals method from Object shouldn't return true unless the types are actually the same. Otherwise it ends up making life really tricky in terms of making sure that the symmetry aspects required by Object.equals(Object) are fulfilled. It also doesn't feel like it's fulfilling natural equality at that point.
However, it would be entirely reasonable to write an class which is able to compare any two instances of Base for equality in your specific case. The nice thing about equality comparators is that they don't have to be as natural - you're not defining what equality should mean for the whole type - you're just describing one specific comparison.
It's unfortunate that Java doesn't have an EqualityComparator<T> (or whatever) interface to go with Comparator<T>. It makes it much harder to create (say) maps and sets which use a specific idea of equality (and a hash code to go with it). That may or may not be a problem in your case - how are you hoping to use this equality comparison anyway? If it's in your own code, you could write your own EqualityComparator<T> interface. If you're going to build a map or set, it's not going to be as easy :(