John P
John P

Reputation: 1581

In a Java method that takes an Object argument, how can you access fields that only exist for instances of specific classes?

-- Yes, this is a question asking for help regarding something that was assigned as homework. No, this is not me asking you to do my homework for me. The deadline was a half an hour ago; I literally can't change my submission. You'll just have to take my word for it. Moving on...

I know that testing for the type of objects is supposed to be unnecessary. When I was looking for details about 'instanceof', I found a half dozen threads where people responded only to tell the original poster that they were making a mistake if they had to test to find out what kind of object they were dealing with before processing it. Yes, I know, I would love to follow the conventions. Unfortunately, my professor asked for us to override the equals method of a class we defined, and specifically required an Object type parameter. If you see my code, you'll probably understand better:

public boolean equals(Course other){
    if(!(other instanceof Course)){
        return false;
    } else if(other.name==this.name && other.days==this.days && 
        other.start==this.start && other.end==this.end){
        return true;
    }
    return false;
}

You can probably understand where I'm going with this. The 'other' parameter should be an Object type, but the program has a fit if I leave it as an Object and use the name / days / start / end fields. If I change it to Course, of course it works (no pun intended), but that would be a completely different method. The desired behavior is for all objects other than Course instances to make the method return false, and additionally, for mismatched data between Course instances to make it return false.

I'm sorry to all of you who know Java well enough to be frustrated by seeing questions like these.

Upvotes: 1

Views: 15935

Answers (4)

jabu.10245
jabu.10245

Reputation: 1892

If you want to override the "equals" method, you should use Object as a parameter, and thus you have to check for the object's type. Usually your own implementation would look like this:

@Override
public boolean equals(Object obj) {
    if (obj == this)
        return true;  // object's references are identical
    else if (!(obj instanceof Course))
        return false;

    Course that = (Course) obj;
    return (this.name.equals(that.name)) && (this.days == that.days)
        && (this.start.equals(that.start)) && (this.end.equals(that.end));
}

Of course you should override "hashCode" as well, using the same significant fields.


Instead, you overloaded the method with your own parameter of type Course. So if you call myobject.equals(anotherObject) and anotherObject is not of type Course, your "equals" method will never be called, instead the Object#equals method will be called, which does only the following: return this == obj.


The reason why overloading the "equals" method is not enough is the necessity to overload "hashCode" as well, which takes no parameters and thus cannot be overloaded.

  • If you write your own implementation of boolean equals(Object), you must also implement int hashCode()
  • Both methods should use the same significant fields for "hashCode" and "equals".
  • If a.equals(b) == true than the following must be also true: a.hashCode() == b.hashCode()
  • Also if a.hashCode() != b.hashCode() then a.equals(b) == false

The last point is the main reason why you should not just overload "equals" with your own type:

Course c1 = new Course("myname");
Course c2 = new Course("myname");
c1.equals(c2);                   // true
c1.hashCode() == c2.hashCode();  // false

Upvotes: 7

Alex Calugarescu
Alex Calugarescu

Reputation: 848

Your code :

 public boolean equals(Course other){
     if(!(other instanceof Course)){  <-- other can only be Course here
          return false;
     } else if(other.name==this.name && other.days==this.days && 
         other.start==this.start && other.end==this.end){
         return true;
      }
     return false;
  }

Correct code :

  public boolean equals(Object other){
     if(!(other instanceof Course)){
         return false;
     } else{ 
       Course c = (Course) other;
       if(c.name==this.name && c.days==this.days && 
          c.start==this.start && c.end==this.end){
         return true;
      }
     }
   } 
     return false;
  }

Upvotes: 0

SLaks
SLaks

Reputation: 888223

You're trying to cast it:

Cource c = (Course)other;

Upvotes: 0

LazyCubicleMonkey
LazyCubicleMonkey

Reputation: 1243

You can cast Object as Course:

Course course = (Course)object;

Then do all the comparisons on the course object. Obviously, still do the instanceof check before casting to avoid a ClassCastException.

Upvotes: 0

Related Questions