How to compare derived class object with Base class object java? - java

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 :(

Related

What is a good design pattern for tracking issues in a class?

I have a class that has a custom equals() method. When I compare two objects using this equals method, not only am I interested in whether or not they are equal, but if they are not equal, what was different about them. Finally, I want to be able to retrieve the differences arising from an unequal situation.
I currently use logging to display where my objects are unequal. This works, but I have a new requirement of being able to extract the actual results of the equals check for display later. I suspect there is an object-oriented design pattern for handling this type of situation.
public class MyClass {
int x;
public boolean equals(Object obj) {
// make sure obj is instance of MyClass
MyClass that = (MyClass)obj;
if(this.x != that.x) {
// issue that I would like to store and reference later, after I call equals
System.out.println("this.x = " + this.x);
System.out.println("that.x = " + that.x);
return false;
} else {
// assume equality
return true
}
}
}
Are there any good design pattern suggestions where some sort of work is being done, but a secondary object collects information about how well that work was done which can later be retrieved and displayed?
Your problem is that you are trying to use the boolean equals(Object) API for something it was not designed for. I don't think there is any design pattern that will allow you to do this.
Instead, you should be doing something like this:
public class Difference {
private Object thisObject;
private Object otherObject;
String difference;
...
}
public interface Differenceable {
/** Report the differences between 'this' and 'other'. ... **/
public List<Difference> differences(Object other);
}
Then implement this for all classes where you want "differenceable" functionality. For example:
public class MyClass implements Differenceable {
int x;
...
public List<Difference> differences(Object obj) {
List<Difference> diffs = new ArrayList<>();
if (!(obj instanceof MyClass)) {
diffs.add(new Difference<>(this, obj, "types differ");
} else {
MyClass other = (MyClass) obj;
if (this.x != other.x) {
diffs.add(new Difference<>(this, obj, "field 'x' differs");
}
// If fields of 'this' are themselves differenceable, you could
// recurse and then merge the result lists into 'diffs'.
}
return diffs;
}
}
I am unaware of a particular design pattern for this. One problem with this requirement is that to find out all differences between two unequal objects you would need to continue additional comparisons after the first false result (which is typically not necessary).
If I were doing this I might consider doing a normal equality test and if not equal, kick off a thread to determine why and log the results rather than incorporate such logic in the equals method itself. This might be done in a special method outside of the equals method.

Why does javax MimeType not implement equals?

The javax.activation.MimeType class does not compare intuitively (to me) due to a lack of an overridden equals-method. Consider the following snippet;
MimeType a = new MimeType("image/png");
MimeType b = new MimeType("image/png");
a.equals(b); // false
a.toString().equals(b.toString()); // true
a.getBaseType().equals(b.getBaseType());// true
a.getSubType().equals(b.getSubType()); // true
a.getParameters().size(); // 0
b.getParameters().size(); // 0
It seems to me that a and b are equal in every aspect and that a.equals(b) should return true.
Is there a reason that this class does not implement an equals-method?
Update: There exists a match-method which does exactly what I want, but I only found out after posting this question which kind-of confirms the not-so-intuitiveness of this class.
You could consider filing a bug; at a glance this seems like a class that should properly override .equals() and .hashCode(). Of course that won't help you for some time (not sure if this library is on the JDK's release cycle).
As a workaround you could create a subclass or wrapper class that properly implements .equals() and .hashCode(), e.g.:
public class ValueMimeType extends MimeType {
// constructors
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof ValueMimeType) { // not MimeType, as that wouldn't be symetric
return match((ValueMimeType) o);
}
return false;
}
#Override
public int hashCode() {
return toString().hashCode();
}
}
And just always use ValueMimeType instead of MimeType. Obviously not ideal, but better than nothing.
I can only speculate as this decision is not documented, but when checking the MimeType class, there are two match methods: match(MimeType) and match(String). The second does it's job by constructing a MimeType object from the string argument and then calling the first match method.
So by implementing the match methods, it is possible to compare to MimeType and String objects. This would not be possible by implementing the equals(Object)method. Of course you could implement the equals method so that it can compare to both a MimeType and a String, but this would violate the contract that is specified by the equalsdocumentation:
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
This would only work if String.equals(Object o) would use o.toString() to do the comparison, but String doc states:
Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
So you could only implement equals to compare to a different MimeType, and if you want to compare to a String, you would have to fall back to the match(String) method.
And I think the reason for not implementing equals in this class is just to keep the method you use for comparing consistent for different objects to compare to.

Java equal method explanation on the following code

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.

Hash function for a generic object

