Why this behavior in overloading [duplicate] - java

This question already has answers here:
Strange Java null behavior in Method Overloading [duplicate]
(4 answers)
Closed 8 years ago.
When I run this program why it is calling method overloaded with string parameter.
public class StaticBindTest {
public static void main(String args[]) {
StaticBindTest et = new StaticBindTest();
et.sort(null);
}
//overloaded method
public void sort(Object c){
System.out.println("Inside Collection sort method");
}
//another overloaded method
public void sort(String hs){
System.out.println("Inside HashSet sort method");
}
}
In case if I re-write my method as
public void sort(String hs){
if(hs instanceof String)
System.out.println("Inside HashSet sort method");
}
It will display blank console, which means it is not a instance of String then why it call in this manner?

t's because In case of method Overloading
The most specific method is choosen at compile time.
As 'java.lang.String' is a more specific type than 'java.lang.Object'. In your case the method which takes 'String' as a parameter is choosen.
Clearly mentioned in DOCS

When I execute your code, I found Inside HashSet sort method is in output. null is empty reference to object. Both methods have Object as input that is why the method with more narrow hierarchy String is called.
Do not write StaticBindTest et = new StaticBindTest(); Just call sort(null) without object et.

The full methodology is explained in section 15.12.2 of the JLS, and in particular 15.12.2.5 (choosing the most specific).
The summary is that Java always chooses the most specific overload that is applicable. Since null can be an instance of any class, both methods are candidates. And since String is a subclass of Object, it is definitely more specific. Hence the String overload is called.
As for your closing paragraph, null is not an instanceof anything. If you had written your Object-overload method in a similar way, it also would not have printed anything - so this is not strong evidence as to whether Java should have chosen one overload or another.

Related

Cast an object to its specific type at runtime Java [duplicate]

