why this code does not give compilation error? [duplicate] - java

I came across this question in a quiz,
public class MoneyCalc {
public void method(Object o) {
System.out.println("Object Verion");
}
public void method(String s) {
System.out.println("String Version");
}
public static void main(String args[]) {
MoneyCalc question = new MoneyCalc();
question.method(null);
}
}
The output of this program is "String Version". But I was not able to understand why passing a null to an overloaded method chose the string version. Is null a String variable pointing to nothing ?
However when the code is changed to,
public class MoneyCalc {
public void method(StringBuffer sb) {
System.out.println("StringBuffer Verion");
}
public void method(String s) {
System.out.println("String Version");
}
public static void main(String args[]) {
MoneyCalc question = new MoneyCalc();
question.method(null);
}
}
it gives a compile error saying "The method method(StringBuffer) is ambiguous for the type MoneyCalc"

Is null a String variable pointing to nothing ?
A null reference can be converted to an expression of any class type. So in the case of String, this is fine:
String x = null;
The String overload here is chosen because the Java compiler picks the most specific overload, as per section 15.12.2.5 of the JLS. In particular:
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.
In your second case, both methods are still applicable, but neither String nor StringBuffer is more specific than the other, therefore neither method is more specific than the other, hence the compiler error.

Additionally, the JLS 3.10.7 also declares that "null" is a literal value of the "null type". Therefore there exists a type called "null".
Later, the JLS 4.1 states that there exists a null type of which is impossible to declare variables, but you can use it through the null literal only. Later it says:
The null reference can always undergo a widening reference conversion
to any reference type.
Why the compiler chooses to widen it to String might well be explained in Jon's answer.

You can assign a string to a null value so it is valid and the order for java and most programming languages is fit to the closest type and then to object.

To answer the question in the title: null is neither a String nor an Object, but a reference to either can be assigned to null.
I'm actually surprised this code even compiles. I tried something similar previously and I got a compiler error saying that the call was ambiguous.
However, in this case, it seems like the compiler is choosing the method which is lowest on the food chain. It's assuming that you want the least generic version of the method in order to help you out.
I'll have to see if I can dig up the example where I got a compiler error in this (seemingly) exact same scenario, though...]
EDIT: I see. In the version I made, I had two overloaded methods accepting a String and an Integer. In this scenario, there is no "most specific" parameter (as in Object and String), so it can't choose between them, unlike in your code.
Very cool question!

As String type is more specific than Object type. Let's say you add one more method that takes an Integer type.
public void method(Integer i) {
System.out.println("Integer Version");
}
Then you will get a compiler error saying that the call is ambiguous. As now we two equally specific methods with same precedence.

Java compiler gives most derived class type to assign null.
Here is the example to understand it :
class A{
public void methodA(){
System.out.println("Hello methodA");
}
}
class B extends A{
public void methodB(){
System.out.println("Hello methodB");
}
}
class C{
public void methodC(){
System.out.println("Hello methodC");
}
}
public class MyTest {
public static void fun(B Obj){
System.out.println("B Class.");
}
public static void fun(A Obj){
System.out.println("A Class.");
}
public static void main(String[] args) {
fun(null);
}
}
output: B Class.
on the other hand:
public class MyTest {
public static void fun(C Obj){
System.out.println("B Class.");
}
public static void fun(A Obj){
System.out.println("A Class.");
}
public static void main(String[] args) {
fun(null);
}
}
Result : The method fun(C) is ambiguous for the type MyTest
Hope it will help to understand this case better.

Source: https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5
Concept: Most specific method
Explanation: 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. Try casting the null on to specific type and the method you wish will be automatically called.

I would say neither. NULL is a state not a value. Check out this link for more info on this (the article applies to SQL, but I think it helps with your question as well).

Related

Weird behavior when overloading using variable arguments with primitive types in java