How do you come up with a hash function for a generic object? There is the constraint that two objects need to have the same hash value if they are "equal" as defined by the user. How does Java accomplish this?
I just found the answer to my own question. The way Java does it is that it defines a hashCode for every object and by default the hashCode for two objects are the same iff the two objects are the same in memory. So when the client of the hashtable overrides the equals() method for an object, he should also override the method that computes hashcode such that if a.equals(b) is true, then a.hashCode() must also equal b.hashCode(). This way, it is assured that equal objects have the same hashcode.
First, basically you define the hash function of a class by overriding the hashCode() method. The Javadoc states:
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.
So the more important question is: What makes two of your objects equal? Or vice versa: What properties make your objects unique? If you have an answer to that, create an equals() method that compares all of the properties and returns true if they're all the same and false otherwise.
The hashCode() method is a bit more involved, I would suggest that you do not create it yourself but let your IDE do it. In Eclipse, you can select Source and then Generate hashCode() and equals() from the menu. This also guarantees that the requirements from above hold.
Here is a small (and simplified) example where the two methods have been generated using Eclipse. Notice that I chose not to include the city property since the zipCode already uniquely identifies the city within a country.
public class Address {
private String streetAndNumber;
private String zipCode;
private String city;
private String country;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((country == null) ? 0 : country.hashCode());
result = prime * result
+ ((streetAndNumber == null) ? 0 : streetAndNumber.hashCode());
result = prime * result + ((zipCode == null) ? 0 : zipCode.hashCode());
return result;
}
#Override
public boolean equals(final Object obj) {
if(this == obj)
return true;
if(obj == null)
return false;
if(!(obj instanceof Address))
return false;
final Address other = (Address) obj;
if(country == null) {
if(other.country != null)
return false;
}
else if(!country.equals(other.country))
return false;
if(streetAndNumber == null) {
if(other.streetAndNumber != null)
return false;
}
else if(!streetAndNumber.equals(other.streetAndNumber))
return false;
if(zipCode == null) {
if(other.zipCode != null)
return false;
}
else if(!zipCode.equals(other.zipCode))
return false;
return true;
}
}
Java doesn't do that. If the hashCode() and equals() are not explicitly implemented, JVM will generate different hashCodes for meaningfully equal instances. You can check Effective Java by Joshua Bloch. It's really helpful.
Several options:
read Effective Java, by Joshua Bloch. It contains a good algorithm for hash codes
let your IDE generate the hashCode method
Java SE 7 and greater: use Objects.hash
The class java.lang.Object cheats. It defines equality (as is determined by equals) as being object identity (as can be determined by ==). So, unless you override equals in your subclass, two instances of your class are "equal", if they happen to be the same object.
The associated hash code for this is implemented by the system function System.identityHashCode (which is no longer really based on object addresses -- was it ever? -- but can be thought of as being implemented this way).
If you override equals, then this implementation of hashCode no longer makes sense.
Consider the following example:
class Identifier {
private final int lower;
private final int upper;
public boolean equals(Object any) {
if (any == this) return true;
else if (!(any instanceof Identifier)) return false;
else {
final Identifier id = (Identifier)any;
return lower == id.lower && upper == id.upper;
}
}
}
Two instances of this class are considered equal, if their "lower" and "upper" members have the same values. Since equality is now determined by object members, we need to define hashCode in a compatible way.
public int hashCode() {
return lower * 31 + upper; // possible implementation, maybe not too sophisticated though
}
As you can see, we use the same fields in hashCode which we also use when we determine equality. It is generally a good idea to base the hash code on all members, which are also considered when comparing for equality.
Consider this example instead:
class EmailAddress {
private final String mailbox;
private final String displayName;
public boolean equals(Object any) {
if (any == this) return true;
else if (!(any instanceof EmailAddress)) return false;
else {
final EmailAddress id = (EmailAddress)any;
return mailbox.equals(id.mailbox);
}
}
}
Since here, equality is only determined by the mailbox member, the hash code should also only be based on that member:
public int hashCode() {
return mailbox.hashCode();
}
Hashing of an object is established by overriding hashCode() method, which the developer can override.
Java uses prime numbers in the default hashcode calculation.
If the equals() and hashCode() method aren't implemented, the JVM will generate hashcode implicitly for the object (for Serializable classes, a serialVersionUID is generated).

What does equals(Object obj) do?

