Friday, October 8, 2010

Can you override Static Methods in Java

 Well... the answer is NO if you think from the perspective of how an overriden method should behave in Java. But, you don't get any compiler error if you try to override a static method. That means, if you try to override, Java doesn't stop you doing that; but you certainly don't get the same effect as you get for non-static methods. Overriding in Java simply means that the particular method would be called based on the run time type of the object and not on the compile time type of it (which is the case with overriden static methods). Okay... any guesses for the reason why do they behave strangely? Because they are class methods and hence access to them is always resolved during compile time only using the compile time type information. Accessing them using object references is just an extra liberty given by the designers of Java and we should certainly not think of stopping that practice only when they restrict it :-)


Example: let's try to see what happens if we try overriding a static method:-

class SuperClass{
......
public static void staticMethod(){
System.out.println("SuperClass: inside staticMethod");
}
......
}

public class SubClass extends SuperClass{
......
//overriding the static method
public static void staticMethod(){
System.out.println("SubClass: inside staticMethod");
}

......
public static void main(String []args){
......
SuperClass superClassWithSuperCons = new SuperClass();
SuperClass superClassWithSubCons = new SubClass();
SubClass subClassWithSubCons = new SubClass();

superClassWithSuperCons.staticMethod();
superClassWithSubCons.staticMethod();
subClassWithSubCons.staticMethod();
...
}

}

Output:-

SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod

Notice the second line of the output. Had the staticMethod been overriden this line should have been identical to the third line as we're invoking the 'staticMethod()' on an object of Runtime Type as 'SubClass' and not as 'SuperClass'. This confirms that the static methods are always resolved using their compile time type information only.

Memory leaks with static

'static' can't straightway be blamed for causing memory leaks. But, if the programmer has not well thought the usage and has not taken care of the setting the references to 'null' explicitly after using the static objects then they can definitely cause memory leaks. Let's see how.

As 'static' members will by default live for the entire life of an app unless they are explicitly set to 'null'. So, always make it a point to nullify the references as soon as you reach at a point in your code where the use of the static member is over. For example: suppose you have created a 'Statement' object from a DB Connection and the connection is a pooled one. Now as you know calling close()method on a pooled connection will not actually close the connection instead it will return the Connection object to the pool to be re-used. So, in such a case unless you explicitly close the 'Statement' object, it would keep consuming precious memory space for no real use. Just think the scenario where you have declared the 'Statement' object as a static member, it'll be maintained in the memory for the entire life time of the app even when the control is out of the scope. It's just a sample scenario and many of you might never have used 'Statement' object in such an irresponsible manner. It's just an attempt to show how the 'static' can be misused to cause memory leaks in Java.


Not that if your Statement object is non-static you should reply on the out-of-scope nullification (i.e., as soon as control is out of scope the local objects would be marked for re-claimation) as in case you still have a significant amount of code (in terms of time/space) after using the Statement last and before reaching the end of the local scope, it would be a sheer wastage of memory if you don't explicitly nullify the 'Statement' after its use is over. Such a scenario should also be thought of as memory leaks only and one should always make sure the nullification of resources is as close to their last usage as possible.


Therefore, in summary we can say that one should/must :-

  • always think if you really need to make this variable/member a 'static' one?
  • always try to confine the scope of an object to restrict its usage only to the section it's actually needed
  • always make a conscious effort to explicitly nullify objects once you finish using them (especially the large objects)

Choosing the Most Specific Method - Tricky Method Overloading

Let's start with looking at a code-segment and try to think of the output/error, it would produce when compiled/executed and subsequently we'll discuss the behavior of code.

public class NullTest {

   public static void method(Object obj){
     System.out.println("method with param type - Object");
   }
 
   public static void method(String obj){
     System.out.println("method with param type - String");
   }
 
   public static void main(String [] args){
     method(null);
   }
}

So, what do you expect as the output here? Before thinking about the output, do you really expect the code to compile successfully? Well... yeah, the code will compile and run fine as opposed to anyone who might have sensed an ambiguity here - we'll see the reason soon. 

Since the methods are overloaded, the resolution will be done at compile-time only. Which method do you see being bind here - the one with parameter type 'Object' or the one with parameter type 'String' and why? Of course, the compiler can't bind two methods with one call, so on what basis would it pick the most suitable? Which method would be picked, is evident from the output given below:-


method with param type - String

Any guesses for why a special treatment is being given to 'String' here? Well... it's not actually for 'String' class specifically, but any sub-class would get a preference over the super class in such a situation. But, why? Because JLS (Section: 15.12.2.5)allows this. It clearly says:

"If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specificmethod is chosen."

As you easily deduce that the compiler should be able to pick 'the most specific', failing which it will throw a compile-time error. Let's understand it with the below code-segment which doesn't compile because the compiler can't pick 'the most specific' here.


