Thursday, June 18, 2009

Choosing the Most Specific Method - Tricky Overloading


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 specific method 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 String and 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 other overloaded 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!
}
}


Before I conclude let me thank Ranvijay (one of our regular visitors), who inquired about the underlying reason of this behavior via an email. I thought it would probably be helpful to other visitors as well and hence posted a full article. Keep contributing Ranvijay!

Liked the article? Subscribe to this blog for regular updates. Wanna follow it to tell the world that you enjoy GeekExplains? Please find the 'Followers' widget in the rightmost sidebar.



Share/Save/Bookmark


Thursday, June 11, 2009

Initializer Blocks & their alternatives in Java


Initializer Blocks in Java and their possible alternatives

Initializer Blocks - what are they, why & how are they used?


These blocks are similar to the static initialization blocks with the only difference being the absence of the 'static' keyword. The Java compiler copies all the initializer blocks in the same order as they are in the source code in every constructor before any executable statement in that constructor.



public class InitializationWithInitializerBlock{

public static int staticIntField = 100;
private boolean instanceBoolField;

{
boolean y;

y = true; //or, y = <some expression returning a boolean value>;

instanceBoolField = y;
}
}


So if you see all your constructors having same code-segment at the top then you will probably be better off keeping that in an initializer block as anyway the compiler would copy the block in every constructor at the top. This way you can at least make the code more readable, maintainable (as the common code will only be at one place), and if the size of common code is significant and if you have multiple constructors then using initializer block you can also reduce the size of your source code.


public class InitializerBlocks {

public static void main(String[] args) {
new InitializerBlocks();
}
//Constructor - 1
public InitializerBlocks(){
System.out.println("3");
}
//Initializer Block - 1
{
System.out.println("1");
}
//Initializer Block - 2
{
System.out.println("2");
}
}

Output

1
2
3

(Of course the above code is not making a good use of initializer blocks as they not initializing anything what they are actually meant to. The purpose here is just to show how a Java compiler places all the initializer blocks at the top in every constructor in the same order as they appear in the code.)

Alternative to Initializer Blocks in Java


You can use an instance method to initialize an instance field - in most of the cases you would like to make this instance method as 'final' as there will hardly be any need for the subclasses to override such a method (evidently, a non-final instance method would also do the job). Similarly if you need to call the method only from within the same class, you would probably make it 'private'.
Read more about how to pick access modifiers - choosing suitable access control modifiers in Java >>


public class InitializationWithPrivateInstanceMethod{

public static int staticIntField = 100;
private boolean instanceBoolField = privInstanceMeth();

private final boolean privInstanceMeth() {
boolean y;
//computing the value of y
y = <some expression returning boolean>;
return y;
}
}


The advantage of using an instance method over an initializer block is that it gives you flexibility of re-initializing those instance fields by calling the corresponding final instance method(s) in some setter or in some other method. Another interesting scenario where you can't use an initializer block and you would probably need an instance method to do it for you: Suppose you have a need of using the code of initializer block in any of your sub-classes and suppose all your constructors have extra code as well in addition to the initializer block code which would be added to them on the top during compilation. Now in such a situation, if you need to set only those fields which are set in the initializer block then you can't do that directly in your subclass as the most you can do here is to call a super class constructor (that too would normally re-set all the instance fields) ... right? Having a final instance method would solve your problem here. Choosing a suitable access specifier will again follow the same rules what has been discussed in article mentioned in above paragraph. In this case since the sub-classes require access to that method, so choosing 'protected' as the access specifier should be fine.


Liked the article? Subscribe to this blog for regular updates. Wanna follow it to tell the world that you enjoy GeekExplains? Please find the 'Followers' widget in the rightmost sidebar.



Share/Save/Bookmark


Sunday, June 7, 2009

Static Initialization Blocks & their alternatives


Static Initialization Blocks and their alternatives in Java

Why do we need Static Initialization Blocks?


The easiest way of initializing fields (static or instance) in Java at the time of their declaration is simply by providing a compile time constant value of a compatible data type. For example:



public class InitializationWithConstants{

public static int staticIntField = 100;
private boolean instanceBoolField = true;

}


This type of initialization has its limitation due to its simplicity and it can not support initialization based even on some moderately complex logic - like initializing only selected elements of a complex array using some logic in a for loop.

Here comes the need for static initialization blocks and initializer blocks for initializing static and instance fields, respectively.


Static Initialization Blocks - what are they and how to use them?


It's a normal block of code enclosed within a pair of braces and preceded by a 'static' keyword. These blocks can be anywhere in the class definition where we can have a field or a method. The Java runtime guarantees that all the static initialization blocks are called in the order in which they appear in the source code and this happens while loading of the class in the memory.



public class InitializationWithStaticInitBlock{

public static int staticIntField;
private boolean instanceBoolField = true;

static{
//compute the value of an int variable 'x'
staticIntField = x;
}
}


Since static initialization blocks are actually code-blocks so they will allow us to initialize even those static fields which require some logical processing to be done for them to get their initial values.


Alternative to Static Initialization Blocks


A private static method is a suitable alternative to the static initialization blocks. In fact it has some advantages over static initialization blocks as well like you can re-use a private static method to re-initialize a static field in case you need it. So, you kind of get more flexibility with a private static method in comparison to the corresponding static initialization block. This should not mislead that a 'public' static method can't do the same. But, we are talking about a way of initializing a class variable and there is hardly any reason to make such a method 'public'.
More about how to pick the access control modifiers here - Choosing a suitable access control modifier >>


public class InitializationWithPrivateStaticMethod{

public static int staticIntField = privStatMeth();
private boolean instanceBoolField = true;

private static int privStatMeth() {
//compute the value of an int variable 'x'
return x;
}
}


Liked the article? Subscribe to this blog for regular updates. Wanna follow it to tell the world that you enjoy GeekExplains? Please find the 'Followers' widget in the rightmost sidebar.



Share/Save/Bookmark