Here is my understanding.
- Step 1: When you say Integer counter = 0;what you're actually doing is
 Integer counter = new Integer(0);Here you created anInteger objectwhose value is 0 andcounteris reffering to it.
- Step 2: - Integer test = counter;
 - Now - testis also referring to the    same- Integer objectwe
created in step 1.
 
- Step 3: Here comes the tricky part. When you do - counter++;in your    main method, Java Auto-boxing and Auto-unboxing
features are    implementing the below code for you.
 - counter = Integer.valueOf(counter.intValue() + 1);
 
As Integer class is immutable in Java, when the value is incremented from 0 to 1, the valueOf() method is creating a new Integer object and storing the new value 1 in it instead of changing the old object's value (See below for Java's valueOf() method implementation). As you're referring the new object with counter, it de-referenced  the old Integer object whose value is 0. But the reference variable test is still holding the old Integer object. This is the reason test printing the old value. 
Java's valueOf() method from library class Integer
638     public static Integer More ...valueOf(int i) {
639         assert IntegerCache.high >= 127;
640         if (i >= IntegerCache.low && i <= IntegerCache.high)
641             return IntegerCache.cache[i + (-IntegerCache.low)];
642         return new Integer(i); //See, new object is created here.
643     }
See below for detailed diagrammatic explanation. 
Solid line implies reference variable is still holding the object.
Dotted line implies reference variable is no more holding the object.
