I have a multitude of objects that are created with multiple instance variables (a string a multiple integers)
I have to create a method that will check for equality between the object that executes the method and another object. By that I mean that I would want to see whether all the instance variables are the same for two objects by calling a method. I'm thinking of something like the equals method (string1.equals(string2)), but can I do the same for an object with multiple instance variables which are not all strings?
example:
//object1
String name1= keyb.nextLine();
int age1= keyb.nextInt();
int monthborn1;
//object2
String name2=keyb.nextLine();
int age2 = keyb.nextInt();
int monthborn2;
I need to make a method that compare both objects and sees if they are equal or not.
Thank you very much.
Yes, you can create an equals method for your class. For example:
public final class Person {
private final String name;
private final int age;
private final int birthMonth;
public Person(String name, int age, int birthMonth) {
this.name = Objects.requireNonNull(name);
this.age = age;
this.birthMonth = birthMonth;
}
#Override
public boolean equals(Object o) {
if (o instanceof Person) {
Person rhs = (Person) o;
return name.equals(rhs.name)
&& age == rhs.age
&& birthMonth == rhs.birthMonth;
}
return false;
}
// Any time you override `equals`, you must make a matching `hashCode`.
// This implementation of `hashCode` is low-quality, but demonstrates
// the idea.
#Override
public int hashCode() {
return name.hashCode() ^ age ^ birthMonth;
}
}
In Java you usually have to manually check every field like this:
class MyObject {
String name;
int age, monthborn;
public boolean isEqual(MyObject other) {
return Objects.equals(name, other.name) &&
age == other.age && monthborn == other.monthborn;
}
}
Objects.equals is used here which is null-safe equivalent of name.equals(other.name). When you add new fields you will have to add new checks in your method as well. The alternative would be to utilize reflection, but it looks ugly and has significant performance drawback. Here's a draft example how to do this (do not take into account possible inheritance):
import java.lang.reflect.Field;
import java.util.Objects;
public class ObjectUtil {
public static <T> boolean allFieldsEqual(T o1, T o2) throws IllegalAccessException {
if(o1 == o2) return true;
if(o1.getClass() != o2.getClass()) return false;
for(Field field : o1.getClass().getDeclaredFields()) {
field.setAccessible(true);
if(!Objects.equals(field.get(o1), field.get(o2))) {
return false;
}
}
return true;
}
}
class MyObject {
String name;
int age, monthborn;
public boolean isEqual(MyObject other) {
try {
return ObjectUtil.allFieldsEqual(this, other);
} catch (IllegalAccessException e) {
return false;
}
}
}
This way upon adding the new field the isEqual method will take it into account as well. However I would not recommend such solution.
Please see this answer . Also, since you are overriding the equals method you should also override the hashcode method (also covered in the linked post)
Once you compare two objects you have to consider about all the members of the class.
We will assume that we have a class named B and with two member variables age and name.
class B :
public class B {
String name;
int age;
public B(String name, int age) {
this.age = age;
this.name = name;
}
}
Then lets compare the two different objects of same class using equals and hashcode methods which are inherited to our class B from Object class.
class A to compare :
public class A {
public static void main(String args[]){
B b1 = new B("a", 22);
B b2 = new B("a",22);
System.out.println(b1.equals(b2));
System.out.println(b1.hashCode());
System.out.println(b2.hashCode());
}
}
As soon as we compile and run class A we will get following out-puts.
false
705927765//returns int value
366712642//returns int value
But here in the class A we have passed same parameters to both objects of the B. Which means we are getting what we did not expect because of equals and hashcode methods which are in Object class not doing what we need.
So in this case we have to override these methods in our class B to make it success.
Class B after override done:
public class B {
String name;
int age;
public B(String name, int age) {
this.age = age;
this.name = name;
}
#Override
public boolean equals(Object obj) {
boolean flag = false;
if (obj instanceof B) {
B b = (B) obj;
if (this.age == b.age) {
if (this.name.charAt(0)==b.name.charAt(0))) {
flag = true;
} else {
flag = false;
}
} else {
flag = false;
}
} else {
flag = false;
}
return flag;
}
#Override
public int hashCode() {
return this.age+this.name.charAt(0);
}
}
If we run our class A again we could get follwing result :
true
119
119
Which means our work is done.
Related
I posted about this application yesterday, but now I'm having a different problem. I'm currently working on this application for tracking track (tracking track?) day runs and displaying a leaderboard. This is for a class so I'm not looking for code necessarily, just some thoughts on how to go about it. Anyway, the application currently will take input information (from the bottom textfields), create a TreeSet of RaceEntrant objects (class shown below), and create a queue on the right which is emptied as the participants go through their runs. The problem is, I need the TreeSet to be sorted in the (grey) leaderboard area from smallest to largest runTime and update while the times are entered at the top. I'm kind of unsure how to have it sort the objects specifically by the runTime. Any help is appreciated.
RaceEntrant Class
class RaceEntrant
{
private String name,
car;
private double runTime;
public RaceEntrant(String name, String car)
{
this.name = name;
this.car = car;
}
public String getName()
{
return name;
}
public String getCar()
{
return car;
}
public double getTime()
{
return runTime;
}
public void setTime(double time)
{
this.runTime = time;
}
#Override
public String toString()
{
StringBuilder sb = new StringBuilder("");
sb.append(getName());
sb.append(" ");
sb.append(getCar());
sb.append("\n" );
sb.append("Best time: " + getTime() + "\n");
return sb.toString();
}
}
This is an example of the current operation - the RaceEntrant(s) are displayed in order of their runs, not sorted by anything. I apologize for the lengthy post.
Your class, RaceEntrant, should implements Comparable, and you can control order in the implemented method compareTo.
Your class could look like this:
class RaceEntrant implements Comparable<RaceEntrant>
{
private final String name,
car;
private double runTime;
public RaceEntrant(final String name, final String car)
{
this.name = name;
this.car = car;
}
public String getName()
{
return name;
}
public String getCar()
{
return car;
}
public double getTime()
{
return runTime;
}
public void setTime(final double time)
{
this.runTime = time;
}
#Override
public String toString()
{
final StringBuilder sb = new StringBuilder("");
sb.append(getName());
sb.append(" ");
sb.append(getCar());
sb.append("\n" );
sb.append("Best time: " + getTime() + "\n");
return sb.toString();
}
#Override
public boolean equals(final Object obj) {
if(this == obj) return true;
if (obj instanceof RaceEntrant){
return (((RaceEntrant) obj).getTime() == runTime) && ((RaceEntrant) obj).getName().equals(name) && ((RaceEntrant) obj).getCar().equals(car);
}
return false;
}
#Override
public int hashCode() {
return new Double(runTime).intValue();
}
#Override
public int compareTo(final RaceEntrant o) {
return new Double(o.runTime).compareTo(this.runTime)*-1;
}
}
In your RaceEntrant class:
class RaceEntrant implements Comparable<RaceEntrant>{
//..
public int compareTo(RaceEntrant re){
return getTime().compareTo(re.getTime());
}
#Override //optional for Sets
public boolean equals(Object o){
If(o != null && o instanceOf RaceEntrant){
RaceEntrant entrant = (RaceEntrant)o;
return getName().equals(entrant.getName() &&
getCar().equals(entrant.getCar()) &&
getTime() == entrant.getTime();
}
}
}
Then you can sort your List (probably ArrayList) by runTime.
You could also use a TreeSet (this should be sorted automatically) and define a equals method on runTime + name + car if that's a possible approach.
I guess the TreeSet is not the right data structure. A TreeSet is above all a Set -- which keys are considered unique based on comparison.
I think you can have identical run times?
Maybe just use an ArrayList and sort it using Collections.sort() with a custom Comparator.
HashSet contains objects,I want to remove duplicates whose objects are having same id's
the following is the code..
Set<Employee> empSet=new HashSet<Employee>();
empSet.add(new Employee(1,"naresh"));
empSet.add(new Employee(2,"raj"));
empSet.add(new Employee(1,"nesh"));
empSet.add(new Employee(2,"rajes"));
//i saw in some blog that we can use hashCode equals method, but i don't how to use that in this context, please help me out
import groovy.transform.EqualsAndHashCode
#EqualsAndHashCode(includes='id')
class Employee {
int id
String name
}
You can remove constructors as well if #Canonical AST is used. Canonical also provides #EqualsAndHashCode, but to add the includes it has to be used separately again.
UPDATE
If the class is not modifiable and you have a list/hasSet then you can use unique with a closure to perform the uniqueness. Assuming the SolrDocument mentioned in comment is referred as Employee and you have the above HashSet with duplicate ids, then below should work:
empSet.unique { it.id } //this mutates the original list
empSet.unique( false ) { it.id } //this does not mutate the original list
Write equals and hashCode as shown below
public class Employee {
private int id;
private String name;
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
if (id != employee.id) return false;
return true;
}
#Override
public int hashCode() {
return id;
}
}
You need to override equals() method in your Employee class and it will be taken care of. Set uses the equals method to compare the objects inserted in the Set.
public class Employee
{
public boolean equals(Employee e)
{
/// logic to compare 2 employee objects
}
}
I would like an object to be comparable (to use it in a TreeSet in that case).
My object got a name field and I would like it to be sorted by alphabetical order.
I thought first that I could use the unicode value of the string and simply do a subtraction, but then AA would be after Ab for example…
Here’s how I started :
public final class MyObject implements Comparable<MyObject> {
private String name;
public MyObject(String name) {
this.name = name;
}
public String name() {
return name;
}
#Override
public int compareTo(MyObject otherObject) {
return WHAT DO I PUT HERE ?;
}
}
Thanks to those who will help,
have a nice day!
You are overthinking the problem. Strings have their own natural ordering, which is alphabetic, so you can just use the String.compareTo like this:
#Override
public int compareTo(MyObject otherObject) {
return this.name.compareTo(otherObject.name);
}
return name.compareTo(otherObject.name);
String already implements Comparable so you don't need do to anything.
I think you want something like this
package mine;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class MyObject {
private String name;
public MyObject(String name) {
this.name = name;
}
public MyObject() {
// TODO Auto-generated constructor stub
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "MyObject [name=" + name + "]";
}
public static void main(String[] args){
List<MyObject> l = new ArrayList<>();
l.add(new MyObject("Ab"));
l.add(new MyObject("AA"));
l.add(new MyObject());
Collections.sort(l, new Comparator<MyObject>(){
#Override
public int compare(MyObject o1, MyObject o2) {
if (o1.name == null && o2.name == null){
return 0;
}else if (o1.name == null){
return -1;
}else if (o2.name == null){
return 1;
}else{
return o1.name.toUpperCase().compareTo(o2.name.toUpperCase());
}
}
});
System.out.println(l);
}
}
Exist so many way which preferred before it. But for maintain better compatibility, performance and avoiding runtime exceptions (such as NullPointerException) use best practices which is
For String
#Override
public int compareTo(OtherObject o) {
return String.CASE_INSENSITIVE_ORDER.compare(this.name,o.name);
}
For int, double float (to avoid boxing and unboxing which issue for performance use below comparators)
// with functional expression
Comparator.compareInt, Comparator.compareDouble, Comparator.compareFloat
// or with static compare method
/**
* Integer
*/
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
/**
* Double
*/
public int compareTo(Double anotherDouble) {
return Double.compare(value, anotherDouble.value);
}
/**
* Float
*/
public int compareTo(Float anotherFloat) {
return Float.compare(value, anotherFloat.value);
}
/**
* Objects
*/
public int compareTo(Object other) {
return Object.compare(value, other.value);
}
[Effective Java Item 14: Consider implement Comparable]
Finally, whenever you implement a value class that has a sensible ordering, you should have a class implements Comparable interface so that its instances can be easily sorted, searched and used in comparison-based collections. When comparing field values in the implementations of the compareTo methods, avoid the use of the < and > operators. Instead, use the static compare methods in the boxed primitive classes or the comparator construction methods in the Comparator interface
I have the classes below:
public class Sample implements java.io.Serializable{
//POJO with two fields and getters/setters
private String name;
private Integer id;
//This POJO does not override equals() and hashCode()
}
public class B{
private Sample sample;
//here i need override hashcode and equals() based on **sample** property.
}
When i tried overriding equals() and hashCode() in the B class I got the error below in Eclipse.
The field type com.mypackage.Sample does not implement hashCode() and equals() - The resulting code may not work correctly.
Now how can I compare two B instances whether equals or not based on the Sample property?
I cannot modify Sample class.
are you looking something like following? Just try it, as from your question i think you want to compare contents of your Sample class also.
class Sample implements java.io.Serializable{
//POJO with two fields and getters/setters
private String name;
private Integer id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
//This POJO does not override equals() and hashCode()
}
public class Beta implements Comparable{
private Sample sample;
public Sample getSample() {
return sample;
}
public void setSample(Sample sample) {
this.sample = sample;
}
#Override
public int compareTo(Object o) {
if(!(o instanceof Beta)){
return -1;
}
}if(((Beta)o).getSample().getName().equals(this.sample.getName())){
return 0; // return true if names are equal
}
if(((Beta)o).getSample().getId().equals(this.sample.getId())){
//if name are notequal and IDs are equal, do what you need to do
}
return -1;
}
public static void main(String[] args) {
Beta b = new Beta();
Sample s = new Sample();
s.setId(10);
s.setName("Name1");
b.setSample(s);
Beta b2 = new Beta();
Sample s2 = new Sample();
s2.setId(20);
s2.setName("Name2");
b2.setSample(s2);
System.out.println(b2.compareTo(b));
Beta b3 = new Beta();
Sample s3 = new Sample();
s3.setId(10);
s3.setName("Name1");
b3.setSample(s3);
System.out.println(b3.compareTo(b));
}
}
Overriding approach
class Sample implements java.io.Serializable{
//POJO with two fields and getters/setters
private String name;
private Integer id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
//This POJO does not override equals() and hashCode()
}
public class Beta /*implements Comparable*/{
private Sample sample;
public Sample getSample() {
return sample;
}
public void setSample(Sample sample) {
this.sample = sample;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Beta other = (Beta) obj;
if ((this.getSample() == null) && (other.getSample() == null)){
return true;
}
if ((this.getSample().getId().equals(other.getSample().getId())) && (this.getSample().getName().equals(other.getSample().getName()))) {
return true;
}
return false;
}
#Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + (this.getSample().getName() != null ? this.getSample().getName().hashCode() : 0);
hash = 53 * hash + (this.getSample().getId() != null ? this.getSample().getId().hashCode() : 0);
return hash;
}
/* #Override
public int compareTo(Object o) {
if(!(o instanceof Beta)){
return -1;
}
if(((Beta)o).getSample().getId().equals(this.sample.getId()) && ((Beta)o).getSample().getName().equals(this.sample.getName())){
return 0;
}
return -1;
}*/
public static void main(String[] args) {
Beta b = new Beta();
Sample s = new Sample();
s.setId(10);
s.setName("Name1");
b.setSample(s);
Beta b2 = new Beta();
Sample s2 = new Sample();
s2.setId(20);
s2.setName("Name2");
b2.setSample(s2);
System.out.println(b2.equals(b));
Beta b3 = new Beta();
Sample s3 = new Sample();
s3.setId(10);
s3.setName("Name1");
b3.setSample(s3);
System.out.println(b3.equals(b));
}
If you don't explicitly override .equals(), they will be compared based solely off of their references (despite not having a equals(), every object inherits one from Object). If you only want B to be compared based off of Sample, then simply do the following:
#Override
public boolean equals(Object o)
{
if (o istanceof B)
{
return sample.equals(o.sample)
}
return false;
}
Additionally, you should then override hashCode() (and compareTo()) to maintain the contract between equals() and hashCode(). Hence, you should also have the following:
#Override
public int hashCode()
{
return sample.hashCode();
}
EDIT (in response to comment):
My requirement is first i need to check equals property against "name"
property of Sample. IF names are equals then both objects are equal.
If names are not equals then i need to check for equality against "ID"
property of Sample. How can i do that? Thanks!
Determining whether Samples are equivalent should be handled in Sample, by overriding equals(). If equals() for Sample bases off of name and id, then you're fine. If you want to compare Samples in B differently than they are normally compared, then you're not going to be able to maintain the contract between equals() and hashCode() for B if you use hashCode() or equals() from Sample, which means that your hashCode() and equals() for B should be cannot call equals() or hashCode() from Sample. See this tutorial for how to override based on specific fields.
Let's say I created an instance in Java of a class Person
public class Person
{
private String name;
private int age;
// lot of other member variables
// get set here
}
How to know whether this instance at least have one of member variables being set (without checking all of the variables one by one?
For example :
Person person = new Person();
Person person1 = new Person();
person1.setName("John");
I need to know that person instance has not set any variables. However person1 has set at least one variable.
What I can think for solving this is to
create boolean flag that being changed to true in every set method, or
create a method that checking the variables one by one.
But I wonder if there's some way that more elegant to do this.
This is one way to get this done (not recommended for production because it doesn't check well for javabean style variables).
With this you only have to call
Helper.hasSomethingBeenSetted
with the object as parameter.
package com.intellij.generatetestcases.javadoc;
import java.lang.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.regex.*;
import static com.intellij.generatetestcases.javadoc.Person.Helper.hasSomethingBeenSetted;
public class Person {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private String name;
private int age;
// lot of other member variables
// get set here
public static void main(java.lang.String[] args) throws InvocationTargetException, IllegalAccessException {
Person person = new Person();
System.out.println("has been set something: " + hasSomethingBeenSetted(person));
Person person1 = new Person();
person1.setAge(3);
System.out.println("has been set something: " + hasSomethingBeenSetted(person1));
Person person2 = new Person();
person2.setName("john");
System.out.println("has been set something: " + hasSomethingBeenSetted(person2));
}
public static class Helper {
public static boolean hasSomethingBeenSetted(Person person) throws IllegalAccessException, InvocationTargetException {
// TODO get all javabean style attributes
// TODO flag to indicate something has been set, false by default
boolean somethingSetted = false;
Class<? extends Person> aClass = person.getClass();
Method[] methods = aClass.getMethods();
for (Method method : methods) {
if (method.getDeclaringClass().equals(aClass) && method.getModifiers() == Modifier.PUBLIC) {
Matcher matcher = Pattern.compile("get(\\p{Lu}[a-zA-Z]*)").matcher(method.getName());
if (matcher.find()) {
// assuming there is a getter FIXME check manually this
Object value = method.invoke(person);
if (value != null) {
Class<? extends Object> clazz = value.getClass();
if (isWrapperType(clazz)) {
if (clazz.equals(Boolean.class)) {
if (DEFAULT_BOOLEAN != (Boolean) value) {
somethingSetted = true;
}
} else if (clazz.equals(Byte.class)) {
if (DEFAULT_BYTE != (Byte) value) {
somethingSetted = true;
}
} else if (clazz.equals(Short.class)) {
if (DEFAULT_SHORT != (Short) value) {
somethingSetted = true;
}
} else if (clazz.equals(Integer.class)) {
if (DEFAULT_INT != (Integer) value) {
somethingSetted = true;
}
} else if (clazz.equals(Long.class)) {
if (DEFAULT_LONG != (Long) value) {
somethingSetted = true;
}
} else if (clazz.equals(Float.class)) {
if (DEFAULT_FLOAT != (Float) value) {
somethingSetted = true;
}
} else if (clazz.equals(Double.class)) {
if (DEFAULT_DOUBLE != (Double) value) {
somethingSetted = true;
}
}
} else {
somethingSetted = true;
}
}
}
}
}
return somethingSetted;
}
private static final HashSet<Class<?>> WRAPPER_TYPES = getWrapperTypes();
public static boolean isWrapperType(Class<?> clazz) {
return WRAPPER_TYPES.contains(clazz);
}
private static HashSet<Class<?>> getWrapperTypes() {
HashSet<Class<?>> ret = new HashSet<Class<?>>();
ret.add(Boolean.class);
ret.add(Character.class);
ret.add(Byte.class);
ret.add(Short.class);
ret.add(Integer.class);
ret.add(Long.class);
ret.add(Float.class);
ret.add(Double.class);
ret.add(Void.class);
return ret;
}
private static boolean DEFAULT_BOOLEAN;
private static byte DEFAULT_BYTE;
private static short DEFAULT_SHORT;
private static int DEFAULT_INT;
private static long DEFAULT_LONG;
private static float DEFAULT_FLOAT;
private static double DEFAULT_DOUBLE;
}
}
I would say we should have a state checking method on the Person class which should be called just before you use the Person instance (as a mechanism to filter data from database). In-fact it might be a good idea to set up a separate class to handle this(not use person), which can be used for other entities too. This class can then evolve (can be extended) to handle checking if we need different logic for different entities.