Tuesday, July 28, 2009

Getting references to outer classes

Sometimes it is necessary to get references to the outer classes of an inner class. From within the inner class it is pretty straightforward to obtain the reference to the outer class. Just precede the keyword this with the outer class name. Here is a simple example:

public class OuterThis {
private String me = "OuterThis";
public class Inner1 {
private String me = "Inner1";
public class Inner2{
public void getEnclosingClasses() {
System.out.println(Inner1.this.me);
System.out.println(OuterThis.this.me);
}
}
}

public static void main(String[] args) {
OuterThis.Inner1.Inner2 in2 = new OuterThis().new Inner1().new Inner2();
in2.getEnclosingClasses();
}

}


You can also get the outer class reference through reflection. The this reference is encoded as this$n where n is an int specifying the level of the class. In the example above, this$0 is the outer class "OuterThis" while this$1 refers to "Inner1". So in the code above just do the following to get the enclosing class "Inner1" through reflection in the method getEnclosingClasses().
Inner1 in1 = (Inner1)getClass().getDeclaredField("this$1").get(this);

Reflection to obtain the outer class reference is usually used when you are outside the inner class. The following example illustrates it.

import java.util.ArrayList;

public class ExposeThis {
private String exposeThis = "Just Expose This";

public static void main(String[] args) throws
IllegalArgumentException, SecurityException, NoSuchFieldException,
IllegalAccessException {
Client cl = new Client();
new ExposeThis().registerMe(cl);
cl.printThis();
}

public void registerMe(Client client) {
client.addListener(new ClientListener(){});
}

public String toString() {
return exposeThis;
}

}

interface ClientListener {
}

class Client {
private ArrayList<ClientListener> clients = new ArrayList<ClientListener>();

public void addListener(ClientListener cl) {
clients.add(cl);
}

public void printThis() throws
NoSuchFieldException, IllegalArgumentException,
SecurityException, IllegalAccessException{
for (ClientListener cl: clients) {
//Get handle to OuterClass this by reflection
ExposeThis et =
(ExposeThis)cl.getClass().getDeclaredField("this$0").get(cl);
System.out.println(et);
}
}
}





Note:
Since it is possible to obtain references to enclosing classes by getting a handle to the inner class, one has to be very careful while working with inner classes.

Wednesday, July 22, 2009

Checked collections

The generics mechanism provides compile-time type checking. So generic collections are mostly type-safe. I did not say they will "always" be safe because it is possible to add wrong types into generic collections using unchecked casts. For instance mixing generic and non-generic code results in unchecked casts. The compiler will issue warnings when there are unchecked casts but the compilation does not fail. Also at runtime, when a wrong type is added to the parameterized collection no ClassCastException is thrown because the runtime has no knowledge of type parameters due to type erasure. So now, the wrong type is happily added to the collection. The problem of wrong type in the collection does not get discovered until much later. And when the problem is discovered, the runtime exception makes it quite impossible to discover the source of the problem i.e. where exactly the unsafe type got added. Here is a simple example followed by the runtime exception that the program throws when it runs.

import java.util.ArrayList;
import java.util.Collection;

public class UnsafeCollectionOperation {

public static void unsafeAdd(Collection c) {
c.add(new Integer(1));
}

public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("One");
c.add("Two");
unsafeAdd(c);
for (String s: c) {
System.out.println(s);
}

}

}




Here is what happens at runtime:
One
Two

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer
at UnsafeCollectionOperation.main(UnsafeCollectionOperation.java:17)


As you see from the exception above, the runtime exception does not offer any information on where exactly the unsafe type was added. My code is so small, so we can easily deduce where we went wrong, but when we deal with a lot of code, this task becomes very cumbersome. One way to deal with this problem is to use checked collection(see java.util.Collections). Checked collections are dynamically type safe views of collections. They perform a runtime type check every time an element is inserted into the collection. Any attempt to insert a wrong type will immediately result in ClassCastException. So we know exactly where we went wrong. Here is an example:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

public class CheckedCollection {

public static void safeAdd(Collection c) {
c.add("three");
}

public static void unsafeAdd(Collection c) {
c.add(new Integer(1));
}

public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("One");
c.add("Two");
Collection<String> checkedCollection =
Collections.checkedCollection(c, String.class);
safeAdd(checkedCollection);
unsafeAdd(checkedCollection);
for (String s: checkedCollection) {
System.out.println(s);
}

}

}



Running the program produces:
Exception in thread "main" java.lang.ClassCastException: Attempt to insert class java.lang.Integer element into collection with element type class java.lang.String
at java.util.Collections$CheckedCollection.typeCheck(Collections.java:2206)
at java.util.Collections$CheckedCollection.add(Collections.java:2247)
at CheckedCollection.unSafeAdd(CheckedCollection.java:14)
at CheckedCollection.main(CheckedCollection.java:23)


