Friday, May 25, 2012

If a class is serializable but its superclass in not , what will be the state of the instance variables inherited from super class after deserialization?


The values of the instance variables inherited from superclass will be reset to the values they were given during the original construction of the object as the non-serializable super-class constructor will run.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SubSerialSuperNotSerial {

    public static void main(String [] args) {

        ChildSerializable c = new ChildSerializable();
        System.out.println("Before : - " + c.noOfWheels + " "+ c.color);
        try {
        FileOutputStream fs = new FileOutputStream("superNotSerail.ser");
        ObjectOutputStream os = new ObjectOutputStream(fs);
        os.writeObject(c);
        os.close();
        } catch (Exception e) { e.printStackTrace(); }

        try {
        FileInputStream fis = new FileInputStream("superNotSerail.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        c = (ChildSerializable) ois.readObject();
        ois.close();
        } catch (Exception e) { e.printStackTrace(); }
        System.out.println("After :- " + c.noOfWheels + " "+ c.color);
        }

}

 class ParentNonSerializable {
    int noOfWheels;
   
    ParentNonSerializable(){
        this.noOfWheels = 4;
    }
   
}


 class ChildSerializable extends ParentNonSerializable implements Serializable {
 
    private static final long serialVersionUID = 1L;
    String color;


    ChildSerializable() {
        this.noOfWheels = 8;
        this.color = "blue";
    }
}



Result on executing above code –
Before : - 8 blue
After :- 4 blue
The instance variable ‘noOfWheels’ is inherited from superclass which is not serializable. Therefore while restoring it the non-serializable superclass constructor runs and its value is set to 8 and is not same as the value saved during serialization which is 4.

Tuesday, May 22, 2012

Thread pool:Concurrency

import java.util.ArrayList;
import java.util.List;

import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ExecutorService;

public class Concurrency {

   public static void main(String args[]) {
       long start = System.currentTimeMillis();

       // initialize pool
       ExecutorService pool = Executors.newFixedThreadPool(3);

       // store futures somewhere
       List<Future<CallableData>> futures = new ArrayList<Future<CallableData>>();

       // submit a bunch of Callables to the Pool
       for(int i = 0; i < 10; i++) {
           System.out.println("Creating! " + i);
           futures.add(pool.submit(new CallableData(i)));
       }

       // wait for everything to finish
       for(Future<CallableData> future : futures) {
           try {
               CallableData data = future.get();
               System.out.println("Got result!" + data.getFoo());
           } catch (Exception e){
               e.printStackTrace();
           }
       }

       System.out.println("Total time: " + (System.currentTimeMillis() - start) + " ms");

       // don't forget to shutdown
       pool.shutdown();
   }

   private static class CallableData implements Callable<CallableData> {
       private int foo;
       public CallableData(int foo) {
           this.foo = foo;
       }
       public CallableData call() {
           System.out.println("Running! " + foo);
           try { Thread.sleep(2000); } catch (Exception e) {}
           foo = foo + 1000;
           System.out.println("Completed! " + foo);
           return this;
       }
       public int getFoo() {
           return foo;
       }
   }
}

Friday, May 18, 2012

Why HashSet / HashMap in java does not maintain the insertion order?


Why HashSet / HashMap in java does not maintain the insertion order? example code

Tough interview questions like "Why HashSet / HashMap in java does not maintain the insertion order? OR Why HashSet / HashMap does not make guarantee that the iteration order will remain constant over time?" may be asked .When you run the following code with default hash map capacity (16) , you may get the output as gvien below
    
import java.util.*;
import java.util.*;
class HashMap2
{
public static void main(String args[]) {
HashMap hm=new HashMap();
hm.put("545", "Kumar");
hm.put("5143", "Jegan");
hm.put("767", "Akshu");
hm.put("1766", "Lakshan");
    Iterator it = hm.entrySet().iterator();
System.out.println("\nIteration Order when using HashMap");
    while (it.hasNext()) {
        Map.Entry keyValue= (Map.Entry)it.next();
        System.out.println(keyValue.getKey() + " -> " + keyValue.getValue());
    }
HashSet<String> set = new HashSet<String>(16);
set.add("Apple");
set.add("Banana");
set.add("Orange");
set.add("Pine Apple");
System.out.println("\nIteration Order when using HashSet");
  for (String fruit : set){
         System.out.println(fruit); }
}
}


Insertion Order in HashMap : 545 , 5143, 767, 1766 . In HashSet : Apple, Banana, Orange, Pine Apple. The Iteration order is given below.
Output:

In the above output , the display order (iteration order) is different from the order in which the elements are inserted. Let us see how does this happen ?
HashSet stores elements in a hash table (actually through a HashMap instance , where element in the HashSet is the key to HashMap and dummy object is passed as a value). So the below answer is applicable to both HashMap and HashSet . Hashing determines where the object has to be placed in a HashMap. In Detail : HashMap internally uses an array to store key and value pairs (i.e the reference to HashMap.Entry objects where HashMap.Entry objects have the fields to store hash, key ,value , link to next HashMap.Entry object - a linked list implementation) . The index to above array is calculated from the key using hash function. The hash function accepts the hashcode of the key (key.hashCode()) and calculates the hash using formula given below and returns hash. The index is calculated based on the hash value and the length of array (Capacity) with the formula ( h & (length-1) , h -> hash value, length -> array capacity) so that the elements (key-value pairs) can be distributed in the array within the given range (capacity) . Array can be resized if required but the length should be a power of two. So whenever the length (capacity) of the array is resized to 2^n , the index of the element is also changed .Thus the iteration order is changed.
Function to calculate hash using the hashcode of key.
    
//fromJava Source code . This function ensures that hashCodes that differ only by constant multiples at each bit position have a bounded  number of collisions (approximately 8 at default load factor).
  static int hash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

The below code prints the index which is calculated using the hashcode and capacity using hash function .
    
import java.util.*;
class HashMap3
{
public static void main(String args[]) {
int length=128; // capacity
HashMap hm=new HashMap(length);
hm.put("545", "Kumar");
hm.put("5143", "Jegan");
hm.put("767", "Akshu");
hm.put("1766", "Lakshan");
    Iterator it = hm.entrySet().iterator();
System.out.println("\nIteration Order when using HashMap with capacity : "+ length);
    while (it.hasNext()) {
        Map.Entry keyValue= (Map.Entry)it.next();
        System.out.println(  "Index : " + (hash(keyValue.getKey().hashCode()) & (length -1) )+ " " +  keyValue.getKey() + " -> " + keyValue.getValue());
    }

HashSet<String> set = new HashSet<String>(length);
set.add("Apple");
set.add("Banana");
set.add("Orange");
set.add("Pine Apple");

System.out.println("\nIteration Order when using HashSet with capacity : "+ length);
    for (String fruit : set){
System.out.println("Index : " + (hash(fruit.hashCode()) & (length -1) )+ " Element : " + fruit);
}
}

static int hash(int h) {
         h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
}

Output :

Two keys with different hashCode can also generate the same index (collisions) . In the above output, Orange and Banana has same index 12. The following two lines of code adds new elements and also solves collision.
Entry e = table[index];
table[index] = new Entry(hash, key, value, e);

if e==null means , there is no collision. Collision can be resolved by many techniques like Chaining

Picture : HashMap with Collision

Change the length to 128 and run the above program . The index / iteration order is changed.

Final conclusion : The location of the element in the HashMap is determined by the Hashcode of key and capacity of the HashMap.
Note: To maintain insertion order , you can use LinkedHashSet / LinkedHashMap