Sunday, June 27, 2010

Use of comparable and comparator interface


In java the element in collections can be sorted by using TreeSet or TreeMap. To sort the data elements a class needs to implement Comparator or Comparable interface. Thats why all Wrapper classes like Integer,Double and String class implements Comparable interface.

A class implementing Comparable interface need to override compareTo(Object obj) method and put the logic for sorting.

The method returns an int value :-1,0,1
It will return -1 : If this object is lesser than the passed object
It will return 0 : If this object is same the passed object
It will return 1 : If this object is greater than the passed object

Consider a class Person.

class Person {
public String name;
public String lastName;

public Person(String name, String lastName){
this.name=name;
this.lastName=lastName;
}
public String getName(){
return name;
}
public String getLastName(){
return lastName;
}

public static void main(String arg[]){
List myList = new ArrayList();

myList.add(new Person("Robert","USA"));
myList.add(new Person("Andy","UK"));
myList.add(new Person("Harish","India"));
for(Person person : myList){
System.out.println("My name is "+person.getName());
}
}
}
Output is :
My name is Robert
My name is Andy
My name is Harish

But now i want that the objects to be sorted on name basis should be retrieved in sorted order.
Consider a class Person.

class Person implements Comparable{
public String name;
public String lastName;

public Person(String name, String lastName){
this.name=name;
this.lastName=lastName;
}
public String getName(){
return name;
}
public String getLastName(){
return lastName;
}

public int compareTo(Object obj){
Person p = (Person)obj;
return this.name.compareTo(p.getName);
}

public static void main(String arg[]){
List myList = new ArrayList();

myList.add(new Person("Robert","USA"));
myList.add(new Person("Andy","UK"));
myList.add(new Person("Harish","India"));
Collections.sort(myList);
for(Person person : myList){
System.out.println("My name is "+person.getName());
}
}
}
Output is :
My name is Andy
My name is Harish
My name is Robert

Couple of things which needs to be taken in consideration:
1) Collections.sort() will sort only the collection having objects which implements either one of the comparing interface.
2) Collections.sort() will sort the same list.

Comparator interface is used when an extra logic is required to sort the objects. One need to override compare(Object obj1, Object obj2) method.For example you want the list of Person object to be sorted on the basis of complete name i.e "name lastName" but also on the other hand doesnt want to change the Person class default sorting implementation or Person class is a jar so so no code modification in it can be done. First create a Custom Comparator.

public class MyCustomComparator implements Comparator{
public int compare(Object obj1, Object obj2){
Person p1 =(Person) obj1;
Person p2 =(Person) ob2;
String p1Name = p1.getName()+ " " +p1.getLastName();
String p2Name = p2.getName()+ " " +p2.getLastName();
return p1Name.toCompareTo(p2Name);
}
}

// Changes made in main method of Person class.
public static void main(String arg[]){
List myList = new ArrayList();

myList.add(new Person("Robert","USA"));
myList.add(new Person("Robert","UK"));
myList.add(new Person("Robert","India"));
Collections.sort(myList new MyCustomComparator());
for(Person person : myList){
System.out.println("My name is "+person.getName() + " " + person.getLastName());
}
}
OutPut:
My name is Robert India
My name is Robert UK
My name is Robert USA
Couple of things which needs to be taken in consideration:
1) For Comparator interface you need to override method compare(obj)
2) In collections.sort() the instance of Comparator need to be passed. In this example the list is sorted according to the custom Comparator created

Java classloaders


Classloader allows JVM to load classes. Regular Java applications running from command line involve three classloaders – Bootstrap, Extensions and System-Classpath classloaders. The three class loaders have a parent child relationship among themselves

1. Classes in the list of bootstrap classes— These are classes that embody the Java platform, such as the classes in rt.jar.

2. Classes that appear in the list of extension classes— These classes use the Extension Mechanism Framework to extend the Java platform, with archive files (.jar, .zip, etc.) located in the /lib/ext directory of the runtime environment.

