When overriding an equals property for one of my classes is it possible to implement it as so? The properties in question such as identifier could be String, boolean, Date, Set, or LinkedHashSet
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
if (!compareProperty(identifier, other.getIdentifier())) return false;
//Continue for all properties
}
//Compares any two objects
private boolean compareProperty(Object sourceObject, Object testObject)
{
if (sourceObject == null)
{
if (testObject != null)
return false;
}
else if(!sourceObject.equals(testObject))
{
return false;
}
return true;
}
Why or why not?
This is indeed what should be done.
I wouldn't reinvent the wheel, though. Consider using Objects.equals (in Java 7), or Objects.equal (in Guava) or an EqualsBuilder (in apache commons-lang).
Related
I've a class A which is as follows:
A{
String name;
ArrayList<Bike> firstArray;
ArrayList<Cycle> secondArray;
// it's constructors and related methods are down lines.
}
and I have two instances of it named a_Obj and b_obj. I compare only the variable ,name inside object a_Obj with b_Obj using indexOf.
My question is how to call indexOf in this case and in other words how to tell the compiler that I just want to compare name of two objects regardless of ArrayLists declared inside the class A.
you can override equals() in your class
Given below is how indexOf has been implemented by default:
public int indexOf(Object o) {
ListIterator<E> it = listIterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return it.previousIndex();
} else {
while (it.hasNext())
if (o.equals(it.next()))
return it.previousIndex();
}
return -1;
}
By overriding the equals method in A to consider just the equality of name, you can make it happen.
Given below is the definition generated by Eclipse IDE:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
A other = (A) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
A shorter version for the same can be as follows:
#Override
public boolean equals(Object obj) {
if (obj == null)
return false;
A other = (A) obj;
return Objects.equals(name, other.name);
}
I have implemented hashCode() and equals() for an object using the default from NetBeans:
#Override
public int hashCode() {
int hash = 5;
hash = 37 * hash + this.unitSystemID;
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
LOGGER.debug(getClass().toString());
LOGGER.debug(this.getClass().getClassLoader().toString());
LOGGER.debug(obj.getClass().toString());
LOGGER.debug(obj.getClass().getClassLoader().toString());
if (getClass() != obj.getClass()) {
return false;
}
final UnitSystem other = (UnitSystem) obj;
if (this.unitSystemID != other.unitSystemID) {
return false;
}
return true;
}
At the logging check-points, I get:
units.UnitSystem - class
com.utilities.domain.units.UnitSystem
units.UnitSystem -
org.springframework.boot.devtools.restart.classloader.RestartClassLoader#42d353e2
units.UnitSystem - class
com.utilities.domain.units.UnitSystem_$$_jvst6b1_19ed
units.UnitSystem -
org.springframework.boot.devtools.restart.classloader.RestartClassLoader#42d353e2
The equality fails at that point and equals returns false.
What is the extra _$$_jvst6b1_19ed? Where does it come from?
From what I understand, the classes should be equal if they are from the same class loader, which these are. I have not had a problem with this implementation anywhere else I have used it. Why is getClass() returning different things?
Unless you actually subclass UnitSystem yourself, exact class matching isn't necessary, so replace
if (getClass() != obj.getClass()) {
return false;
}
with
if (! (obj instanceof UnitSystem)) {
return false;
}
You can't make UnitSystem class final since you want Hibernate to be able to create a subclass proxy, so you don't have absolute guarantee that UnitSystem won't be subclassed by non-Hibernate code, but is such an absolute guarantee really needed?
As #Andreas said in a comment it usually happens when the object has been fetched by a lazy loading. To get the initial object you should to unproxy it first. Here is an example of the unwrapper for a Hibernate
#SuppressWarnings("unchecked")
public static <T> T initializeAndUnproxy(T entity) {
if (entity == null) {
throw new InternalServerException("Entity passed for initialization is null");
}
T unproxy = entity;
Hibernate.initialize(entity);
if (isProxy(entity)) {
unproxy = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
return unproxy;
}
public static <T> boolean isProxy(T entity) {
return entity instanceof HibernateProxy;
}
How do I solve a cobertura branch coverage issue which is being reflected in a concrete method of an abstract class.
In the below snippet the equals method of the abstract class Currency contains a part where there is a check for the variables SID and Ab which comes after the condition
if (getClass() != obj.getClass()).
This part never gets covered
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
if (getClass() != obj.getClass())
return false;
final Currency other = (Currency) obj;
if (this.getAb() == null) {
if (other.Ab() != null)
return false;
} else if (!this.getAb().equals(other.getAb()))
return false;
if (this.getSID() < 1 || (this.getSID() != other.getSID()))
return false;
return true;
}
I tried to cover these variables in the test class using the below method but it still doesn't get covered:
Test class:
Currency currency = new Currency() {
#Override
public boolean equals(Object obj) {
return super.equals(obj);
}
};
Currency currency1 = new Currency() {
#Override
public boolean equals(Object obj) {
return super.equals(obj);
}
};
currency.setAb("SE3421");
currency1.setAb("SE3421");
assertFalse(currency.equals(currency1));
assertTrue((currency1.getAb()).equals(currency.getAb()));
Any help is appreciated.
I would add a new test method, such as this.
#test
public void test_equals() {
Currency currency = new Currency() { };
assertFalse(currency.equals(new String()));
}
One other comment: you should really implement the hashCode method as well.
In hashCode() it says: 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. If you only override equals() and not hashCode() your class violates this contract
I need to make equals function for MyClas.
public class MyClass
{
boolean equals(Object value)
{
if (... value is type of MyCLass ...)
{
return= ... check conditions...;
} else return false;
}
}
For this purpose I need to know if value of Object is type of MyClass. How to make it?
In order to check if value is of type MyClass use:
if( value instanceof MyClass)
instanceof operator is used to determine that. It's infix, so use it like so...
(value instanceof MyClass)
public class MyClass
{
boolean equals(Object value)
{
if (value instanceof MyCLass)
{
return= ... check conditions...;
} else return false;
}
}
You can do
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyClass myClass = (MyClass) o;
//Your logic
You can also use instanceof instead of getClass() approach.
Just a little IDE trick. Just to save up some time.
In eclipse you can do that by right click on the class file and select source --->generate hashCode() and equals() method , select all the attribute you need to compare and IDE will generate corresponding code for you
An excerpt
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (firstName == null) {
if (other.firstName != null)
return false;
} else if (!firstName.equals(other.firstName))
return false;
if (id != other.id)
return false;
if (lastName == null) {
if (other.lastName != null)
return false;
} else if (!lastName.equals(other.lastName))
return false;
if (salary != other.salary)
return false;
return true;
}
value instanceof ClassName
the instanceof key word checks, where value is a subclass of ClassName, If yes reutns true and otherwise returns false
Altough RTTI (Real Time Type Identification) is considered a code smell by some individuals, there are two alternatives, one is to use the instanceof operator:
if(value instanceof MyClass)
On the other hand, you can use a full fledged method from the Class class, that given two objects, you can determine if they belong to the same hierarchy (much more powerful than instanceof IMO):
if(value.getClass().isAsignableFrom(getClass()))
This second approach determines if value is the very same class or a superclass/superinterface of the current class (the this) at execution time given any kind of object. This is where isAsignableFrom excels, since with instanceof you need to know the reference type at compile time.
I let Eclipse generate the equals method for my class and it starts with:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (getClass() != obj.getClass())
return false;
[...]
It seems to me, a check like if (obj == null) return false; is missing. Otherwise, if a null reference is passed to equals there will be a null pointer exception in obj.getClass(). Am I wrong or is Eclipse wrong?
Perhaps you are having an old eclipse version. My eclipse generates this:
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
You are right, if Eclipse does it that way. But it doesn't. On my machine, Eclipse Indigo / Ubuntu, given this Class:
public class Foo {
private String bar;
}
Eclipse would generate the following equals() method:
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Foo other = (Foo) obj;
if (bar == null) {
if (other.bar != null) return false;
} else if (!bar.equals(other.bar)) return false;
return true;
}
For comparison, here's the equals() method I would write for the same class (using Guava):
#Override
public boolean equals(final Object obj) {
return obj instanceof Foo ? Objects.equal(bar, ((Foo) obj).bar) : false;
// ^--- implicit null check here
}
I use this Eclipse code template to achieve this:
${:import(com.google.common.base.Objects)}
#Override
public boolean equals(final Object obj){
return obj instanceof ${enclosing_type} ? Objects.equal(${field1:field}, ((${enclosing_type}) obj).${field1}) : false;
}
#Override
public int hashCode(){
return Objects.hashCode(${field1});
}
#Override
public String toString(){
return MoreObjects.toStringHelper(this).add("${field1}", ${field1}).toString();
}
Unfortunately, I have to keep one of these around for each cardinality of fields, so I have templates named eq1 (the above), eq2, eq3, eq4 etc. It's a small nuissance, but it's still a lot better than the monster methods generated by Eclipse.
Guava docs
Yes, passing null as obj would give a NullPointerException with that code.
You indeed need a null check. My version of Eclipse generates equals methods with a null check.
if (obj) is null, the obj.getClass() will throw an NPE
It seems to me, a check like if (obj == false) return false; is missing.
Why do you want to compare object with a Boolean value? ;-)
I suppose you though about obj == null check, and that is exactly what Eclipse generates in my case:
#Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TestGetClass other = (TestGetClass) obj;
if (id != other.id)
return false;
return true;
}
I am using 3.7 version. Anyway, you are right... actually Eclipse... too ;-)