Roedy Green said:
public static void main(String args[]) {
Class1 c = new Class1);
c.method(null);
The choice of class implementing a method is dynamic based on the
runtime class of c, but the choice of which overloaded method depends
on the compile time declaration of types in the invocation. You
specified null which has no type information. So you gave Java no hint
as to which overloaded method to use. From the point of view of
maintainable code, this is a malformed program. It should not depend
on such fine points in the JLS as how it resolves this ambiguous case.
I'm new to Java and though I have lots of experience with C and and other
languages like Smalltalk, there are are a few things in Java that are
just not obvious that I need to understand to really learn the language
and the system of selecting between redundant overloaded methods is
exactly the type of thing I don't yet understand.
Because of this thread, I found a little time yesterday to play with it
and realized as you say that the selection is based on compile time hints
and not run time reality. Because when I do something like:
Object o
o = "string";
method(o);
The method used is method(Object) and not method(String) even though the
String method would be the obvious choice if it was a run time decision.
So it's using the compile time information (o is type Object) to make the
choice instead of the actual type of the object at run time.
But I'm having a hard time grasping how this is all actually implemented
and without a good model of how it's implemented I'm feeling at a loss to
really understand what it does in all cases.
I understand that on method calls, arguments can be automatically
converted to different types, such as an int to a double, or a int to an
Integer. But is the decision about the conversion always resolved at
compile time so the conversion will always happen as it was determined to
happen at compile time? Or is this a decision that is sometimes put off
to run time so it has to produce conditional conversions?
The issue it seems to me would come up when different possible objects
are the target of the method, and that the different objects have
different sets of redundant methods to choose from.
For example we have these sorts of classes and methods:
Class Superclass
method(double)
Class Subclass extends Superclass
method(double)
method(int)
And code like this:
Superclass s;
s = (either a Superclass object or a Subclass object);
s.method(int);
So, at run time, s might be either type of object. So depending on the
type of object, either the Superclass or the Subclass methods will be
called.
But if it's a Subclass object, it can use the int method and the argument
doesn't need to be converted. But if it's the Superclass, there is no
int method, so it will want to use the double method, and convert the
argument from int to double before passing it.
So what actually happens? Does the compiler prevent such a thing from
being coded? That is, you can't add extra overloaded methods in a
subclass? Or, since the type of the s variable is Superclass, does it
only use the methods defined in the Superclass to make the decision at
compile time, and produce the code to convert the int to a double, and
always call the double method even if the receiving object is a Subclass
object? i.e., in that case, the int method would just never be used
unless the declared type of the s variable was Subclass?
Or does it figure it all out at run time, and call the method with the
int arg when the object is a Subclass and do the conversion and call the
double method if the object is a Superclass object?
It seems the above example is exactly the type of thing that could catch
you off guard and create some unexpected bugs in your code depending on
what Java allows. That is, you try to add a new overloaded method in a
subclass to add some special handling of a specific type argument, and
the method never gets called because you were trying to apply it to an
object typed as Superclass in some sort of collection. In which case,
the whole point of polymorphism and overloading of methods would fail
you, and to make it work you would have to resort to producing code to
hand check for the object type before sending the method with something
like this:
Superclass s = (something unspecified);
if (s.getClass() == Subclass.class)
((Subclass)s).method(int);
else
s.method(int);
Or you could modify Superclass and add the method(int) as a stub to call
method(double) - which would not be an option if you couldn't modify the
superclass you were trying to use.
So, without me having to actually test the above special case, can
someone give me a better idea of how java actually implements method
calls so that I can feel like I have the power to predict how Java will
deal with these sorts of special cases without having to test each
special case I dream up? Most important, how much is it forced to decide
at compile time, and how much does it leave to run time in the selection
of overloaded methods and the auto-conversion of argument types?