Overriding equals: Telling IDE its okay to have different values? - java

Suppose, I have a Class, call it Student. The student class has an element, an int called Id. I want to override equals, so that if a Student is compared to an Integer the method returns true. like:
public class OverrideTest {
public static void main(String[] args) {
Student a = new Student();
a.setId(5);
System.out.println(a.equals(5));
}
public static class Student {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Override
public boolean equals(Object o) {
if (o instanceof Student) {
Student a = (Student) o;
if (a.getId() == this.getId())
return true;
}
if (o == this)
return true;
if (o instanceof Integer) {
int id = (Integer) o;
if (id == this.getId())
return true;
}
return false;
}
}
}
Is there a way to signal the IDE that this is okay and no warnings have to be sent?
This returns true, but with a syntax warning in IDE.

As Yshavit noted, while you can do what you're trying to do, it's extremely dangerous because it breaks the symmetry of the .equals(...) relation. For example, consider:
Student s = new Student(5);
Integer i = new Integer(5);
if(s.equals(i)) System.out.println("s equals i");
else System.out.println("s doesnt equal i");
if(i.equals(s)) System.out.println("i equals s");
else System.out.println("i doesnt equal s");
Output:
s equals i
i doesnt equal s
Logically this doesn't make any sense. There is probably a way to convince your IDE to ignore the warning here, but you should almost certainly heed it and not make Students able to equal Integers.
The equals(..) method is used internally in containers such as HashSets, so this method would cause have erratic behavior in built-in structures.
More about overriding equals(...)

Related

When trying to overwrite a equals method in Java, it won't compare the values only the object itself?

In this exercise, I need to create a equals() method for a Drink class. Two drinks are the same if they have the same name and same size. I am receiving false from testing the method, even though I'm certain it should be true.
The main code:
public class Drink {
private String name;
private double size;
public Drink(String name, double size)
{
this.name = name;
this.size = size;
}
public String getName()
{
return name;
}
public double getSize()
{
return size;
}
//I tried to stringify the double values
public boolean equals(Drink a, Drink b){
String q = String.valueOf(a.getSize());
String w = String.valueOf(b.getSize());
if(q.equals(w) && a.getName().equals(b.getName())){
return true;
}
else{
return false;
}
}
}
The tester Code:
public class DrinkTester
{
public static void main(String[] args)
{
Drink one = new Drink("Soda", 12);
Drink two = new Drink("Soda", 12);
Drink three = new Drink("Soda", 20);
System.out.println(one.equals(two));
System.out.println(one.equals(three));
}
}
You need to override the equals method, if you use the
#Override annotation you'll see if you're doing it right.
public boolean equals(Object obj) {
return (this == obj);
}
That is the Object one, so yours might for example look like:
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Drink drink = (Drink) obj;
return this.size.equals(drink.size)
&& this.name.equals(drink.name);
}
you'll also have to override your hashCode if you want your code to work optimally.
(And i've only recently noticed that if you use Objects.hash in your overridden hashCode method, your overridden equals method won't get used, the Objects one will get used instead)

Comparing object in Java

Here is my application
public class testwithmain {
public static void main(String[]args)
{
Money m12CHF = new Money(12,"CHF");
System.out.println(m12CHF.amount());
Money m14CHF = new Money(14,"CHF");
System.out.println(m14CHF.amount());
Money expected = new Money(26,"CHF");
System.out.println("expected "+expected.amount()+expected.currency());
Money result = m12CHF.add(m14CHF);
System.out.println("result "+result.amount()+result.currency());
System.out.println(expected.equals(result));
}
}
//-------------------------
public class Money {
private int fAmount;
private String fCurrency;
public Money(int amount, String currency) {
fAmount = amount;
fCurrency = currency;
}
public int amount() {return fAmount;}
public String currency() {return fCurrency;}
public Money add(Money m) {
return new Money(amount() + m.amount(), currency());
}
}
The result is:
12
14
expected 26CHF
result 26CHF
false
Please, why i have false ?
Thank you so much.
Your Money class lacks an implementation of equals method, which is required in order for Java to know that the object representing the result of m12CHF.add(m14CHF) and the new Money(26,"CHF") represent the same thing, even though the two are distinct Java objects.
The code inside equals should follow this general template:
#Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Money)) {
return false;
}
Money other = (Money) o;
... // Your code goes here
}
#Override
public int hashCode() {
return Objects.hash(fAmount, fCurrency);
}
Your implementation needs to compare fAmount and fCurrency of your object to the values in other.fAmount and other.fCurrency. Use equals for comparison of String objects; numbers can be compared with == operators.
As Nexevis said you need to override the equals method (which is inherited from the object class)
#Override
public boolean equals(Object obj){
if(obj instanceof Money){
Money other = (Money)obj;
//now you define when two intance object of Money are equal...
}
//...
}
Why is this necessary?
Because the current equals that you are using it is the equals from the Object class. Object's equals method defines that two objects are the same when they have the same reference

