in the first call new A() its obious that you get the empty constructor called since you don't pass anything and prints ... Default
in the second call new a("hi") since you pass a string your second constructor gets called and prints ... String
in the third you are passing a null and null dosen't mean its empty so it finds for a constructor with something that can be assigned a null values wich is the second constructor so it prints ... String
if you add a third constructor for example:
you will still get the same result since String is more specific than Object however if you add a fourth constructor for example:
you will get a compilation error since the compiler will not be able to decide to which constructor to assign the null value, A(Integer) or A(String)
hope you got the point ;)
Omar Al Kababji - Electrical & Computer Engineer
[SCJP - 90% - Story] [SCWCD - 94% - Story] [SCBCD - 80% - Story] | My Blog
But just an add on. All object references can take null values. If you try any primitive types , again the call is gonna go to the String constructor, which you have mentioned in your code...
Well, if you call the constructor with a primitive type, and if you had a constructor with an Object parameter, the call would be resolved to that constructor (but that constructor is not part of the original code.) The call would never be resolved to the constructor that takes a String parameter, you would get a compiler error.
For the case where you have a constructor that takes an Object parameter, when you call the constructor with a primitive type, first you would autobox the primitive into the corresponding wrapper class, and then widening would take place (boxing plus widening.)
There are some interesting theoretical ways that you can look at null (and the null type.) The null literal is a representation of the only instance of the null type, and any reference can be assigned the null literal (which is equivalent to saying that null is an acceptable value for a reference of any type.) The way you can look at it is that the null type is at the bottom of the hierarchy, so when you do
A = null;
that's always going to work, because upcasting never fails. In that sense, you could think of the null type and Object as complete opposites, with Object sitting at the top of the hierarchy, and the null type at the bottom. This is just a theoretical way to look at it though, because if the null type actually sat at the bottom of the hierarchy, that would mean that java would support multiple inheritance, which as we know it doesn't. This explanation is just an imaginary construct to explain why you can assign null to any reference type, which is a special case anyway.
One thing to be careful with though is this: Once you have assigned null to a reference variable, the reference still has the null value, but at that point the null value becomes a value of the type of the reference, so you have to abide by the regular casting restrictions:
String s = null;
Integer i = null;
i = s; // Compiler error
There are a lot of subtleties to be considered.
All code in my posts, unless a source is explicitly mentioned, is my own.
Omar Al Kababji
Joined: Jan 13, 2009
Hi Ruben you said
i see there is a duplicate variable named "i" which causes a compiler error but i don't think this is what you meant, so i suppose you meant something like this:
just for making it more understandable ;)
Joined: Dec 16, 2008
Yes, thanks Omar. I wasn't thinking about the duplicate declaration, just trying to illustrate the point.
You can downcast and upcast at will when the reference value on the right side is null:
Object o = null;
String s = (String) o;
String s1 = null;
Object o1 = s1;
But you can't do the Integer-String casting, because that is a compile-time error.