-1

Effective:The choice of which overloading to invoke is made at compile time. Example:

class parentsecond{
    public int getdouble(int x){ return x*2;}
}
class second extends parentsecond{
    public int getdouble(int x){ return x*3;}
}
class third{
    public static void calloverload(parentsecond s){
        System.out.println(s.getdouble(4));
    }
    public static void calloverload(second s){
        System.out.println(s.getdouble(4));
    }

    public static void main(String[] args){
        third t=new third();
        parentsecond s=new second();
        t.calloverload(s);
    }

}

Answer is 12. And the behaviour is the same for instance method overloaded method too.

So in either case ,the decision of which overloaded method is invoked is made at run-time rather than compile time(its always 'second's' getdouble which is invoked).

So there are some qualifications to this particular item in 'Effective Java' that I did not get.

Please help clarify what was meant by 'resolving overloading at compile-time'.

How is the above different from this:

....

    class fourth{

            public static String getCollection(Set<?> s){
                return "Set";
            }
            public static String getCollection(Collection<?> c){
                return "Collection";
            }   

            public  String getiCollection(Set<?> s){
                return "Set";
            }
            public  String getiCollection(Collection<?> c){
                return "Collection";
            }       

            public static void main(String[] args){

                Collection<String> c=new HashSet<String>();
                System.out.println(fourth.getCollection(c));
                fourth f=new fourth();
                System.out.println(f.getiCollection(c));
...

This answer in this case is always 'Collection' rather than the actual run-time type.

IUnknown
  • 9,301
  • 15
  • 50
  • 76

2 Answers2

2

The declared type of s is parentsecond so when the compiler runs through the code, it will assign the method that takes parentsecond as an argument

public static void calloverload(parentsecond s)...

However, overriding is a different subject. The actual type of the instance s is second and so second's getdouble method will be executed. This is a case of polymorphism. In java, polymorphism is accomplished through late-binding.

To quote from this answer:

The JLS states in §8.4.9 Overloading:

  1. 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).
  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).

The argument is s and its compile time type is parentsecond. Its run time type is second.

EDIT To answer the addition to your question, see point 1 above. Nothing needs to be evaluated at run time. The compiler uses the compile time type, Collection, in both calls.

Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Makes perfect sense now.When I do print out which overloaded version of 'calloverload' is being called - its indeed the ne which accepts the parent.It then calls getdouble on the run-time version of the passed-in class. – IUnknown Apr 06 '13 at 03:22
  • @IUnknown I'm happy this helped. You should heed what _Russell_ said below. When Overloading methods, try not to use subtypes. – Sotirios Delimanolis Apr 06 '13 at 03:23
0

The point is not that the compiler can't figure it out; the point is that overloading is confusing for the programmer, and is therefore likely to cause bugs.

If you need to pull out the JLS in order to figure out which method is the most specific match to the way you are calling it, then every maintenance programmer who ever looks at that code will have to go through the same exercise.

Hence, the suggestion that overloads should have different numbers of parameters, or at least parameter types that are not interconvertible.

The specific danger of "resolving overloading at compile time" is this. Suppose I have:

void method(List a) { }
void method(Collection a) { }

Then, these two calls will do different things:

List list = new ArrayList();
method(list);
method((Collection)list);

This is highly unintuitive (hence confusing, hence a source of bugs) for the programmer.

Russell Zahniser
  • 16,188
  • 39
  • 30