I´ve often found an equals method in different places. What does it actually do? Is it important that we have to have this in every class?
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (obj == null)
{
return false;
}
if (obj instanceof Contact)
{
Contact other = (Contact)obj;
return other.getFirstName().equals(getFirstName()) &&
other.getLastName().equals(getLastName()) &&
other.getHomePhone().equals(getHomePhone()) &&
other.getCellPhone().equals(getCellPhone());
}
else
{
return false;
}
}
It redefines "equality" of objects.
By default (defined in java.lang.Object), an object is equal to another object only if it is the same instance. But you can provide custom equality logic when you override it.
For example, java.lang.String defines equality by comparing the internal character array. That's why:
String a = new String("a"); //but don't use that in programs, use simply: = "a"
String b = new String("a");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
Even though you may not need to test for equality like that, classes that you use do. For example implementations of List.contains(..) and List.indexOf(..) use .equals(..).
Check the javadoc for the exact contract required by the equals(..) method.
In many cases when overriding equals(..) you also have to override hashCode() (using the same fields). That's also specified in the javadoc.
Different classes have different criteria for what makes 2 objects "equal". Normally, equals() returns true if it is the same Object:
Object a = new Object();
Object b = new Object();
return(a.equals(b));
This will return false, eventhough they are both "Object" classes, they are not the same instance. a.equals(a) will return true.
However, in cases like a String, you can have 2 different instances but String equality is based on the literal characters that make up those Strings:
String a = new String("example");
String b = new String("example");
String c = new String("another");
a.equals(b);
a.equals(c);
These are all different instances of String, but the first equals will return true because they are both "example", but the 2nd will not because "example" isn't "another".
You won't need to override equals() for every class, only when there is a special case for equality, like a class that contains 3 Strings, but only the first String is used for determining equality. In the example you posted, there could have been another field, description which could be different for 2 different "Contacts", but 2 "Contacts" will be considered equal if those 4 criteria match (first/last name, and home/cell phone numbers), while the description matching or not matching doesn't play into whether 2 Contacts are equal.
Aside from everything given by Bozho, there are some additional things to be aware of if overriding equals:
something.equals(null) must always return false - i.e. null is not equal to anything else. This requirement is taken care of in the second if of your code.
if it is true that something == something else, then also something.equals(something else) must also be true. (i.e. identical objects must be equal) The first if of your code takes care of this.
.equals SHOULD be symetric for non-null objects, i.e. a.equals(b) should be the same as b.equals(a). Sometimes, this requirement breaks if you are subclassing and overriding equals in the parent-class and in the subclass. Often equals contains code like if (!getClass().equals(other.getClass())) return false; that at least makes sure that a diffrent object type are not equal with each other.
If you override equals you also MUST override hashCode such that the following expression holds true: if (a.equals(b)) assert a.hashCode() == b.hashCode(). I.e. the hash code of two objects that are equal to each other must be the same. Note that the reverse is not true: two objects that have the same hash code may or may not be equal to each other. Ususally, this requirement is taken care of by deriving the hashCode from the same properties that are used to determine equality of an object.
In your case, the hashCode method could be:
public int hashCode() {
return getFirstName().hashCode() +
getLastName().hashCode() +
getPhoneHome().hashCode() +
getCellPhone().hashCode();
}
If you implement Comparable that compares two objects if they are smaller, larger, or equal to each other, a.compareTo(b) == 0 should be true if and only if a.equalTo(b) == true
In many IDEs (e.g. Eclipse, IntelliJ IDEA, NetBeans) there are features that generate both equals and hashCode for you, thereby sparing you of tedious and possibly error-prone work.
The equals method is used when one wants to know if two objects are equivalent by whatever definition the objects find suitable. For example, for String objects, the equivalence is about whether the two objects represent the same character string. Thus, classes often provide their own implementation of equals that works the way that is natural for that class.
The equals method is different from == in that the latter tests for object identity, that is, whether the objects are the same (which is not necessarily the same as equivalent).
It enables you to re-define which Objects are equal and which not, for example you may define that two Person objects as equal if the Person.ID is the same or if the Weight is equal depending on the logic in your application.
See this: Overriding the java equals() method quirk
By default, the Object class equals method invokes when we do not provide the implementation for our custom class. The Object class equals method compares the object using reference.
i.e. a.equals(a); always returns true.
If we are going to provide our own implementation then we will use certain steps for object equality.
Reflexive: a.equals(a) always returns true;
Symmetric: if a.equals(b) is true then b.equals(a) should also be true.
Transitive: If a.equals(b), b.equals(c) then a.equals(c) should be true/false according to previous 2 result.
Consistent: a.equals(b) should be the same result without modifying the values of a and b.
Note: default equals method check the reference i.e. == operator.
Note: For any non-null reference value a, a.equals(null) should return
false.
public class ObjectEqualExample{
public static void main(String []args){
Employee e1 = new Employee(1, "A");
Employee e2 = new Employee(1, "A");
// if we are using equals method then It should follow the some properties such as Reflexive, Symmetric, Transitive, and constistent
/*
Reflexive: a.equals(a) always returns true;
Symmetric: if a.equals(b) is true then b.equals(a) should also be true.
Transitive: If a.equals(b), b.equals(c) then a.equals(c) should be true/false according to previous 2 result.
Consistent: a.equals(b) should be the same result without modifying the values of a and b.
Note: default equals method check the reference i.e. == operator.
Note: For any non-null reference value a, a.equals(null) should return false
*/
System.out.println(e1.equals(e1));
System.out.println(e1.equals(e2));
}
}
class Employee {
private int id;
private String name;
#Override
public String toString() {
return "{id ="+id+", name = "+name+"} ";
}
#Override
public boolean equals(Object o) {
// now check the referenc of both object
if(this == o) return true;
// check the type of class
if(o == null || o.getClass() != this.getClass()) return false;
// now compare the value
Employee employee = (Employee)o;
if(employee.id == this.id && employee.name.equals(this.name)) {
return true;
} else return false;
}
public int hashCode() {
// here we are using id. We can also use other logic such as prime number addition or memory address.
return id;
}
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
One more thing, maps use the equals method to decide if an Object is present as a key. https://docs.oracle.com/javase/8/docs/api/java/util/Map.html

Categories

Resources