• Home
  • LLMs
  • Docker
  • Kubernetes
  • Java
  • All
  • About
Java | Method Overloading
  1. Method Overloading
  2. Method Invocation Resolution
  3. Ambiguous Method Calls
  4. Method Resolution Priority
  5. Varargs and Overloading

  1. Method Overloading
    Method overloading is a mechanism that allows defining multiple versions of a method with the same name in the same class.

    The fundamental rule is: the parameter list must be different (either in number and/or types of parameters) for each overloaded method.

    The return type, modifiers, and exceptions thrown by the overloaded methods can be the same or different; these aspects do not affect overloading resolution.
    package com.mtitek.overloading;
    
    public class TestClass {
        public Integer multiplyOperation(Integer value1, Integer value2) {
            return value1 * value2;
        }
    
        public Double multiplyOperation(Double value1, Double value2) {
            return value1 * value2;
        }
    
        public static void main(String[] args) {
            TestClass testClass = new TestClass();
    
            System.out.println(testClass.multiplyOperation(5, 10)); // calls multiplyOperation(Integer, Integer)
    
            System.out.println(testClass.multiplyOperation(5.0, 10.0)); // calls multiplyOperation(Double, Double)
        }
    }
    A method defined in a superclass can be overloaded in a subclass by adding methods with different parameter lists.

    Note: Changing a method's parameter list creates overloading, while keeping the same signature but changing the implementation creates overriding.
  2. Method Invocation Resolution
    Method invocation for overloaded methods is resolved statically at compile time. The compiler examines the arguments passed in the method call and their types to determine which overloaded method will be invoked at runtime.

    When overloading methods with parameter types that have inheritance relationships, the compiler selects the most specific method that matches the argument types.
    package com.mtitek.overloading;
    
    public class TestClass {
        public void doSomething(TestClass testClass) {
            System.out.println("TestClass parameter: " + testClass.toString());
        }
    
        public void doSomething(Object obj) {
            System.out.println("Object parameter: " + obj.toString());
        }
    
        public static void main(String[] args) {
            TestClass testClass = new TestClass();
            Object obj = testClass;
    
            testClass.doSomething(testClass); // calls doSomething(TestClass)
    
            testClass.doSomething(obj); // calls doSomething(Object) - reference type determines method
    
            testClass.doSomething((TestClass) obj); // calls doSomething(TestClass) - explicit cast changes compile-time type
        }
    }
    Note: When a method is invoked on a reference (refVar.method()), the compiler only considers methods available to the declared type of that reference and its supertypes. If the desired method is not accessible through the reference type, a compilation error occurs.

    Explicit casting can change the compile-time type of a reference, allowing access to methods specific to the cast type ((SpecificType) obj).
  3. Ambiguous Method Calls
    Ambiguous method calls occur when the compiler cannot determine which overloaded method to invoke, typically when passing null values or when multiple methods are equally specific matches.
    package com.mtitek.overloading;
    
    public class TestClass {
        public void doSomething(String str) {
            System.out.println("String: " + str);
        }
    
        public void doSomething(Integer num) {
            System.out.println("Integer: " + num);
        }
    
        public void doSomething(Object obj) {
            System.out.println("Object: " + obj);
        }
    
        public static void main(String[] args) {
            TestClass testClass = new TestClass();
    
            // testClass.doSomething(null); // Compiler error: The method doSomething(String) is ambiguous for the type TestClass
    
            testClass.doSomething((String) null); // OK: Explicit cast
            testClass.doSomething((Integer) null); // OK: Explicit cast
            testClass.doSomething((Object) null); // OK: explicit cast
    
            String str = null;
            testClass.doSomething(str); // OK: Variable with specific type
    
            testClass.doSomething("Hello"); // OK: Calls doSomething(String)
            testClass.doSomething((Object) "Hello"); // OK: Calls doSomething(Object)
        }
    }
  4. Method Resolution Priority
    Java follows a specific priority order when resolving overloaded method calls:
    1. Exact match - Direct type match.
    2. Widening - Primitive type promotion (int → long → float → double).
    3. Autoboxing - Primitive to wrapper conversion.
    4. Varargs - Variable argument methods.

    package com.mtitek.overloading;
    
    public class TestClass {
        public void doSomething(int value) {
            System.out.println("int: " + value);
        }
    
        public void doSomething(long value) {
            System.out.println("long: " + value);
        }
    
        public void doSomething(Integer value) {
            System.out.println("Integer: " + value);
        }
    
        public void doSomething(int... values) {
            System.out.println("varargs: " + java.util.Arrays.toString(values));
        }
    
        public void doSomethingElse(Long value) {
            System.out.println("Long wrapper: " + value);
        }
    
        public static void main(String[] args) {
            TestClass testClass = new TestClass();
    
            byte b = 1;
            testClass.doSomething(b); // Calls doSomething(int) - widening
            testClass.doSomething(1); // Calls doSomething(int) - exact match
            testClass.doSomething(1L); // Calls doSomething(long) - exact match
            testClass.doSomething(Integer.valueOf(1)); // Calls doSomething(Integer) - exact match
    
            int i = 1;
            testClass.doSomethingElse(i); // Compiler error: The method doSomethingElse(Long) in the type TestClass is not applicable for the arguments (int)
    
            Integer j = 1;
            testClass.doSomethingElse(Integer.valueOf(i)); // Compiler error: The method doSomethingElse(Long) in the type TestClass is not applicable for the arguments (Integer)
    
            long k = 1l;
            testClass.doSomethingElse(k); // Calls doSomething(Long) - autoboxing
    
            testClass.doSomething(Integer.valueOf(1), Integer.valueOf(2)); // Calls doSomething(int...) - varargs match
        }
    }
  5. Varargs and Overloading
    Variable arguments (varargs) introduce special considerations in method overloading. Varargs methods can cause ambiguity when combined with other overloaded methods.
    package com.mtitek.overloading;
    
    public class TestClass {
        public void doSomething(String str) {
            System.out.println("String: " + str);
        }
    
        public void doSomething(String... strs) {
            System.out.println("String varargs: " + java.util.Arrays.toString(strs));
        }
    
        public void doSomething(int... nums) {
            System.out.println("int varargs: " + java.util.Arrays.toString(nums));
        }
    
        public void doSomething(int i, int... nums) {
            System.out.println("int + int varargs: " + i + ", " + java.util.Arrays.toString(nums));
        }
    
        public void doSomethingElse(String... strs) {
            System.out.println("String varargs: " + java.util.Arrays.toString(strs));
        }
    
        public void doSomethingElse(Object... objs) {
            System.out.println("Object varargs: " + java.util.Arrays.toString(objs));
        }
    
        public static void main(String[] args) {
            TestClass testClass = new TestClass();
    
            testClass.doSomething("a"); // Calls doSomething(String) - exact match
            testClass.doSomething("a", "b", "c"); // Calls doSomething(String...) - varargs
            testClass.doSomething(); // Compiler error: The method doSomething(String[]) is ambiguous for the type TestClass
    
            testClass.doSomething(1); // Compiler error: The method doSomething(int[]) is ambiguous for the type TestClass
            testClass.doSomething(1, 2, 3); // Compiler error: The method doSomething(int[]) is ambiguous for the type TestClass
    
            testClass.doSomethingElse("a", "b"); // Calls doSomethingElse(String...) - varargs
            testClass.doSomethingElse(new Object(), "test"); // Calls doSomethingElse(Object...) - varargs
            testClass.doSomethingElse(); // Calls doSomething(String...) - empty varargs
        }
    }
© 2025  mtitek