Overloading

  • define numerous methods that share the same name but different method signature
  • overloaded methods differ in number, type and order of arguments

Method Signature

  • unique identifier comprised of:
    • name
    • number, type and order of arguments
  • Does not contain return type or throws clause

Type casting

  • compiler chooses the method that has the closest argument type in order of implicit casting
  • Here print(100) will match to int, if not present then go for long, if not present then go for double and so on…
  • See Casting
public class Test {
    public static void print(short a) {
        System.out.println("short arg: " + a);
    }
 
    public static void print(int a) {
        System.out.println("int arg: " + a);
    }
 
    public static void print(long a) {
        System.out.println("long arg: " + a);
    }
 
    public static void print(double a) {
        System.out.println("double arg: " + a);
    }
 
    public static void main(String[] args) {
        print(100); // int arg: 100
    }
}

Type Erasure

  • If the overloading/overriding methods have same type erasure, then it is not possible to overload/override them
  • Following works:
class NumberUtils {
    static void print(String name) {
        System.out.println(name);
    }
 
    static void print(Integer mark) {
        System.out.println(mark);
    }
}
  • Following will cause compile error, because methods have same type erasure:
class NumberUtils {
    static void print(List<String> names) {
        for (var name:names) {
            System.out.println(name);
        }
    }
    
    static void print(List<Integer> marks) {
        for (var mark:marks) {
            System.out.println(mark);
        }
    }
}

Overloading constraints

  • https://www.baeldung.com/java-method-signature-return-type
  • Method Signature contains:
    • method name
    • order and type of parameters
  • Does not contain
    • return type
    • access or non-access modifiers
    • throws declaration
    • name of parameters
  • Type erasure changes the effective signature
    • T extends Serializable changes to Serializable
    • T (without upper bound) effectively changes to Object
public class OverloadingErrors<T extends Serializable> {
 
    // Type erasure causes T to replace with upper bound: Serializable
    public void printElement(T t) {
        System.out.println("Signature is: printElement(T)");
    }
 
    // causes compile time error during static binding
    public void printElement(Serializable o) {
        System.out.println("Signature is: printElement(Serializable)");
    }
}
  • Subclass and Superclass
    • obj.sum(Integer.valueOf(2), Integer.valueOf(3))
      • matches with sum(Integer, Integer)
    • obj.sum(2, 3)
      • No exact match found
      • auto boxes int to Integer
      • matches sum(Integer, Integer)
    • obj.sum(2, 0x1)
      • No exact match found
      • Type promotion from byte value to int and then auto-boxes to Integer
      • matches sum(Integer, Integer)
    • obj.sum(2.0d, 3.0d)
      • No exact match found
      • double auto-boxes to Double
      • Double is closest to Number compared to Object
      • matches sum(Number, Number)
    • obj.sum(Float.valueOf(2), Float.valueOf(3))
      • No exact match found
      • Float is closest to Number compared to Object
      • matches sum(Number, Number)
 
public Number sum(Integer term1, Integer term2) {
    System.out.println("Adding integers");
    return term1 + term2;
}
 
public Number sum(Number term1, Number term2) {
    System.out.println("Adding numbers");
    return term1.doubleValue() + term2.doubleValue();
}
 
public Number sum(Object term1, Object term2) {
    System.out.println("Adding objects");
    return term1.hashCode() + term2.hashCode();
}
  • Varargs
    • obj.sum(1, 2)
      • matches sum(Integer, Integer)
    • obj.sum(1, 2, 3)
      • matches sum(Integer, Integer...)
    • obj.sum(1, new Integer[] {2})
      • matches sum(Integer, Integer...)
public Integer sum(Integer term1, Integer term2) {
    // ...
}
 
// effective signature is sum(Object, Object[])
public Integer sum(Integer term1, Integer... term2) {
    // ...
}
 
// causes compile time error 
// since sum(Object, Object[]) is already present
public Integer sum(Integer term1, Integer[] term2) {
    // ...
}