Clearly I've not enough knowledge of how overloading, autoboxing and variable arguments work.
So here's the program causing trouble whenever there's an involvement of primitive types.
public static void z(int a, Object...objects){
}
public static void z(Object...objects){
}
public static void main(String[] args) {
z(); // no error
z(4); // Compile time Error : Ambiguous
z2(); // No error
z2(true, "sadas"); // Error
// No problem with reference types
z3(); // No error. String one called
z3(5); // No error. Object one called
z4(); // Error
z4(4); // Error
z4("asdas"); // Working properly
}
public static void z2(boolean b, Object...objects){
}
public static void z2(Object...objects){
}
public static void z3(String...objects){
System.out.println("String one called");
}
public static void z3(Object...objects){
System.out.println("Object one called");
}
public static void z4(int...objects){
System.out.println("int z4 called");
}
public static void z4(Object...objects){
System.out.println("Object z4 called");
}
Can anybody explain why any of this is happening? I can happily use Integer, Boolean instead of int, boolean but would very much like to know internal working behind it.
A method call will not compile if the compiler cannot determine which of the overloaded method variants it should use.
Let's use z4 as an example:
The method call z4() fits the signature of both variants.
The method call z4(4) also fits the signature of both variants because the variable can be auto-boxed.
The method call z4("asdas") is not ambiguous, as String cannot be cast to int.
Update: the rules for resolving overloaded method calls are as follows:
The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.
...
The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the third phase.
...
The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.
If more than one variant is selected in the same phase, then the most specific one is chosen,* but in short z3(String...) is more specific than z3(Object...), while z4(int...) and z4(Object...) are equally specific.
*The rules for determining this most specific variant are somewhat complicated (see here)
Thats a fab question
Now consider
public static void z2(boolean b, Object... objects) {
}
public static void z2(Object... objects) {
}
Both methods have a vararg argument, which means they will both be considered on the third and final phase of overloading resolution.
Remember Object class is the mother of all objects in java
Well this explains one thing
The compiler can treat both as object which will result in object array again.
Now finally
void z2(boolean b, Object... objects)
public static void z2(Object... objects)
is treated as same function.
To check you can comment
z2(true);
z2(true, "sadas");
removing either of
public static void z2(boolean b, Object... objects) {
}
Or
public static void z2(Object... objects) {
}
This will work.
But
You have taken object inside parameter
If you are specific for example
public static void z2(boolean b, String... objects) {
}
public static void z2(String... objects) {
}
z2(); // No error
z2(true, "sadas"); // No error
This way it can be resolved

Passing NULL to Overloading while checking Specificity in two Cases [duplicate]

If I write this line in Java:
JOptionPane.showInputDialog(null, "Write something");
Which method will be called?
showInputDialog(Component parent, Object message)
showInputDialog(Object message, Object initialSelectionValue)
I can test it. But in other cases similar to this, I want to know what happens.
The most specific method will be called - in this case
showInputDialog(Component parent, Object message)
This generally comes under the "Determine Method Signature" step of overload resolution in the spec (15.12.2), and in particular "Choosing the Most Specific Method".
Without getting into the details (which you can read just as well in the spec as here), the introduction gives a good summary:
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.
The informal intuition is that one
method is more specific than another
if any invocation handled by the first
method could be passed on to the other
one without a compile-time type error.
In your particular case the more specific method will be called. In general, though, there are some cases where the method signature can be ambiguous. Consider the following:
public class Main {
public static void main(String[] args) {
Main m = new Main();
m.testNullArgument(null);
}
private void testNullArgument( Object o )
{
System.out.println("An Object was passed...");
}
private void testNullArgument( Integer i )
{
System.out.println("An Integer was passed...");
}
private void testNullArgument( String s )
{
System.out.println("A String was passed...");
}
}
In this case, the compiler can't decide between the method that takes an Integer and the method that takes a String. When I try to compile that, I get
reference to testNullArgument is ambiguous, both method testNullArgument(java.lang.Integer) in testnullargument.Main and method testNullArgument(java.lang.String) in testnullargument.Main match
Neither. You'll get a compiler error asking you to clarify what method you want to call. You can do so by explicitly casting the first argument:
showInputDialog((Object) null, "Write something");
or
showInputDialog((Component) null, "Write something");
Update I should have known - never doubt Jon Skeet. The problem I've referred to above only occurs when it's impossible to determine which method is more specific. Here's a test case:
public class Test {
public void doSomething(String arg1, Object arg2) {
System.out.println("String, Object");
}
public void doSomething(Object arg1, String arg2) {
System.out.println("Object, String");
}
public static void main(String[] args) {
Test test = new Test();
test.doSomething(null, null);
}
}
The above will give a compiler error.

