简体   繁体   中英

Comparing class with class instances without hashCode and equals

Is it possible to compare Class that contains some other class instances , that does not contain hashCode and equals

We have 3 classes : Car.java , SUV.java and TestFinal.java

Car.java (Simple POJO without hashCode and equals)

public class Car
{
  private long carId;
  private String manufacturer;

  public Car(long carId, String manufacturer)
  {
    super();
    this.carId = carId;
    this.manufacturer = manufacturer;
  }

  /**
   * @return The carId.
   */
  public long getCarId()
  {
      return carId;
  }

  /**
   * @param carId The carId to set.
   */
  public void setCarId(long carId)
  {
      this.carId = carId;
  }

  /**
   * @return The manufacturer.
   */
   public String getManufacturer()
   {
      return manufacturer;
   }

  /**
   * @param manufacturer The manufacturer to set.
   */
  public void setManufacturer(String manufacturer)
  {
      this.manufacturer = manufacturer;
  }
}

SUV.java (contain instance of car and contains hashCode and equals)

public class SUV {
    private Car car;

    /**
     * @return The car.
     */
    public Car getCar()
    {
        return car;
    }

    /**
     * @param car The car to set.
     */
    public void setCar(Car car)
    {
        this.car = car;
    }

    public SUV(Car car)
    {
        super();
        this.car = car;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode()
    {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((car == null) ? 0 : car.hashCode());
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if (obj == null)
        {
            return false;
        }
        if (getClass() != obj.getClass())
        {
            return false;
        }
        SUV other = (SUV) obj;
        if (car == null)
        {
            if (other.car != null)
            {
                return false;
            }
        }
        else if (!car.equals(other.car))
        {
            return false;
        }
        return true;
    } }

TestFinal is main class , where I am compare two SUV objects

public class TestFinal
{
    public static void main(String args[])
    {
        Car car1 = new Car(1, "Toyota");
        Car car2 = new Car(1, "Toyota");

        SUV suv1 = new SUV(car1);
        SUV suv2 = new SUV(car2);

        System.out.println(suv1.equals(suv2));
    }
}

Here

suv1.equals(suv2)

returns false , since Car does not contains overriding of equals and hashCode. Is there way I can update my Overriding logic of SUV without making changes in Car (like adding equals and hashCode) such that

suv1.equals(suv2)

returns true

Any inputs or suggestion would be valuable.

Thanks !!

For the equals logic, you could use a very ugly workaround: comparing the relevant properties of the Car objects that compose the two SUV objects you're comparing, manually.

Essentially:

if (other.car.getManufacturer().equals(car.getManufacturer())) etc.

I would still strongly advise against that - not to mention the trouble you'd get with hashCode !!

Another way that might suit is to remove Car s as relevant terms of comparison when implementing SUV 's both equals and hashCode , and decide that equality between two SUV s is not impacted by their Car s.

Finally: shouldn't SUV be a Car , rather then have a Car ?

Is there way I can update my Overriding logic of SUV without making changes in Car (like adding equals and hashCode)

Not really, since in your SUV.equals() method, you have

else if (!car.equals(other.car))
{
    return false;
}

And since car.equals() isn't overriden, it uses the Object.equals() which simply compares the objects for instance equality.

Well, you could replace that code with comparing each field from car individually, but do you really want to do that? It's ugly. Better to just override Car.equals() .

I have updated the class "SUV", I don't say it's ideal way but a workaround...

public class SUV {
    private Car car;

    /**
     * @return The car.
     */
    public Car getCar() {
        return car;
    }

    /**
     * @param car
     *            The car to set.
     */
    public void setCar(Car car) {
        this.car = car;
    }

    public SUV(Car car) {
        super();
        this.car = car;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((car == null) ? 0 : car.hashCode());
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        SUV other = (SUV) obj;
        if (car == null) {
            if (other.car != null) {
                return false;
            }
        } else if (!carEquals(car, other.car)) {
            return false;
        }
        return true;
    }

    private boolean carEquals(Car firstObj, Car otherObj){


        if(otherObj == null){
            return false;
        } else{
            if(firstObj.getCarId() == otherObj.getCarId() && firstObj.getManufacturer().equals(otherObj.getManufacturer())){
                return true;
            } else {
                return false;
            }
        }

    }
}

You can have your SUV class to implement Comparable Interface and then write your own logic to compare SUVs in your implementation of the method compareTo(T o) Also you can create a class that would implement Comapartor interface that compares SUVs with your own logic. Read about it in Javadoc: Comparable and Comparator . But it is an ugly workaround and implementing hashcode and equals definitely by far more preferrable

Using Comparator Interface also as below :

import java.util.Comparator;

public class CarComparator implements Comparator<Car>{

@Override
public int compare(Car o1, Car o2) {
    if(o1 == null || o2 == null){
        return -1;
    } else if(o1!=null && o2 == null){
        return -1;
    } else if(o1==null && o2!=null){
        return -1;
    } else{
        if(o1.getCarId() == o2.getCarId() && o1.getManufacturer().equals(o2.getManufacturer())){
            return 0;
        } else {
            return -1;
        }
    }
    
  }

}

Then for SUV Class :

package test.corejava.concepts;

public class SUV {
private Car car;

/**
 * @return The car.
 */
public Car getCar() {
    return car;
}

/**
 * @param car
 *            The car to set.
 */
public void setCar(Car car) {
    this.car = car;
}

public SUV(Car car) {
    super();
    this.car = car;
}

/**
 * {@inheritDoc}
 */
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((car == null) ? 0 : car.hashCode());
    return result;
}

/**
 * {@inheritDoc}
 */
@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    SUV other = (SUV) obj;
    if (car == null) {
        if (other.car != null) {
            return false;
        }
    } else if (new CarComparator().compare(car, other.car)!=0) {
        return false;
    }
    return true;
  }

}

Hope, this helps....

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM