AP CSA 1.9 — Method Signatures (2025)

Introduction

In Java, a method’s signature determines which method is called. Understanding what is and is not part of a signature is essential for reading APIs and writing overloaded methods.

Learning goals

  • Identify what constitutes a Java method signature (per AP): method name + parameter types and order.
  • Distinguish parameters vs arguments; return type is NOT part of the signature.
  • Explain method overloading and how Java selects an overload.
  • Write valid method headers and call them correctly.
  • Trace evaluation for calls with literals, variables, and expressions.

Quick reference

  • Signature (AP scope): methodName(type1, type2, ...) — only name + parameter types/order.
  • Not in signature: return type, parameter names, access modifiers.
  • Overloading: same name, different parameter lists (type and/or arity and/or order).
  • Calls: arguments must be compatible with the parameter types (with standard promotions/widening allowed).
  • Return: a method declared void returns nothing; non-void must return a value of its declared type.
  • Widening at call site: intdouble allowed; narrowing requires explicit cast.

Example: runnable Java class (overloading)

public class SigDemo {
    public static int add(int a, int b) {          // signature: add(int, int)
        return a + b;
    }
    public static double add(double a, double b) { // signature: add(double, double)
        return a + b;
    }
    public static int add(int a) {                 // signature: add(int)
        return a + 1;
    }
    public static int increment(int a) {           // different name
        return a + 1;
    }
    public static void main(String[] args) {
        System.out.println(add(3, 4));     // 7
        System.out.println(add(3.0, 4));   // 7.0
        System.out.println(add(5));        // 6
        System.out.println(increment(9));  // 10
    }
}

What is and isn’t in a signature

  • In AP CSA scope, signature = name + parameter types and order: name(T1, T2, ...).
  • NOT in signature: return type, parameter names, access modifiers, throws clauses.
  • Therefore, you cannot overload by changing only the return type.

Not overloading by return type (concept)

  • Changing only the return type does not create a new signature.
  • If two methods differ only by return type and are otherwise identical, it’s a compile-time error.
  • Tip: Change parameter types/arity/order to overload correctly.

Runnable example: Overload resolution with literals and variables

public class OverloadPick {
    static void show(int x)    { System.out.println("int:" + x); }
    static void show(double x) { System.out.println("double:" + x); }
    static void show(long x)   { System.out.println("long:" + x); }

    public static void main(String[] args) {
        show(5);     // int literal → show(int)
        show(5L);    // long literal → show(long)
        show(5.0);   // double literal → show(double)
        int i = 7; long L = 7L; double d = 7.0;
        show(i); show(L); show(d);
    }
}

Ambiguity and overload selection (concept)

  • Java prefers the most specific applicable method without narrowing.
  • int literal can widen to long or convert to float; integral widening to long is typically chosen.
  • Avoid ambiguous designs: provide distinct parameter lists or cast at the call site to disambiguate.

Popcorn Hack: Write and test max overloads

Instructions: Write two overloaded methods named max that each return the larger of two numbers.

One should accept two int values.

The other should accept two double values.

Then, test both versions in the main method.

public class PopcornMax {
    // TODO: write int version of max
    // TODO: write double version of max

    public static void main(String[] args) {
        System.out.println(max(3, 9));      // expected: 9
        System.out.println(max(-2, -7));    // expected: -2
        System.out.println(max(3.5, 2.9));  // expected: 3.5
        System.out.println(max(2, 2.0));    // should call double version → 2.0
    }
}

public class PopcornMax {
    static int max(int a, int b) {
        if (a > b) {
            return a;
        } else {
            return b;
        }
    }

    static double max(double a, double b) {
        if (a > b) {
            return a;
        } else {
            return b;
        }
    }

    public static void main(String[] args) {
        System.out.println(max(3, 9));      // expected: 9
        System.out.println(max(-2, -7));    // expected: -2
        System.out.println(max(3.5, 2.9));  // expected: 3.5
        System.out.println(max(2, 2.0));    // should call double version → 2.0
    }
}

PopcornMax.main(new String[]{});
9
-2
3.5
2.0

Popcorn Hack 1 Answer:

public class PopcornMax {
    // int overload
    public static int max(int a, int b) {
        return a >= b ? a : b;
    }

    // double overload
    public static double max(double a, double b) {
        return a >= b ? a : b;
    }

    public static void main(String[] args) {
        System.out.println(max(3, 9));      // 9
        System.out.println(max(-2, -7));    // -2
        System.out.println(max(3.5, 2.9));  // 3.5
        System.out.println(max(2, 2.0));    // 2.0  (int 2 promoted to double → calls max(double,double))
    }
}

Popcorn Hack: Overload print for int and String

Instructions:Implement two overloaded print methods — one that accepts an int and prints int: and another that accepts String and prints str:. Test with mixed types.

