简体   繁体   中英

Java comparing class instances

I got this code:

public Class Car;
{
    private String name;  
    public int number;     


    public Car(String name, int number) 
    {
        this.name = name;
        this.number = number;
    }

    // this class also got getters and setters 

Then I got another class:

 public class CarList
    {
        private Collection<Car> cars;


        public CarList()
        {
            cars = new HashSet<>();
        }


       public boolean insertCar(Car car)
        {
            return cars.add(car); 
        }

Then code continues with some other methods but they are not problem. If I create two instances of class Car , for example car1(mazda,1) and car2(porsche,2) and then I call method insertCar , everything is OK, method returns true because there are two cars with different name and number.

But if create for example car1(mazda,1) and then car2(porsche,1) method returns also true despite the fact that numbers of the cars are the same.

EDIT:So my question is how to force method to return false when I try to ''add'' cars with the same number AND same name ( so how would @Override equals() method change )?

Firstly your Car class won't compile as it stands. Class should be class , and you have a semi-colon after Car . I would take it as SO mistake only.

For your task, you have to do following modification in your code:

  • Override equals() and hashCode() method in Car class, where you just consider number attribute for object comparison, and hashcode calculation.

     @Override public boolean equals(Object ob) { if (!ob instanceof Car) return false; Car that = (Car)ob; return this.number == that.number; } @Override public int hashCode() { return number; } 
  • In CarList class, instead of Collection<Car> use a Set<Car> . That will automatically take care of duplicates. Set#add(E) methods adds an element into the Set only if it doesn't exists (this is tested on the basis of equals and hashCode , that is why you need to override them). If the element already exists, then it doesn't modify the set, and return false , as you wanted. (Oops, missed that you are actually instantiating a HashSet only in your class. Better to rename the reference to Set<Car> ).


Related:

There are a few options for you and which is best depends on the usage scenario of your CarList class.

The most straight forward modification to your current code is going to be to add some code to the Add method to go through all the cars in the list and check whether another car with the same number already exists. If so then don't add and return FALSE.

But the above will have quadratic performance for inserts which would probably not be very good for you.

Instead, a much better alternative would be to use an extra data structure such as a HasSet of all the car numbers already in the list. And when adding, check the set for duplicates and if the number you're adding already exists return false.

HashSet<Integer> carNumbers = new HashSet<Integer>();
public boolean insertCar(Car car)
{
    if(!carNumbers.contains(car.getNumber()))
    {
        carNumbers.put(car.getNumber());
        return cars.add(car); 
    }

    return false;
}

You would need to override the equals method for Car . In that method provide the logic you would like to determine whether or not two objects are the same.

@override
public boolean equals(Car car) {
   return car.name == this.name && car.number == this.number;
}

Or whatever condition you would like the method to satisfy.

Suppose you're Java.

You're given two objects, and need to figure whether they're identical. One is Car at memory location 1000000, the other is Cat at 1200000. Look different. Done.

Java does one extra step though: "do the objects have equals() method?" If so, it gets called, and the object can itself decide whether it's equal to another. If it doesn't, falls back to "are they the same instance?"

So if you override equals() method, something like

@Override
public boolean equals(Object ob) {
  if (!(ob instanceOf Car)) { return false; }
  Car other = (Cat)ob;
  // decide whether they're equal and return true/false
}

Then that's a step in the right direction.

Second part is hashCode() . The contract is this:

if a1.equals(a2) then a1.hashCode()==a2.hashCode()

so, identical objects must produce the same hashcode. However, different objects may be producing the same hash code as well.

The HashSet answers will work, but they assume you'll never want two Cars with the same number and different name in any use case.

If you want to use this behaviour in only this use case (eg the number is unique inside a CarList, but not in general), you could use a TreeSet with a custom Comparator. As an additional feature, the list will automatically be sorted by the number.

cars = new TreeSet<>(new Comparator<>(){
    public int compare(Car a, Car b){
       return a.number - b.number;
    }
});

In this case, you don't need to implement equals() or hashCode().

Modify your class as follows: Car

public class Car {

private String name;
public int number;

public Car(String name, int number) {
    this.name = name;
    this.number = number;
}

@Override
public boolean equals(Object ob) {
    if (!(ob instanceof Car)) {
        return false;
    }
    Car car = (Car) ob;
    return this.number == car.number;
}

@Override
public int hashCode() {
    return number;
}
}

Car List

public class CarList {

private Set<Car> cars;

public CarList() {
    cars = new HashSet<Car>();
}

public boolean insertCar(Car car) {
    return cars.add(car);
}

}

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