Study guide

3.6 Method Overloading, Overload Resolution, and Varargs

Oracle Java SE 21 Developer 1Z0-830

Track your progress as you read

Finished sections get a check mark.

1 Chapter 1: Java Basics, Primitive Types, and Operators

1.1 Program Structure, Primitives, Literals, Scopes, and var 1.2 Operators, Precedence, and Type Casting 1.3 Strings, Text Blocks, and StringBuilder 1.4 Date and Time APIs (java.time)

2 Chapter 2: Controlling Program Flow & Pattern Matching

2.1 Conditional Logic: if-else and Ternary Operators 2.2 Switch Statements and Switch Expressions 2.3 Pattern Matching for switch and instanceof 2.4 Loops and Branching Statements

3 Chapter 3: Object-Oriented Design & Class Architecture

3.1 Class Declarations, Constructors, and Object Lifecycle 3.2 Encapsulation and Access Modifiers 3.3 Inheritance, Method Overriding, and Polymorphism 3.4 Abstract Classes and Interfaces 3.5 Nested, Inner, Local, and Anonymous Classes 3.6 Method Overloading, Overload Resolution, and Varargs

4 Chapter 4: Modern Java Data Modeling: Records, Enums, and Sealed Types

4.1 Java Records, Canonical/Compact Constructors, and Component Accessors 4.2 Java Enums: Fields, Methods, and Abstract Constant-Specific Behavior 4.3 Sealed Classes and Interfaces: permits, final, non-sealed, and Hierarchy Architecture 4.4 Advanced Record Patterns (JEP 440), Nested Deconstruction, and Sealed Hierarchy Exhaustiveness

5 Chapter 5: Exception Handling and Annotations

5.1 Exception Hierarchy: Checked vs. Unchecked Exceptions 5.2 Exception Handling: try, catch, finally, and Multi-Catch 5.3 Resource Management: try-with-resources and AutoCloseable 5.4 Custom Exceptions and Best Practices 5.5 Java Annotations: Built-in, Meta-Annotations, and Custom Types

6 Chapter 6: Generics and the Collections Framework

6.1 Generics Fundamentals and Generic Methods 6.2 Wildcards, Type Bounds, and Type Erasure 6.3 Core Collections: Lists, Sets, Queues, and Maps 6.4 Sequenced Collections in Java 21 6.5 Sorting, Comparable, and Comparator 6.6 Arrays: Creation, Multidimensional Forms, and the Arrays Utility Class

7 Chapter 7: Functional Programming & Lambda Expressions

7.1 Built-in Functional Interfaces in java.util.function 7.2 Lambda Expressions, Variable Scopes, and Effectively Final 7.3 Method References: Four Varieties and Edge Cases 7.4 Working with java.util.Optional

8 Chapter 8: The Stream API and Data Pipelines

8.1 Stream Creation and Intermediate Operations 8.2 Terminal Operations and Reductions 8.3 Advanced Collectors, Grouping, Partitioning, and Teeing 8.4 Primitive Streams and Parallel Stream Processing

9 Chapter 9: Concurrency, Multithreading, and Virtual Threads

9.1 Thread Fundamentals, Creation, and Lifecycle 9.2 Thread Safety, Synchronization, and the Java Memory Model 9.3 Concurrency Utilities: ExecutorService, Callable, and Future 9.4 Concurrent Collections, Atomics, and Explicit Locks 9.5 Virtual Threads in Java 21 (Carrier Threads, Pinning, and Best Practices)

10 Chapter 10: The Java Platform Module System (JPMS)

10.1 Module Architecture and module-info.java Declarations 10.2 Module Directives: requires, exports, opens, provides, and uses 10.3 Modular Compilation, Packaging, and CLI Execution 10.4 Module Types, Migration Strategies, ServiceLoader SPI, and JLink

11 Chapter 11: Java I/O, NIO.2, and Object Serialization

11.1 Classic Java I/O Streams and Readers/Writers 11.2 Java NIO.2 File API: Path, Paths, and File System Operations 11.3 Advanced NIO.2 Stream Operations and Directory Traversal 11.4 Java Object Serialization and Record Serialization

12 Chapter 12: Implementing Localization and Internationalization

12.1 Locales and Resource Bundles 12.2 Formatting and Parsing Numbers, Currencies, Dates, Times, and Messages

3.6 Method Overloading, Overload Resolution, and Varargs

Key Takeaways Explain This Topic AI

A method signature is the name plus the number, types, and order of parameters; return type, throws clause, parameter names, and modifiers are excluded, so two methods differing only in return type do not compile.

Overload resolution runs three passes and stops at the first that finds a candidate: strict (widening primitive only), loose (adds boxing/unboxing), then variable arity, so widening beats boxing and boxing beats varargs.

A method invocation conversion may widen a primitive or box it but never widen then box, so passing an int to a Long parameter fails while passing it to an Object parameter succeeds.

A var-arg parameter compiles to an array, must be last, and may appear at most once; f(int...) and f(int[]) therefore clash as duplicate signatures.

Omitting all var-arg arguments passes a zero-length array, but passing a bare null passes null as the entire array, so reading its length throws NullPointerException.

Last updated: September 2026

Method Overloading, Overload Resolution, and Varargs

Oracle lists "Implement overloaded methods, including var-arg methods" as its own sub-objective under Using Object-Oriented Concepts in Java , and the 1Z0-830 exam mines it relentlessly. Overloading questions rarely ask "is this legal?" — they show four candidate methods, one call, and ask which one runs . Getting that right means knowing the compiler's resolution algorithm, not guessing.