I'm experimenting with this code:
interface Callee {
public void foo(Object o);
public void foo(String s);
public void foo(Integer i);
}
class CalleeImpl implements Callee
public void foo(Object o) {
logger.debug("foo(Object o)");
}
public void foo(String s) {
logger.debug("foo(\"" + s + "\")");
}
public void foo(Integer i) {
logger.debug("foo(" + i + ")");
}
}
Callee callee = new CalleeImpl();
Object i = new Integer(12);
Object s = "foobar";
Object o = new Object();
callee.foo(i);
callee.foo(s);
callee.foo(o);
This prints foo(Object o) three times. I expect the method selection to take in consideration the real (not the declared) parameter type. Am I missing something? Is there a way to modify this code so that it'll print foo(12), foo("foobar") and foo(Object o)?
I expect the method selection to take
in consideration the real (not the
declared) parameter type. Am I missing
something?
Yes. Your expectation is wrong. In Java, dynamic method dispatch happens only for the object the method is called on, not for the parameter types of overloaded methods.
Citing the Java Language Specification:
When a method is invoked (§15.12), the
number of actual arguments (and any
explicit type arguments) and the
compile-time types of the arguments
are used, at compile time, to
determine the signature of the method
that will be invoked (§15.12.2). If
the method that is to be invoked is an
instance method, the actual method to
be invoked will be determined at run
time, using dynamic method lookup
(§15.12.4).
As mentioned before overloading resolution is performed at compile time.
Java Puzzlers has a nice example for that:
Puzzle 46: The Case of the Confusing Constructor
This puzzle presents you with two Confusing constructors. The main method invokes a constructor,
but which one? The program's output depends on the answer. What does the program print, or is it
even legal?
public class Confusing {
private Confusing(Object o) {
System.out.println("Object");
}
private Confusing(double[] dArray) {
System.out.println("double array");
}
public static void main(String[] args) {
new Confusing(null);
}
}
Solution 46: Case of the Confusing Constructor
...
Java's overload resolution process operates in two phases. The first phase selects all the methods or constructors that are accessible and applicable. The second phase selects the most specific of the methods or constructors selected in the first phase. One method or constructor is less specific than another if it can accept any parameters passed to the other [JLS 15.12.2.5].
In our program, both constructors are accessible and applicable. The constructor
Confusing(Object) accepts any parameter passed to Confusing(double[]), so
Confusing(Object) is less specific. (Every double array is an Object, but not every Object is a double array.) The most specific constructor is therefore Confusing(double[]), which explains the program's output.
This behavior makes sense if you pass a value of type double[]; it is counterintuitive if you pass null. The key to understanding this puzzle is that the test for which method or constructor is most specific does not use the actual parameters: the parameters appearing in the invocation.
They are used only to determine which overloadings are applicable. Once the compiler determines which overloadings are applicable and accessible, it selects the most specific overloading, using only the formal parameters: the parameters appearing in the declaration.
To invoke the Confusing(Object) constructor with a null parameter, write new
Confusing((Object)null). This ensures that only Confusing(Object) is applicable. More
generally, to force the compiler to select a specific overloading, cast actual parameters to the declared types of the formal parameters.
Ability to dispatch a call to a method based on types of arguments is called multiple dispatch. In Java this is done with Visitor pattern.
However, since you're dealing with Integers and Strings, you cannot easily incorporate this pattern (you just cannot modify these classes). Thus, a giant switch on object run-time will be your weapon of choice.
In Java the method to call (as in which method signature to use) is determined at compile time, so it goes with the compile time type.
The typical pattern for working around this is to check the object type in the method with the Object signature and delegate to the method with a cast.
public void foo(Object o) {
if (o instanceof String) foo((String) o);
if (o instanceof Integer) foo((Integer) o);
logger.debug("foo(Object o)");
}
If you have many types and this is unmanageable, then method overloading is probably not the right approach, rather the public method should just take Object and implement some kind of strategy pattern to delegate the appropriate handling per object type.
I had a similar issue with calling the right constructor of a class called "Parameter" that could take several basic Java types such as String, Integer, Boolean, Long, etc. Given an array of Objects, I want to convert them into an array of my Parameter objects by calling the most-specific constructor for each Object in the input array. I also wanted to define the constructor Parameter(Object o) that would throw an IllegalArgumentException. I of course found this method being invoked for every Object in my array.
The solution I used was to look up the constructor via reflection...
public Parameter[] convertObjectsToParameters(Object[] objArray) {
Parameter[] paramArray = new Parameter[objArray.length];
int i = 0;
for (Object obj : objArray) {
try {
Constructor<Parameter> cons = Parameter.class.getConstructor(obj.getClass());
paramArray[i++] = cons.newInstance(obj);
} catch (Exception e) {
throw new IllegalArgumentException("This method can't handle objects of type: " + obj.getClass(), e);
}
}
return paramArray;
}
No ugly instanceof, switch statements, or visitor pattern required! :)
Java looks at the reference type when trying to determine which method to call. If you want to force your code you choose the 'right' method, you can declare your fields as instances of the specific type:
Integeri = new Integer(12);
String s = "foobar";
Object o = new Object();
You could also cast your params as the type of the param:
callee.foo(i);
callee.foo((String)s);
callee.foo(((Integer)o);
If there is an exact match between the number and types of arguments specified in the method call and the method signature of an overloaded method then that is the method that will be invoked. You are using Object references, so java decides at compile time that for Object param, there is a method which accepts directly Object. So it called that method 3 times.

Overloading method with parent type and child type argument and passing null while calling. Why method with childtype argument is getting called [duplicate]

I have added three methods with parameters:
public static void doSomething(Object obj) {
System.out.println("Object called");
}
public static void doSomething(char[] obj) {
System.out.println("Array called");
}
public static void doSomething(Integer obj) {
System.out.println("Integer called");
}
When I am calling doSomething(null) , then compiler throws error as ambiguous methods. So is the issue because Integer and char[] methods or Integer and Object methods?
Java will always try to use the most specific applicable version of a method that's available (see JLS §15.12.2).
Object, char[] and Integer can all take null as a valid value. Therefore all 3 version are applicable, so Java will have to find the most specific one.
Since Object is the super-type of char[], the array version is more specific than the Object-version. So if only those two methods exist, the char[] version will be chosen.
When both the char[] and Integer versions are available, then both of them are more specific than Object but none is more specific than the other, so Java can't decide which one to call. In this case you'll have to explicitly mention which one you want to call by casting the argument to the appropriate type.
Note that in practice this problem occurs far more seldom than one might think. The reason for this is that it only happens when you're explicitly calling a method with null or with a variable of a rather un-specific type (such as Object).
On the contrary, the following invocation would be perfectly unambiguous:
char[] x = null;
doSomething(x);
Although you're still passing the value null, Java knows exactly which method to call, since it will take the type of the variable into account.
Each pair of these three methods is ambiguous by itself when called with a null argument. Because each parameter type is a reference type.
The following are the three ways to call one specific method of yours with null.
doSomething( (Object) null);
doSomething( (Integer) null);
doSomething( (char[]) null);
May I suggest to remove this ambiguity if you actually plan to call these methods with null arguments. Such a design invites errors in the future.
null is a valid value for any of the three types; so the compiler cannot decide which function to use. Use something like doSomething((Object)null) or doSomething((Integer)null) instead.
Every class in Java extends Object class.Even Integer class also extends Object. Hence both Object and Integer are considered as Object instance. So when you pass null as a parameter than compiler gets confused that which object method to call i.e. With parameter Object or parameter Integer since they both are object and their reference can be null. But the primitives in java does not extends Object.
I Have tried this and when there is exactly one pair of overloaded method and one of them has a parameter type Object then the compiler will always select the method with more specific type. But when there is more than one specific type, then the compiler throws an ambiguous method error.
Since this is a compile time event, this can only happen when one intentionally passes null to this method. If this is done intentionally then it is better to overload this method again with no parameter or create another method altogether.
class Sample{
public static void main (String[] args) {
Sample s = new Sample();
s.printVal(null);
}
public static void printVal(Object i){
System.out.println("obj called "+i);
}
public static void printVal(Integer i){
System.out.println("Int called "+i);
}
}
The output is Int called null and so ambiguity is with char[] and Integer
there is an ambiguity because of doSomething(char[] obj) and doSomething(Integer obj).
char[] and Integer both are the same superior for null that's why they are ambiguous.

WHY the method with String Parameter gets called and not the method with Object parameter [duplicate]

This question already has answers here:
How is an overloaded method chosen when a parameter is the literal null value?
(8 answers)
Closed 5 years ago.
class Jaguar
{
void method(Object o)
{
System.out.println("Object Called");
}
void method(String s)
{
System.out.println("String Called");
}
public static void main(String[] args)
{
Jaguar j=new Jaguar();
j.method(null);
}
}
Question:The o/p of the code is String Called and not ObjectCalled..Why?? null value is applicable to objects also..
Java will always try to use the most specific applicable version of a method that's available see: http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.5
Object and String can all take null as a valid value. Therefore all 3 version is applicable, so Java will have to find the most specific one.
Since Object is the supertype of String, the String version is more specific than the Object-version. So if only those two methods exist, the String version will be chosen.
Each pair of these three methods is ambiguous by itself when called with a null argument. Because each parameter type is a reference type.
The following are the three ways to call one specific method of yours with null.
doSomething( (Object) null);
doSomething( (String) null);
If you add one more method with object subclass example Integer then the compiler will throw ambiguous method error as in that case compiler cannot decide if which method can be called string one or integer one.
I hope this helps.

Java Void type - possible/allowed values?

1) In Java, I can do this:
Void z = null;
Is there any other value except null I can assign to z?
2) Consider the following code snipped:
Callable<Void> v = () -> {
System.out.println("zzz");
Thread.sleep(1000);
return null;
};
This compiles OK, but if I remove the last statement return null; it doesn't. Why? After all, Void is supposed to mean no return value.
From the docs:
The Void class is an uninstantiable placeholder class to hold a reference to the Class object representing the Java keyword void.
So, no.
Void is used by methods having to return an object, but really returning nothing.
A decent example can be observed with some usage of the AsyncTask in Android, in cases where you don't need to return any object after the task is complete.
You would then extend AsyncTask<[your params type], [your progress type], Void>, and return null in your onPostExecute override.
You wouldn't need it in most cases though (for instance, Runnable is typically more suitable than Callable<Void>).
Ansering your question more specifically:
But if I remove the return null it does not compile?! Why?
... because a Void is still an object. However, it can only have value null.
If your method declares it returns Void, you need to (explicitly) return null.
If you check the sources:
package java.lang;
public final class Void {
public static final Class<Void> TYPE = Class.getPrimitiveClass("void");
private Void() {
}
}
Void is:
final class;
has private constructor.
Without using Reflection it's not possible to assign anything but null to a reference of Void type.
In Java, I can do this Void z = null; Is there any other value (but null) which I can assign to z ?
You can if you create you own Void instances. You can use Reflection or Unsafe to create these, not that it's a good idea.
But if I remove the return null it does not compile?! Why? After all, Void is supposed to mean just that - no return type.
Java is case sensitive, this means that Boolean and boolean are NOT the same type nor is Void and void. Void is a notional wrapper for void but otherwise is just a class you shouldn't create any instance of.
Maybe what you are asking for is Runnable or Consumer - some interface that doesn't have a return value. Void only serves to show that you cannot expect anything else than null. It is still just a class, not a keyword or anything special. A class that cannot be instantiated, so you have to return null.
A lot of efforts were spent in designing lambda expression to treat int/Integer etc indistinguishably, so that int->Long will be compatible with Integer->long, etc.
It is possible (and desirable) to treat void/Void in a similar way, see comments from Goetz and Forax.
However, they didn't have the time to implement the idea for java8 :(
You can introduce an adapter type that is both ()->void and ()->Void; it can simplify your use case a little bit, see http://bayou.io/release/0.9/javadoc/bayou/util/function/Callable_Void.html
If you have a method that accepts ()->Void, it is not going to work well with ()->void lambdas. One workaround is to overload the method to accept ()->void. For example, ExecutorService
submit(Callable<T> task)
submit(Runnable task)
...
submit( System::gc ); // ()->void
However, overloading with functional parameter types is tricky... The example above works because both accept a zero-arg function. If the function has non-zero args
foo( Function<String,Void> f ) // String->Void
foo( Consumer<String> f ) // String->void
it's confusing to the compiler (and the programmer)
foo( str->System.out.println(str) ); // which foo?
foo( System.out::println ); // which foo?
Given an implicit lambda str->expr, the compiler needs a target type to make sense of it. The target type here is given by the method parameter type. If the method is overloaded, we need to resolve method overloading first... which typically depends on the type of the argument (the lambda)... So you can see why it is complicated.
(A zero-arg lambda is never implicit. All argument types are known, since there's no argument.)
The lambda spec does have provisions to resolve the following cases
foo( str->{ System.out.println(str); } );
foo( str->{ System.out.println(str); return null; } );
You may argue that in the previous example,
foo( str->System.out.println(str) );
since println(str) returns void, the Void version obviously does not fit, therefore the compiler should be able to resolve it. However, remember that, to know the meaning of println(str), first, the type of str must be resolved, i.e. method overloading of foo must be resolved first...
Although in this case, str is unambiguously String. Unfortunately, the lambda designer decided against to be able to resolve that, arguing it is too complicated. This is a serious flaw, and it is why we cannot overload methods like in Comparator
comparing( T->U )
//comparing( T->int ) // overloading won't work well
comparingInt ( T->int ) // use a diff method name instead

Instantiating a class, toString terms

I have two classes :
import android.cla;
public class CW {
public static void main(String [] args){
System.out.println(new cla());
}
}
public class Cl {
#Override
public String toString(){
return "LOL";
}
}
In the first class I'm calling the objects toString() method, which has been overriden and printing it to console. It clearly returns "LOL";
I have two questions :
Is it possible to return data while instantiating like this (new cla()) without overriding the objects toString() method; and
What is the proper term for instantiating classes like this (new cla()), that's without declaration like : Object l = new cla()
Thanks. Please correct me on the proper terms.
1 - No it isn't. A 'constructor' is a special method on the class that always returns an object instance of the class. The whole point of the constructor is to return the object. So no, it can't return anything else.
1a - The reason that System.out.println calls the toString method is because you are asking it to print out that object to the screen, and the toString method is the method chosen by the authors of println (and the Java language in general) to give a string representation of the object.
2 - That way of writing isn't really called anything. It's just an expression that you're passing as an 'actual parameter' to the println method. True, it's an expression that instantiates a new object, but it's no different to println("a string"). You could call it an anonymous object if you really wanted to.
2a - (old answer that doesn't actually answer your question but I'll keep it here) That's just called 'using a less derived reference† to a class'. Beware you can only call methods on the type of the reference, so if you added extra methods to your Cl class you couldn't call them from an Object reference. Look into Liskov substitution principle.
† 'less derived' or 'supertype' or 'superclass' or 'more general class' etc...

Categories