3. User classes—These are classes that do not use the extension mechanism architecture identified using the -classpath command-line option or the CLASSPATH environment variable.

pic1

Classloader problems, when they occur are difficult to debug. There are only three basic principles to understand.

Classloader hierarchy illustrating the delegation.

Classloader hierarchy illustrating the delegation.

The first principle is Delegation Principle. According to this principle, if a particular class is not loaded already, the classloaders delegate the requests to load that class to their parent classloaders. This delegation continues until the top of the hierarchy is reached and the primordial classloader loads the class. The System-ClassPath classloader loads a class called MyApp. MyApp creates a new instance of java.util.Vector. Assume that java.util.Vector has not been loaded already. Since System-Classpath classloader loaded the MyApp class, it first asks its parent, the extension classloader to load the class. The extension classloader asks the Bootstrap classloader to load java.util.Vector. Since java.util.Vector is a J2SE class, the bootstrap classloader loads it and returns. Consider a slightly different scenario. In this case, MyApp creates a new instance of MyClass, another application specific class. Assume that MyClass has not been loaded yet. As usual, when the System-Classpath classloader receives the request to load the class, it delegates it to its parent. The request finally reaches the Bootstrap classloader. It cannot find the class. Hence its child, Extensions classloader tries to load it. It cannot find it either. Finally the request comes back to the System-Classpath classloader. It finds the class and loads it. This explains the alternative path when everything is not a happy day scenario.

 Classloader hierarchy illustrating the delegation when classes cannot be found

Classloader hierarchy illustrating the delegation when classes cannot be found

 Classloader hierarchy and classes visibility.

Classloader hierarchy and classes visibility.

The second principle is the Visibility principle. According to this principle, Classes loaded by parent classloaders are visible to child classloaders but not vice versa. What this means is that a class can only see other classes loaded by the ClassX’s classloader or one of its parents. The reverse is not true i.e. a class loaded by ClassX’s parent classloader cannot see ClassX. An example will make things clearer. Look at above figure. Four classloaders are shown- ClassLoaders A, B, X and Y. Class A is the topmost Classloader. ClassLoader B is its child. ClassLoaders X and Y are B’s siblings. Each of them loads classes with same names i.e. A, B, X and Y. A is the only class visible as far as other classes loaded by ClassLoader A are concerned. As far as classes loaded by ClassLoader B is concerned, A and B are the visible classes. Similarly for classes loaded by ClassLoader X, classes A, B and X are visible, but not class Y. Sibling classloaders cannot see each other’s classes.

The third principle is the class Uniqueness Principle. According to this principle, when a classloader loads a class, the child classloaders in the hierarchy will never reload the class. This follows from the delegation principle since a classloader always delegates class loading to its parents. The child classloader will load it (or try to load it) only if the parent hierarchy fails to load the class. Thus the uniqueness of the class is maintained. An interesting scenario emerges when both parent and child classloaders load the same class. You might think how is this feasible after all. Isn’t this contradicting the class uniqueness principle? To answer this question look at figure again. Let us assume that none of the classes have been loaded anywhere in the hierarchy. Let us also suppose that X, loaded by ClassLoader X, forcefully uses its classloader to load B. This can be done as shown in example below by using an API such as Class.forName(). The code shows such a scenario. Using Class.forName() 01 public class X { 02 03 public X() { 04 ClassLoader cl = this.getClass().getClassLoader(); 05 Class B = Class.forName(“B”, true, cl); 06 } 07 } In the constructor for X, the class B is loaded by explicitly using Person’s parent classloader, i.e. the parent of the classloader that loaded Person. By doing so, the delegation is overridden and B is loaded by ClassLoaderX – the classloader of X. Now suppose that another class loaded by ClassLoader B tries to access B, it cannot find it and hence follows the delegation principle. Since the delegation principle only consults the parents, ClassLoader B also eventually loads Class B. When some other code tries to compare two objects of type B – each loaded by different classloaders, it gets a ClassCastException.