public class NullTest {

   public static void method(Object obj){
     System.out.println("method with param type - Object");
   }
 
   public static void method(String str){
     System.out.println("method with param type - String");
   }
 
   public static void method(StringBuffer strBuf){
     System.out.println("method with param type - StringBuffer");
   }
 
   public static void main(String [] args){
     method(null); //... compile-time error!
   }
}

Why is the compiler not able to pick 'the most specific' here - because both Stringand StringBuffer are are sub-classes of the Object class, but without being in the same inheritance hierarchy. For finding 'the most specific' method, the compiler needs to find a method having the parameter type, which is a sub-class of the parameter types of all other overloaded methods.

This holds true for overloaded methods having more than one parameters as well. The compiler would pick 'the most specific' by looking which method is having at least one of its parameter types as a clear sub-class of the corresponding parameter type and other parameter types being either the same or clear sub-classes, in all otheroverloaded methods. If it can find one, good, otherwise it will throw a compile-time error. For example:


public class NullTest {

 public static void method(Object obj, Object obj1){
   System.out.println("method with param types - Object, Object");
 }

 public static void method(String str, Object obj){
   System.out.println("method with param types - String, Object");
 }

 public static void main(String [] args){
   method(null, null);
 }
}

Output

method with param types - String, Object

In this case the compiler can easily pick 'the most specific' as the method having parameter types (String, Object) as the other overloaded method is having its parameter types as (Object, Object) - clearly 'String' is a subclass of 'Object' and the other parameter is of same type, so the method with parameter types(String, Object) can be picked with ease. But, the below code would throw a compile-time error as none of the methods satisfy the condition for being picked as 'the most specific' method.


public class NullTest {

 public static void method(Object obj, String obj1){
   System.out.println("method with param types - Object, String");
 }

 public static void method(String str, Object str1){
   System.out.println("method with param types - String, Object");
 }

 public static void main(String [] args){
   method(null, null); //... compile-time error!
 }
}

Work with Memcache

Step1. Download memecache windows exe file from http://jehiah.cz/projects/memcached-win32/
1. Unzip the binaries in your desired directory (eg. c:\memcached)
2. Install the service using the command: 'c:\memcached\memcached.exe -d install' from either the command line
3. Start the server from the Microsoft Management Console or by running the following command: 'c:\memcached\memcached.exe -d start'
4. Use the server, by default listening to port 11211
or 5 memcached.exe -v -d start -m 128 -l 127.0.0.1 -p 11211
This starts memcached.exe up as a daemon, using 128mb of memory, and listening on IP 127.0.01, port 11211.
package memcache;
import com.danga.MemCached.*;

public class MemCacheClient {
// create a static client as most installs only need
// a single instance
protected static MemCachedClient mcc = new MemCachedClient();

// set up connection pool once at class load
static {

// server list and weights
String[] servers =
{
//"10.139.201.51:11211",
"127.0.0.1:11211",
//"server2.mydomain.com:1624",
//"server3.mydomain.com:1624"
};

Integer[] weights = { new Integer(3), new Integer(3), new Integer(2) };

// grab an instance of our connection pool
SockIOPool pool = SockIOPool.getInstance();

// set the servers and the weights
pool.setServers( servers );
pool.setWeights( weights );

// set some basic pool settings
// 5 initial, 5 min, and 250 max conns
// and set the max idle time for a conn
// to 6 hours
pool.setInitConn( 5 );
pool.setMinConn( 5 );
pool.setMaxConn( 250 );
pool.setMaxIdle( 1000 * 60 * 60 * 6 );

// set the sleep for the maint thread
// it will wake up every x seconds and
// maintain the pool size
pool.setMaintSleep( 30 );

// set some TCP settings
// disable nagle
// set the read timeout to 3 secs
// and don't set a connect timeout
pool.setNagle( false );
pool.setSocketTO( 3000 );
pool.setSocketConnectTO( 0 );

// initialize the connection pool
pool.initialize();


// lets set some compression on for the client
// compress anything larger than 64k
mcc.setCompressEnable( true );
mcc.setCompressThreshold( 64 * 1024 );
}
/**
* http://jehiah.cz/projects/memcached-win32/
* 1. Unzip the binaries in your desired directory (eg. c:\memcached)
2. Install the service using the command: 'c:\memcached\memcached.exe -d install' from either the command line
3. Start the server from the Microsoft Management Console or by running the following command: 'c:\memcached\memcached.exe -d start'
4. Use the server, by default listening to port 11211

memcached.exe -v -d start -m 128 -l 10.139.201.51 -p 11211
* @param arg
*/
public static void main(String arg[]) {
mcc.set( "foo", "This is a test String" );
String bar = String.valueOf(mcc.get( "foo" ));
System.out.println(bar);
}
}