Showing posts with label equality. Show all posts
Showing posts with label equality. Show all posts

Saturday, 14 May 2011

equals() vs ==

Object class has a default method which looks like this :

public boolean equals(Object other)
{
return this==other;
}


== tests identity of the object, i.e. whether the 2 references are pointing the same object or not.

The default implementation of equals() is based on the == operator: Two objects are equal if and only if they are the same object. Naturally, most classes should define their own alternative implementation of this important method.

Steps that need to be taken into consideration while implementing equals method

  1. Use the == operator to check whether the incoming object is null. Its kind of performance optimization.
    public boolean equals(Object incomingObject) {
    if (incomingObject == null) return false;
    }


  2. Use the == operator to check if the argument is a reference to this object. If so, return true. This is just a performance optimization, but one that is worth doing if the comparison is potentially expensive.

    public boolean equals(Object incomingObject){
    if(this==incomingObject)
    return true;
    }


  3. Use the instanceof operator to check if the argument has the correct type.
    If not, return false. Typically, the correct type is the class in which the method occurs. Occasionally, it is some interface implemented by this class. Use an interface if the class implements an interface that refines the equals contract to permit comparisons across classes that implement the interface. Collection interfaces such as Set, List, Map, and Map.Entry have this property.

    public boolean equals(){
    if (!(incomingObject instanceof MyClass)) return false;
    }

    Note  : I have not checked like this:

    if(incomingObject instanceof MyClass)
    do something;

    The reason being instanceof returns true even when incomingObject is subclass object. So its important to check whether the object is type of class we are writing equals or not. If not, what is the point of writing further logic. Just return false, and leave.

  4. Cast the argument to the correct type. Because this cast was preceded by an instanceof test, it is guaranteed to succeed.

    public boolean equals(Object incomingObject){
    MyClass mc = (MyClass) incomingObject;
    }



  5. For each “significant” field in the class, checks if that field of the argument matches the corresponding field of this object. If all these tests succeed, return true; otherwise, return false


  6. When you are finished writing your equals method, ask yourself three questions: Is it symmetric? Is it transitive? Is it consistent?

Writing the complete equals function


Finishing whole steps:


public boolean equals(Object o) {
if (o == null) return false;
if (o == this) return true;
if (!(o instanceof MyClass)) return false;
MyClass mc = (MyClass) o;
return ... // compare members of mc
}

Sunday, 1 May 2011

equals() method on array

The equals method is not overloaded for arrays which means that:

int[]a = new int[]{1};
int[]b = new int[]{1};
System.out.println(a.equals(b));


Output:
false


As array is not value based, this was bound to happen. Here equals() method Object class that will be called and we know that this version of equals() method checks for the object references and not the values hence false.

Saturday, 30 April 2011

Immutable Objects / Wrapper Class Caching

Since Java 5, wrapper class caching was introduced.
The following is an examination of the cache created by an inner class, IntegerCache, located in the Integer cache. For example, the following code will create a cache:
Integer myNumber = 10; or Integer myNumber = Integer.valueOf(10);