How do overloaded methods work?

public class Test1 {
public static void main(String[] args) {
Test1 test1 = new Test1();
test1.testMethod(null);
}
public void testMethod(String s){
System.out.println("Inside String Method");
}
public void testMethod(Object o){
System.out.println("Inside Object Method");
}
}
When I try to run the given code, I get the following output:
Inside String Method
Can anyone explain why the method with the String type parameter is getting called?
most specific method argument is chosen for overloaded methods
In this case, String is subclass of Object. Hence String becomes more specific than Object. Hence Inside String method is printed.
Directly from JLS-15.12.2.5
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 BMT and LastFreeNickName have correctly suggested, (Object)null will cause overloaded method with Object type method to be called.
Adding on to an existing reply, I'm not sure if this is because of a newer Java version since the question, but when I tried to compile the code with a method taking an Integer as a parameter instead of an Object, the code still did compile. However, the call with null as the parameter still invoked the String parameter method at run-time.
For example,
public void testMethod(int i){
System.out.println("Inside int Method");
}
public void testMethod(String s){
System.out.println("Inside String Method");
}
will still give the output:
Inside String Method
when called as:
test1.testMethod(null);
The main reason for this is because String does accept null as a value and int doesn't. So null is classified as a String Object.
Coming back to the question asked, The type Object is encounter only when a new object is created. This is done by either type casting null as an Object by
test1.testMethod((Object) null);
or using any type of object for a primitive data type such as
test1.testMethod((Integer) null);
or
test1.testMethod((Boolean) null);
or by simply creating a new object by
test1.testMethod(new Test1());
It should be noted that
test1.testMethod((String) null);
will again invoke the String method as this would create an object of type String.
Also,
test1.testMethod((int) null);
and
test1.testMethod((boolean) null);
will give a compile time error since boolean and int do not accept null as a valid value and as int!=Integer and boolean!=Boolean.
Integer and Boolean type cast to Objects of type int and boolean.

How is an overloaded method chosen when a parameter is the literal null value?

I came across this question in a quiz,
public class MoneyCalc {
public void method(Object o) {
System.out.println("Object Verion");
}
public void method(String s) {
System.out.println("String Version");
}
public static void main(String args[]) {
MoneyCalc question = new MoneyCalc();
question.method(null);
}
}
The output of this program is "String Version". But I was not able to understand why passing a null to an overloaded method chose the string version. Is null a String variable pointing to nothing ?
However when the code is changed to,
public class MoneyCalc {
public void method(StringBuffer sb) {
System.out.println("StringBuffer Verion");
}
public void method(String s) {
System.out.println("String Version");
}
public static void main(String args[]) {
MoneyCalc question = new MoneyCalc();
question.method(null);
}
}
it gives a compile error saying "The method method(StringBuffer) is ambiguous for the type MoneyCalc"
Is null a String variable pointing to nothing ?
A null reference can be converted to an expression of any class type. So in the case of String, this is fine:
String x = null;
The String overload here is chosen because the Java compiler picks the most specific overload, as per section 15.12.2.5 of the JLS. In particular:
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.
In your second case, both methods are still applicable, but neither String nor StringBuffer is more specific than the other, therefore neither method is more specific than the other, hence the compiler error.
Additionally, the JLS 3.10.7 also declares that "null" is a literal value of the "null type". Therefore there exists a type called "null".
Later, the JLS 4.1 states that there exists a null type of which is impossible to declare variables, but you can use it through the null literal only. Later it says:
The null reference can always undergo a widening reference conversion
to any reference type.
Why the compiler chooses to widen it to String might well be explained in Jon's answer.
You can assign a string to a null value so it is valid and the order for java and most programming languages is fit to the closest type and then to object.
To answer the question in the title: null is neither a String nor an Object, but a reference to either can be assigned to null.
I'm actually surprised this code even compiles. I tried something similar previously and I got a compiler error saying that the call was ambiguous.
However, in this case, it seems like the compiler is choosing the method which is lowest on the food chain. It's assuming that you want the least generic version of the method in order to help you out.
I'll have to see if I can dig up the example where I got a compiler error in this (seemingly) exact same scenario, though...]
EDIT: I see. In the version I made, I had two overloaded methods accepting a String and an Integer. In this scenario, there is no "most specific" parameter (as in Object and String), so it can't choose between them, unlike in your code.
Very cool question!
As String type is more specific than Object type. Let's say you add one more method that takes an Integer type.
public void method(Integer i) {
System.out.println("Integer Version");
}
Then you will get a compiler error saying that the call is ambiguous. As now we two equally specific methods with same precedence.
Java compiler gives most derived class type to assign null.
Here is the example to understand it :
class A{
public void methodA(){
System.out.println("Hello methodA");
}
}
class B extends A{
public void methodB(){
System.out.println("Hello methodB");
}
}
class C{
public void methodC(){
System.out.println("Hello methodC");
}
}
public class MyTest {
public static void fun(B Obj){
System.out.println("B Class.");
}
public static void fun(A Obj){
System.out.println("A Class.");
}
public static void main(String[] args) {
fun(null);
}
}
output: B Class.
on the other hand:
public class MyTest {
public static void fun(C Obj){
System.out.println("B Class.");
}
public static void fun(A Obj){
System.out.println("A Class.");
}
public static void main(String[] args) {
fun(null);
}
}
Result : The method fun(C) is ambiguous for the type MyTest
Hope it will help to understand this case better.
Source: https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5
Concept: Most specific method
Explanation: 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. Try casting the null on to specific type and the method you wish will be automatically called.
I would say neither. NULL is a state not a value. Check out this link for more info on this (the article applies to SQL, but I think it helps with your question as well).