public class PopcornPrint {
    // TODO: write print(int n)
    // TODO: write print(String s)

    public static void main(String[] args) {
        print(42);          // expected: int:42
        print("hello");     // expected: str:hello
        print('A' + "!");   // char + String → String → expected: str:A!
    }
}

public class PopcornPrint {
    // TODO: write print(int n)
    static void print(int n) {
        System.out.println("int: " + n);
    }
    // TODO: write print(String s)
    static void print(String s) {
        System.out.println("str: " + s);
    }

    public static void main(String[] args) {
        print(42);          // expected: int:42
        print("hello");     // expected: str:hello
        print('A' + "!");   // char + String → String → expected: str:A!
    }
}

PopcornPrint.main(new String[]{})
int: 42
str: hello
str: A!

Popcorn Hack 2 Answer:

public class PopcornPrint {
    static void print(int n) {
        System.out.println("int:" + n);
    }

    static void print(String s) {
        System.out.println("str:" + s);
    }

    public static void main(String[] args) {
        print(42);          // int:42
        print("hello");     // str:hello
        print('A' + "!");   // str:A!
    }
}

Parameter passing (concept)

  • Primitives are passed by value. Changing the parameter does not change the argument in the caller.
  • E.g., calling bump(a) does not modify a outside the method.
public class FrqTemplates {
    // FRQ 1
    // TODO: implement sumRange(start, end) — sum inclusive, return 0 if start > end
    public static int sumRange(int start, int end) {
        if (start > end) return 0;
        int sum = 0;
        for (int n = start; n <= end; n++) {
            sum += n;
        }
        return sum;
    }

    // FRQ 2
    // TODO: implement area(radius) -> circle area (double)
    // TODO: implement area(width, height) -> rectangle area (int)
    public static double area(double radius) {
        return radius * radius * Math.PI;
    }

    public static int area(int width, int height) {
        return width * height;
    }

    // FRQ 3
    // TODO: implement formatScore(earned, total) -> "earned/total"
    // TODO: implement formatScore(percent) -> "xx.x%"
    public static String formatScore(int earned, int total) {
        // returns something like "45/50"
        return earned + "/" + total;
    }

    public static String formatScore(double percent) {
        // returns something like "92.4%"
        return String.format("%.1f%%", percent);
    }

    public static void main(String[] args) {
        System.out.println(sumRange(1, 5));      // expected: 15
        System.out.println(area(3.0));           // expected: ~28.27
        System.out.println(area(3, 4));          // expected: 12
        System.out.println(formatScore(45, 50)); // expected: 45/50
        System.out.println(formatScore(92.35));  // expected: 92.4%
    }
}

// Run
FrqTemplates.main(new String[]{});

15
28.274333882308138
12
45/50
92.4%

FRQ-style runnable templates

Instructions:Practice FRQ-style overloaded methods. Implement sumRange, overloaded area (circle and rectangle), and overloaded formatScore (fraction and percent).

FRQ Answer Key:

public class FrqTemplates {
    // FRQ 1: Sum all integers from start to end (inclusive)
    public static int sumRange(int start, int end) {
        if (start > end) return 0;
        int sum = 0;
        for (int n = start; n <= end; n++) {
            sum += n;
        }
        return sum;
    }

    // FRQ 2: Overload area for circle vs. rectangle
    public static double area(double radius) {
        return Math.PI * radius * radius;
    }
    public static int area(int width, int height) {
        return width * height;
    }

    // FRQ 3: Overload formatScore for fraction vs. percent
    public static String formatScore(int earned, int total) {
        return earned + "/" + total;
    }
    public static String formatScore(double percent) {
        return String.format("%.1f%%", percent);
    }

    public static void main(String[] args) {
        System.out.println(sumRange(1, 5));      // 15
        System.out.println(area(3.0));           // ~28.274333882308138
        System.out.println(area(3, 4));          // 12
        System.out.println(formatScore(45, 50)); // 45/50
        System.out.println(formatScore(92.35));  // 92.4%
    }
}

Anatomy of a method header (AP scope)

  • General form: modifiers returnType name(parameterList)
  • Signature considered in AP: name(parameterTypesInOrder)
  • Examples:
    • public static int sum(int a, int b) → signature sum(int,int)
    • private double area(double r) → signature area(double)

Overloading checklist

  • Different parameter count and/or parameter types and/or order
  • Same method name
  • Return type alone does not differentiate

Common pitfalls

  • Ambiguity between numeric types (int, long, float, double)
  • Unintended autowidening creates a different overload call than expected
  • Shadowing due to parameter names does not matter to signature

Best practices

  • Keep overloads consistent in behavior and naming
  • Prefer clear, non-ambiguous parameter lists
  • Add documentation examples showing which overload is picked