256 Integer objects are created in the range of -128 to 127 which are all stored in an Integer array. This caching functionality can be seen by looking at the inner class, IntegerCache, which is found in Integer:
private static class IntegerCache 
{
private IntegerCache(){}

static final Integer cache[] = new Integer[-(-128) + 127 + 1];

static
{
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
}

public static Integer valueOf(int i)
{
final int offset = 128;
if (i >= -128 && i <= 127) // must cache
{
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}


So when creating an object using Integer.valueOf or directly assigning a value to an Integer within the range of -128 to 127 the same object will be returned. Therefore, consider the following example:

Integer i = 100;
Integer p = 100;
if (i == p)
System.out.println("i and p are the same.");
if (i != p)
System.out.println("i and p are different.");
if(i.equals(p))
System.out.println("i and p contain the same value.");

The output is:
i and p are the same.
i and p contain the same value.


So this result is similar to the result as shown here for strings.

It is important to note that object i and p only equate to true because they are the same object, the comparison is not based on the value, it is based on object equality. If Integer i and p are outside the range of -128 or 127 the cache is not used, therefore new objects are created. When doing a comparison for value always use the “.equals” method. It is also important to note that instantiating an Integer does not create this caching. So consider the following example:

Integer i = new Integer (100);
Integer p = new Integer(100);
if(i==p)
System.out.println(“i and p are the same object”);
if(i.equals(p))
System.out.println(“ i and p contain the same value”);


In this circumstance, the output is only: i and p contain the same value

The other wrapper classes (Byte, Short, Long, Character) also contain this caching mechanism OR constant pooling mechanism. The Byte, Short and Long all contain the same caching principle to the Integer object. The Character class caches from 0 to 127. The negative cache is not created for the Character wrapper as these values do not represent a corresponding character. There is no caching for the Float object.

BigDecimal also uses caching but uses a different mechanism. While the other objects contain a inner class to deal with caching this is not true for BigDecimal, the caching is pre-defined in a static array and only covers 11 numbers, 0 to 10:

 
// Cache of common small BigDecimal values.
private static final BigDecimal zeroThroughTen[] = {
new BigDecimal(BigInteger.ZERO, 0, 0),
new BigDecimal(BigInteger.ONE, 1, 0),
new BigDecimal(BigInteger.valueOf(2), 2, 0),
new BigDecimal(BigInteger.valueOf(3), 3, 0),
new BigDecimal(BigInteger.valueOf(4), 4, 0),
new BigDecimal(BigInteger.valueOf(5), 5, 0),
new BigDecimal(BigInteger.valueOf(6), 6, 0),
new BigDecimal(BigInteger.valueOf(7), 7, 0),
new BigDecimal(BigInteger.valueOf(8), 8, 0),
new BigDecimal(BigInteger.valueOf(9), 9, 0),
new BigDecimal(BigInteger.TEN, 10, 0),
};


As per Java Language Specification(JLS) the values discussed above are stored as immutable wrapper objects. This caching has been created because it is assumed these values / objects are used more frequently.

String equality and interning in java

Strings in Java are objects, but resemble primitives (such as ints or chars) in that Java source code may contain String literals, and Strings may be concatenated using the “+” operator. These are convenient features, but the similarity of Strings to primitives sometimes causes confusion when Strings are compared.

As we saw here, how java deals with string comparisons. Lets understand the case 2, where == operator returns true for 2 different references having same values.
To save memory (and speed up testing for equality), Java supports “interning” of Strings. When the intern() method is invoked on a String, a lookup is performed on a table of interned Strings. If a String object with the same content is already in the table, a reference to the String in the table is returned. Otherwise, the String is added to the table and a reference to it is returned. The result is that after interning, all Strings with the same content will point to the same object. This saves space, and also allows the Strings to be compared using the == operator, which is much faster than comparison with the equals(Object) method.

Confusion can arise because Java automatically interns String literals. This means that in many cases, the == operator appears to work for Strings in the same way that it does for ints or other primitive values. Code written based on this assumption will fail in a potentially non-obvious way when the == operator is used to compare Strings with equal content but contained in different String instances.
Following test cases show how interning can be performed by java:
Consider following string i.e “A String":
 
String aString = "A String"; 



Case 1: Concatenated string


String aConcatentatedString = "A" + " " + "String";


aString == aConcatentatedString       : true
aString.equals(aConcatentatedString) : true

Case 2: Runtime string




String aRuntimeString = new String("A String");


aString == aConcatentatedString       : false
aString.equals(aConcatentatedString) : true


Case 3: Interned string


String anInternedString = aRuntimeString.intern();

aString == aConcatentatedString : true
aString.equals(aConcatentatedString) : true



Case 4: External strings , eg. 1st argument of main method


String firstArg = args[0];


aString == aConcatentatedString : false
aString.equals(aConcatentatedString) : true


Case 5: Using intern on external strings


String firstArgInterned = firstArg.intern();

aString == aConcatentatedString : true
aString.equals(aConcatentatedString) : true




So we can see that explicitly invoking intern() returns a reference to the interned String.

Similar to string, there is a pool of integers, bytes, etc and other value based classes like bigdecimal. See here for more on this.

== vs equals method in case of String and primitive types

Object equality is tested using == operator. Here it is checked whether 2 references are pointing to same object or not.
While value equality is tested using the .equals(Object) method.
So consider following code snippet:
String one = new String("abc");
String two = new String("abc");


So here

one==two is false

one.equals(two) is true

one==two, because we are creating 2 new objects as specified by new keywords. But as their values are same one.equals(two) returns true because values are same.

Now if we say:

String three = one;



Now both one==two as well one.equals(two) returns true.

Using new keyword vs not using it to create 2 strings


Now consider 2 cases, when we create 2 strings with same value, but first using new keyword and then not using new keyword:

Case1 : Using new keyword:

String data = new String("123");
String moreData = new String("123");



Here data==moreData is false.

Case 2 : Not using new keyword:

String letters = "abc";
String moreLetters = "abc";


Here data==moreData is true.

Why?

Explaining the case 1 is very simple. Because it falls inline with our earlier explanation of == and != operators. But how can we explain case 2, where string comparison using == operator, returns true.

This is due to the compiler and runtime efficiency. In the compiled class file only one set of data "abc" is stored, not two. In this situation only one object is created, therefore the equality is true between these object. Read here for more on this. Not only strings , compiler also support this type of constant pooling for integers, bytes and other value types. See here for this.


Note:

Even though one set of data "123" is stored in the class, this is still treated differently at runtime. An explicit instantiation is used to create the String objects. Therefore, in this case, two objects have been created, so the equality is false. It is important to note that "==" is always used for object equality and does not ever refer to the values in an object. Always use .equals when checking looking for a "meaningful" comparison.

equals() for String, StringBuilder and StringBuffer

Rule of equality in java:

Equals method should be used for checking the logical equality of objects of a class but it does not mean that every class is a candidate for overridden equals method

So if you go and see the source code of StringBuffer/StringBuilder classes in Java, you will find that equals() method is not overridden but it is overridden in the String class.

public class Test{

public static void main (String args[]) {
String str1 = "abcd";
String str2 = "abcd";
System.out.println(str1.equals(str2));

StringBuffer sb1 = new StringBuffer(str1);
StringBuffer sb2 = new StringBuffer(str1);
System.out.println(sb1.equals(sb2));
}
}

Output:

true
false


For String objects, the logical equality would mean the contents of the string should be same.

For StringBuffer and StringBuilder we have following facts:
  • Logical equality means that both objects were configured and assembled using the same String instance and not whether the contents of those String objects is same.
  • The intended use of StringBuffer and StringBuilder is for maintaining a buffer of characters which may change with time.
Both the above statements contradict with each other because the String object being used for building a StringBuffer/StringBuilder object can change very frequently and it does not make any sense to compare the StringBuffer/StringBuilder objects.

This is the reason that the equals() method is not overridden in StringBuffer/StringBuilder classes.

It should be noted that there a misconception that is going around the developer community regarding the above reason which says that then why an ArrayList/Date overrides the equals() method as it too can change with time. Here are a few reasons to clear that thought which in fact is natural:
  • StringBuffer/StringBuilder classes are intended to be used as temporary buffer and change more frequently than classes like ArrayList and Date
  • While one may like to perform various operations like serialization, making clones, being used as keys in collections or stored in database but one is very unlikely to perform similar operations with StringBuffer/StringBuilder classes.
Also String may be treated as value object, where value equality means, object equality. Read here for more on value objects.


Thursday, 21 April 2011

The equality operator


The equality operator (==) when applied to objects return true if two objects have same reference value, false otherwise. The example below illustrates this --

String str1 = "first string";
String str2 = new String("first string");
String str3 = "first string";
boolean test1 = (str1 == str2);
boolean test2 = (str1 == str3);
In the example above, test1 is set to false because str1 and str2 point to different references. As str1 and str3 point to the same reference, test2 gets set to true. When a string is initialized without using the new operator, and with an existing string, then the new string also points to the first string's location. So in the example above, str1 and str3 point to the same pool of memory and hence test2 gets set to true. The string str2 on the other hand is created using the new operator and hence points to a different block of memory. Hence test1 gets set to false.

Tuesday, 26 October 2010

==, .equals(), compareTo(), and compare()

==,equals, compareTo, compare all help in comparing the object in one or other way.

== & != Operator
Compares references, not values. The use of == with object references is generally limited to the following:
  • Comparing to see if a reference is null.
  • Comparing two enum values. This works because there is only one object for each enum constant.
  • You want to know if two references are to the same object


equals() method
Usage : a.equals(b) 
Compares values for equality. Because this method is defined in the Object class, from which all other classes are derived, it's automatically defined for every class. However, it doesn't perform an intelligent comparison for most classes unless the class overrides it. It has been defined in a meaningful way for most Java core classes. If it's not defined for a (user) class, it behaves the same as ==.
It turns out that defining equals() isn't trivial; in fact it's moderately hard to get it right, especially in the case of subclasses. The best treatment of the issues is in Horstmann's Core Java Vol 1. See equals() method here.

Also to see == vs equals() , refer here.

compareTo() method
a.compareTo(b) is present in Comparable interface. Compares values and returns an int which tells if the values compare less than, equal, or greater than. If your class objects have a natural order, implement the Comparable<T> interface and define this method. All Java classes that have a natural ordering implement this (String, Double, BigInteger, ...).
For more on Comparable interface, refer here.

compare(a,b) method
Usage  : compare(a, b) 
is implemented using Comparator interface. Compares values of two objects. This is implemented as part of the Comparator<T> interface, and the typical use is to define one or more small utility classes that implement this, to pass to methods such as sort() or for use by sorting data structures such as TreeMap and TreeSet. You might want to create a Comparator object for the following.

  • Multiple comparisons. To provide several different ways to sort something. For example, you might want to sort a Person class by name, ID, age, height, ... You would define a Comparator for each of these to pass to the sort() method.
  • System class. To provide comparison methods for classes that you have no control over. For example, you could define a Comparator for Strings that compared them by length.
  • Strategy pattern. To implement a strategy pattern, which is a situation where you want to represent an algorithm as an object that you can pass as a parameter, save in a data structure, etc.
If your class objects have one natural sorting order, you may not need this.
For more on Comparator interface refer here.