String constructor with null value

why String (String) constructor with null value cause compile-time error? I think there is 2+ constructor that takes Object and when init. it with null it doesn't know which to start. I'm wonder if there is another reason
String s = new String(null); // compile time error
StringBuffer sb = new StringBuffer(null); // no error
Normally, when you call a constructor or method for which multiple overridden versions might apply, Java will choose the most specific constructor or method. Section 15.12.2 of the Java Language Specification explains this in detail.
Suppose you have two overloaded methods, like this:
public void method(Object o) {
// ...
}
public void method(String s) {
// ...
}
When you call method(null), both these methods apply. Java chooses the most specific one, which is in this case the second method, that takes a String - because String is a more specific type than Object.
However, sometimes the most specific constructor or method cannot be determined. If we look at the constructors of class String that take one argument:
String(byte[] bytes)
String(char[] value)
String(String original)
String(StringBuffer buffer)
String(StringBuilder builder)
Note that there is no hierarchy between the types byte[], char[], String, StringBuffer and StringBuilder, so it's not possible to say that one of these constructors is more specific than the others. So, the Java compiler doesn't know which constructor to choose and will give you an error.
Because, compiler couldn't figure out which constructor to call. See here that how many one-argument-constructor it has.
[Edited]
You said, if there is another reason. So why not try out yourself. Do something like this,
byte[] b = null;
String s = new String(b); // complier should be fine with this
char[] c = null;
String s = new String(c); // complier should be fine with this
.... // you can try other constructors using similar approach.
Just to add more clarity to the solution:
Take this example:
public class Test {
public Test(Object obj) {
System.out.println("Object");
}
public Test(String obj) {
System.out.println("String");
}
public static void main(String[] args) {
new Test(null);
}
}
It will not throw any compile time error as compiler will choose the most specific constructor of available same types. However, if I change the class to:
public class Test {
public Test(Long lg){
System.out.println("Long");
}
public Test(Object obj) {
System.out.println("Object");
}
public Test(String obj) {
System.out.println("String");
}
public static void main(String[] args) {
new Test(null);
}
}
It will throw compile time error. As two separate constructor hierarchies are involved here and compiler has no way to make a decision.
One hierarchy is: Object-->String and second is Object-->Long so no way to choose between Long or String type constructors.
String has many constructors. null is available for them.
Edit: String has 5 one-argument-constructor, in Java 6. Thanks BoltClock and Adeel Ansari!

Categories