From the exception above we know exactly where we went wrong.
Couple of note worthy points are:
- When a checked collection view is created using an existing collection, it will NOT discover incorrectly typed elements, if they already exist in the collection prior to creating the view.
- After creating the checked collection view, if any access happens through the original collection and not through the checked collection, it cannot ensure type safety.
- There is a performance overhead of a runtime type check every time an element is inserted into the collection.

Saturday, July 18, 2009

Accessing local variables in local classes

In Java, local classes can access any members of the containing class. However when it comes to local variables and method parameters they can use only the ones marked final.  The reason is that the instances of the class can live longer than the method.  And since local variables and method parameters live on the stack, they may be long gone before the instance actually uses them.  So if the local classes want to use local variables, they must have a private copy of all the local variables they use. The compiler automatically makes a private internal copy for the local class. However the value of the local variable can change during the lifetime of the method. So someone has to keep the private local variable of the local class in sync with the actual local variable. There are many issues involved in doing it (like when or how often should the sync take place etc). The safest and perhaps the easiest way to guarantee that the local and the private copy are same is to mark the local variable final.  Hence the local classes cannot use local variables and method parameters that are not marked final.  Here is an example of how an instance of a local class can save the scope and use it at a later point in time:





public class LocalClass {

private int instanceVariable = 0;
private interface LocalClassHolder{
int getInstanceVariable();
int getLocalVariable();
}

public LocalClassHolder testLocalClass() {

final int localVariable = 1;
LocalClassHolder lch;
int changingLocalVariable = 0; //not possible to use this in local class

class InnerLocalClass implements LocalClassHolder {
//return instance variable
public int getInstanceVariable() {
return instanceVariable;
}

//return local variable
public int getLocalVariable() {
return localVariable;
}
}
lch = new InnerLocalClass();
changingLocalVariable = 1000;
return lch;

}

public static void main(String[] args) {
LocalClass lc = new LocalClass();
LocalClassHolder ch = lc.testLocalClass();
int instance = ch.getInstanceVariable();
int local = ch.getLocalVariable();
System.out.println("Instance: " + instance + " " + "Local: " + local);

}

}


Sunday, July 12, 2009

Method overloading with Widening, Boxing and Varargs

With the introduction of boxing and varargs in Java 1.5, there are new rules to remember wrt overloaded methods that include widening, boxing and varargs. Key rule to remember is widening always wins over boxing and varargs when present individually. So mathematically, widening > boxing > varargs in that order. There is a catch with widening reference variables. The reference variable widening should satisy the IS-A test. Here is a simple example:



public class BoxWidenVarArgs {

public static void pickMe(Integer i) {
System.out.println("Integer ");
}
public static void pickMe(int... i) {
System.out.println("varargs int ");
}
public static void pickMe(short i) {
System.out.println("short");
}
public static void pickMe(Byte i) {
System.out.println("Byte ");
}
public static void pickMe(byte... i) {
System.out.println("varargs byte");
}
public static void onlyInteger(Integer i) {
System.out.println("Integer");
}

public static void main(String[] args) {
byte b = 1;
pickMe(b); //picks widening over boxing and varargs
int i = 10;
pickMe(i); //As no widening is present, picks boxing over varargs
/**
* compilation error, cannot widen from Byte to Integer as Byte
* is not a Integer, IS-A test fails!
*/
//onlyInteger(new Byte(b));
}

}




Ouput:
short
Integer

Here are possible combinations of Widening, boxing and varargs:

Combining Widening and Boxing:
Can we widen and box, is this allowed? The rule to remember is that first widening then boxing ( i.e. Widen+Box) is not allowed. So a short can be widened to an int but a short cannot be widened and boxed to an Integer.


public class WidenAndBox {

public static void pickMe(Integer i) {
System.out.println("Integer");
}
public static void main(String[] args) {
short s = 2;
//Compilation error. Not allowed.
//pickMe(s);

}

}




Combining Boxing and Widening:
First boxing and then widening is allowed provided the widening satisfies the IS-A relationship. So a short can be boxed to a Short and then widened to a Number or Object but a short cannot be boxed to a Short and then widened to a Integer or String because it does not satisfy the IS-A relation.

Combining varargs with widening/boxing:
You can widen and then combine varargs. You can box and combine with varargs. However you cannot have overloaded methods that has widening+varargs and boxing+varargs. You can combine varargs with either widening or boxing.