Integer string compare to string in Java

I have declared a class implementing comparable interface and compareTo method comparing two employees using employee id. Created class objects inserted into array list. Now When I use Collections.sort(arrayList Object) it is working fine.I have a confusion in how the comparison differs between comparable and comparator interface.I want to know how comparison happens between a employee id string which purely consists of numbers and other string employee id which has few characters and numbers using both the inerface.
class Velraj implements Comparable<Velraj>{
String id;
String work;
public Velraj(String id, String work){
this.id = id;
this.work = work;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getWork() {
return work;
}
public void setWork(String work) {
this.work = work;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((work == null) ? 0 : work.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Velraj other = (Velraj) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (work == null) {
if (other.work != null)
return false;
} else if (!work.equals(other.work))
return false;
return true;
}
public int compareTo(Velraj o) {
// TODO Auto-generated method stub
return this.getWork().compareTo(o.getWork());
}
}
public class AppMain {
public static void main(String[] args) {
Velraj v1 = new Velraj("16450","Security Specialist");
Velraj v2 = new Velraj("245591","Consultant");
Velraj v3 = new Velraj("RNJIV3664","Java Architecct");
ArrayList<Velraj> a = new ArrayList<Velraj>();
a.add(v1);
a.add(v2);
a.add(v3);
Collections.sort(a);
/*Collections.sort(a, new Comparator<Velraj>(){
public int compare(Velraj o1, Velraj o2) {
// TODO Auto-generated method stub
return o1.getId().compareTo(o2.getId());
}
});*/
for(Velraj v: a){
System.out.println(v.getId() +"--> " +v.getWork());
}
}
}
Output using comparable:
245591--> Consultant
RNJIV3664--> Java Architecct
16450--> System Security Specialist
Output using comparator:
16450--> System Security Specialist
245591--> Consultant
RNJIV3664--> Java Architecct
Comparison of Strings uses lexicographic order, also known as alphabetical order. That is, order by the first character, and if the first character is equal look at the second character and so on.
The individual characters are ordered according to their character code. Basically digits < upper case letters < lower case letters.
The reason you are getting different results when using Comparable and Comparator is because you are comparing on different properties in both cases!
In the overridden compareTo method of your class, you have specified that objects should be sorted based on the work property ofVelraj class. But in compare method in your main function, you have specified that objects be sorted on id field of Velraj. If you use the same property in both cases, then you'd have gotten identical result on sort.

Why does contains value return false?

Please don't mind the my convention mistakes
class test implements Comparable<test>
{
int id;
String name;
public test(int id,String name)
{
this.id=id;
this.name=name;
}
#Override
public int compareTo(test o) {
if(this.id>o.id)
return 1;
else if(this.id==o.id)
return 0;
else
return -1;
}
}
class le
{
public static void main(String[] args) {
TreeMap<test,test> p=new TreeMap<test,test>();
p.put(new test(1,"sad"), new test(3121, "adweq"));
p.put(new test(2, "asds"),new test(3123,"awdq"));
p.put(new test(23,"akjdb"),new test(23123,"dqWQDD"));
Set<Map.Entry<test,test>> s=p.entrySet();
Iterator <Map.Entry<test, test>> i=s.iterator();
while(i.hasNext())
{
Map.Entry<test, test> m=i.next();
System.out.println(m.getKey().id);
System.out.println(m.getValue().name);
}
System.out.println(p.containsKey(new test(1,"sad")));//returning true
System.out.println(p.containsValue(new test(3123,"awdq")));//why it is returning false
}
}
here i have made a treemap,and wanted to know why does in containsvalue method it return false? whereas i have implemented comparable interface>
a compareTo() method is not enough - you need to implement an equals() method (and is recommended to also override hashCode() when you override equals()). Here's how:
class test implements Comparable<test>
{
int id;
String name;
public test(int id,String name)
{
this.id=id;
this.name=name;
}
#Override
public int compareTo(test o) {
if(this.id>o.id)
return 1;
else if(this.id==o.id)
return 0;
else
return -1;
}
#Override
public boolean equals(Object o) {
if (o == null)
return false;
if(!this.getClass().equals(o.getClass())
return false;
test that = (test) o;
return this.compareTo(that) == 0;
}
#Override
public int hashCode() { return id; }
}
Side note
Why does equals() use getClass().equals(o.getClass()) rather than (o instanceof test)?
Let us assume there is a subclass of the test class called test2 and that t1 and t2 are objects of type test, test2 (respectively).
If test2 overrides equals() then t1.equals(t2) can yield different result than t2.equals(t1) if equals() in test were implemented using instanceof. This violates the equals() contract (specifically, the symmetric requirement).
Because your class test doesn't override equals() and hashCode(), something like
#Override
public boolean equals(Object o) {
if (o instanceof test) {
test t = (test) o;
return t.id == o.id;
}
return false;
}
#Override
public int hashCode() {
return Integer.valueOf(id).hashCode();
}
Assuming that id equality is sufficient. Additionally, test is a poor class name. The Java naming convention would be Test but that's also a poor name. Maybe, EqualityTest (so it has some meaning).
You need to override Object.equals in your Test class in order to check for equality between new test(3123,"awdq") and another instance of new test(3123,"awdq").
It is also recommended to override Object.hashCode when overriding equals.

How to implement hashCode and equals method

How should I implement hashCode() and equals() for the following class in Java?
class Emp
{
int empid ; // unique across all the departments
String name;
String dept_name ;
String code ; // unique for the department
}
in Eclipse right mouse click-> source -> generate hashCode() and equals() gives this:
/* (non-Javadoc)
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (code == null ? 0 : code.hashCode());
return result;
}
/* (non-Javadoc)
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Emp))
return false;
Emp other = (Emp) obj;
return code == null ? other.code == null : code.equals(other.code);
}
I've selected code as a unique field
try this code, use org.apache.commons.lang3.builder
public int hashCode() {
return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
append(empid).
append(name).
append(dept_name ).
append(code ).
toHashCode();
}
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof Person))
return false;
Emp rhs = (Emp) obj;
return new EqualsBuilder().
// if deriving: appendSuper(super.equals(obj)).
append(name, rhs.name).
isEquals();
}
Guava has helper methods for creating them. You tell it which fields to take in consideration and it will handle nulls for you and do the prime number calculation for hashcode.
IDEs can also generate them based on the fields you choose.
The advantage of delegating it to a tool like that is you get a standard solution and will worry less about bugs and maintenance of varied implementations spread all over your project.
Here's an example of using Guava and generated by an IntelliJ plugin: https://plugins.jetbrains.com/plugin/7244?pr=
If code is unique (i.e. your business key), it's best to only use the code for equals and hashCode - it's good practice to seperate business key (code) from object id (id).
Here's a nice read: Hibernate Documentation: Equals and HashCode (valid not only for Hibernate itself)
what ever values you use in equals to determine if two objects are the same, are the the values that you need to use to create a hash code.
public boolean equals(Object o) {
boolean result = false;
if(o instanceof CategoryEnum) {
CategoryEnum ce = (CategoryEnum) o;
result = ce.toString().equals(name);
}
return result;
}
public int hashCode()
{
int hash = 6;
hash += 32 * name.hashCode();
return hash;
}
equals()and hashcode(),They have a lot of different places.
equals(),if we don't Override it from Object,it represent that whether two variables are pointing to the same object heap?
public Class Student(){
private int id;
private name;
public Student(int id,String name){
this.name=name;
this.id=id;
}
public void main(String[] args){
Student A=new Student(20,'Lily');
Student B=new Student(20,'Lily');
boolean flag=A.equals(B)//flag=flase;
/*
*Although they attribute the same, but they are two different objects, they point to different memory
*/
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (this.getClass() != obj.getClass()) {
return false;
}
Student s=(Student)obj;
return new Integer(this.id).equals(new Integer(s.id))&&this.name.equals(s.name);
}
/**
*Sometimes even though we Override the equals, but we still can not determine whether the *two objects the same,
*In the collection object, such as HashSet, this time we have to Override the hashoCode ()
*/
public int hashCode(){
return id + name.hashCode() ;
}

Categories