1. What Actually Distinguishes Two Overloads

A method signature consists of the method name plus the number, types, and order of its formal parameters. Nothing else counts:

Element Part of the signature?

  • Method name Yes
  • Parameter types and their order Yes
  • Parameter names No
  • Return type No
  • throws clause No
  • Access modifier ( public , private ) No
  • static / final / synchronized No int parse(String s) { return 0; }
  • long parse(String s) { return 0L; } // ERROR: same signature, only return type differs
  • void log(String msg) { }
  • void log(String message) { } // ERROR: parameter names are irrelevant
  • void log(String msg) throws IOException { } // ERROR: throws is not part of the signature
  • Legal overloads must differ in arity or in at least one parameter type : void log(String msg) { }
  • void log(String msg, int level) { } // OK: different arity
  • void log(StringBuilder msg) { } // OK: different parameter type

Caution

Generic type arguments are erased, so handle(List<String>) and handle(List<Integer>) collide (see section 6.2). Erasure runs before the duplicate-signature check.

2. The Three-Phase Resolution Algorithm

When several overloads share a name, the compiler runs up to three passes and stops at the first pass that finds at least one applicable method . This ordering is the single highest-yield fact in this section.

Phase Conversions allowed Varargs considered?

1 — Strict Identity, subtyping, widening primitive ( int → long → float → double ) No

2 — Loose Everything in phase 1, plus boxing/unboxing , and boxing followed by a widening reference conversion No

3 — Variable arity Everything in phase 2, plus varargs expansion Yes

The practical slogan: widening beats boxing, and boxing beats varargs. static void f(long x) { System.out.print("long "); }

  • static void f(Integer x) { System.out.print("Integer "); }
  • static void f(Object x) { System.out.print("Object "); }
  • static void f(int... x) { System.out.print("varargs "); }

f(5); // prints "long"

Now delete the overloads one at a time and re-run f(5) :

  • Remaining overloads Winner Why
  • long , Integer , Object , int... long Phase 1 succeeds via widening int → long
  • Integer , Object , int... Integer Phase 2; Integer is more specific than Object
  • Object , int... Object Phase 2 via boxing then widening reference conversion
  • int... only int... Only phase 3 has an applicable method
  • The Conversion That Does Not Exist

A method invocation conversion may widen a primitive or box it , but never both in that order: static void g(Long x) { }

  • g(5); // ERROR: int -> long -> Long is not a method invocation conversion
  • g(5L); // OK: long -> Long is a plain boxing conversion
  • g((long) 5); // OK

The reverse direction is legal, because boxing may be followed by a widening reference conversion: int → Integer → Number → Object .

3. Choosing Between Reference Overloads

Within a single phase, the compiler picks the most specific applicable method — the one whose parameter type can be passed to all the others. static void h(Object o) { System.out.print("Object"); }

static void h(String s) { System.out.print("String"); }

h(null); // prints "String" — String is more specific than Object

If two candidates are unrelated, neither is more specific and the call is ambiguous : static void k(String s) { }

static void k(StringBuilder b) { }

  • k(null); // ERROR: reference to k is ambiguous
  • k((String) null); // OK — the cast picks the overload
  • Overloading Is Resolved at Compile Time

This is the trap that separates overloading from overriding. Overriding dispatches on the runtime object; overloading is decided from the declared type of the argument expression: Object value = "hello"; // declared Object, runtime String

  • h(value); // prints "Object", NOT "String"
  • 4. Var-Arg Methods

A variable-arity (var-arg) parameter is written Type... name and is compiled to Type[] .

Declaration rules

A method may declare at most one var-arg parameter.

It must be the last parameter: void report(String label, int... values) is legal; void report(int... values, String label) is not.

void f(int... a) and void f(int[] a) cannot coexist — after desugaring they have the same signature, and the compiler rejects the class.

Call-site behaviour static int total(String label, int... values) { return values.length; }

  • total("a"); // 0 -> an EMPTY array is created, never null
  • total("a", 1, 2, 3); // 3
  • total("a", new int[]{1, 2, 3}); // 3 -> an existing array may be passed directly

Important

Passing a bare null to a var-arg parameter passes it as the whole array , not as one element. values is then null , and values.length throws NullPointerException . Write total("a", (int) 0) for a single element, or cast — printAll((Object) null) — when the parameter is Object... .

Ambiguity between var-arg overloads is resolved by the same most-specific rule, applied to the element types: static void show(Object... args) { System.out.print("Object..."); }

static void show(String... args) { System.out.print("String..."); }

  • show("a", "b"); // prints "String..." — String[] is a subtype of Object[]
  • show(1, "b"); // prints "Object..." — only this one is applicable

Because generic var-args create an unchecked heap-pollution warning, mark provably safe generic var-arg methods with @SafeVarargs (section 5.5) — it is permitted only on static , final , or private instance methods and on constructors.

5. Exam Traps Checklist

Autoboxing never outranks widening. f(5) with f(long) and f(Integer) present picks long .

Varargs is always last resort , even when it looks like an exact match.

int → Long fails ; int → Object succeeds.

Null with two unrelated reference overloads is ambiguous , not "picks the first one".

A missing var-arg argument yields a zero-length array , so values.length is 0 , never an exception.

f(int...) and f(int[]) clash ; f(int...) and f(int, int) do not.

Return type differences never create an overload.

Loading diagram... Three-Phase Overload Resolution and Its Failure Modes