public class LegalCombinations {

public static void pickMe(Number n) {
System.out.println("Number");
}
public static void wideningVarArgs(Integer... i) {
System.out.println("Integer...");
}
public static void boxingVarArgs(long... i) {
System.out.println("long...");
}

public static void main(String[] args) {
short s = 2;
pickMe(s); //Boxing and Widening
int i = 1;
wideningVarArgs(i); //combination of widening and varargs
boxingVarArgs(i); //combination of boxing and varargs
}

}



The following causes compilation error as discussed above:
public class IllegalCombinations {

public static void withVarArgs(Integer... i) {
System.out.println("Integer...");
}
public static void withVarArgs(long... i) {
System.out.println("long...");
}

public static void main(String[] args) {
int i = 1;
/**
* Compilation error. Cannot have 2 overloaded methods one using
* boxing+varargs and another using widening+varargs.
* Can have one or the other.
*/
//withVarArgs(i);
}

}

Also remember varargs are always chosen last. So if you have 2 overloaded methods one with boxing + widening and and one with varargs, compiler will choose boxing+widening over varargs.

Summary
:
  • used individually, widening > boxing > varargs
  • varargs are always chosen last, they always lose.
  • reference variables have to satisfy IS-A test while widening
  • widening then boxing is not permitted. 
  • boxing then widening is permitted.
  • varargs can be combined with wither boxing or widening.

Monday, July 6, 2009

Shadowing final variables

In Java, final variables can be shadowed. They follow the same rules of shadow variables and static methods which I had discussed in my earlier post. The key point to remember is that while resolving a shadow variable or shadow static method, the reference type and NOT the reference object (i.e. object pointed to by the reference type) is used. Here is a simple example:

class Super {
public final String y = "SUPER";
public static final int z = 0;
}

class Sub extends Super {

//Shadowing a final variable
public final String y = "SUB";

//Shadowing a final variable and also changing type and access modifier's
char z = '1';

}

public class ShadowingFinalVariables {


public static void main(String[] args) {
Sub sub = new Sub();
Super supr = sub;


print(sub.y); //yields SUB
print(supr.y); //yields SUPER
print(((Super)sub).y); //Due to casting, yields SUPER
print(((Sub)supr).y); //Due to casting, yields SUB
print(sub.z); //yields 1
print(supr.z); //yields 0
print(((Super)sub).z); //Due to casting, yields 0
print(((Sub)supr).z);//Due to casting yields 1

}


public static <T> void print(T t) {
System.out.println(t);
}

}

Wednesday, July 1, 2009

Task Scheduling in Java


In Java, the Timer class helps you to schedule tasks to run at some time in the future. The tasks can be run either once or repeatedly like a batch job. 


Tasks can be scheduled to run in the following way:

  • Create Timers using a simple constructor of the Timer class. This creates a Timer Thread.
  • Subclass the TaskTimer class to represent your task. Implement the run() method and put your task implementation details here.
  • Schedule the task using one of the schedule() methods of the Timer class.


Types of Schedule

There are 3 types of schedules:

  • One time schedule

This runs the task once after the delay time specified. Here is an example:



import java.util.Timer;

import java.util.TimerTask;


public class MyTimer {

public static void main(String[] args) {

Timer timer = new Timer();

TimerTask task = new TimerTask() {

public void run() {

System.out.println("Scheduled Task");

}

};

//Execute this task after 0 milliseconds i.e. immediately

timer.schedule(task,0);

}


}

  • Fixed-delay schedule

This runs the task repeatedly after the initial delay time specified. The time between the subsequent executions is specified by a period time. This schedule ensures that the period time elapses between invocations. Here is one example:


long oneday = 24*60*60*1000;

//Execute this task every day starting immediately. Make sure

//that there is a 24 hr delay between the invocations. So if the

//last invocation was delayed for some reason, the delay carries

//forward.

timer.schedule(task, 0, oneday);


  • Fixed-rate schedule


This runs the task repeatedly after the initial delay time specified. The time between the subsequent executions is specified by a period time. This schedule ensures that the task runs during their scheduled time .i.e it is not affected by the time of its previous invocation. Example:

//Way to setup a cron or batch job. Make sure that the task 

//runs at the fixed time every 24 hrs. If the last invocation

//was delayed due to some reason, the delay is not reflected in the

//next invocation.

timer.scheduleAtFixedRate(task,0,oneday);


Some interesting facts:

  • Each Timer object runs only one background thread. So if multiple tasks are assigned to the same Timer object, they will be run sequentially. To run them in parallel you have to create multiple Timer objects. 
  • The class is thread-safe.
  • There is no mechanism to cancel the currently executing task. There is a cancel method which terminates the Timer thread and thereby discards any scheduled tasks but does not affect the currently executing task.