Method Signature in Java: What It Includes (and What It Doesn’t)

Method Signatures in Java

In this article, we will get to know about method signatures in Java. So, by the end of reading this article, you will be able to answer what Java method signature is.

In real life, you may find many people having the same name as you. But how can we identify and differentiate the identities of all the people having the same name? One way for identification is signature matching.

Your signatures can act as a differentiator in this case. A similar thing happens in Java programming language, where we do this with the help of a method signature.

There is one question on this topic that confuses a lot of students: is the return type a part of the method signature or not? Different websites give different answers. So, in this article, we will not just tell you the answer. We will write the code, hand it to the Java compiler, and let the compiler settle it.

Are you ready to learn about the topic in detail? Well then, let's dive in!

Summary Of The Article:

  • Java method signature is used as a differentiator or an identifier for Java methods.
  • It is made of two things only: the method name and the types of the parameters, in their order.
  • The return type, the access modifier, the parameter names, and the throws part belong to the method declaration, but they are not part of the signature.
  • It helps us in determining how to use a method especially while using overloaded methods.
  • Method signature in Java also helps the Java compiler to match the correct method with its definition.

What Is A Method Signature In Java?

A method signature in the Java programming language is a unique value or an identifier that helps the Java compiler match the correct method with its definition. It helps us to know how a particular method is being used.

It consists of the method name and the parameter list in its definition. To be exact, it is the name plus the types of the parameters, in the order they are written. Let us take the first line of a method and pull the signature out of it.

public static int Codingzap(int a, int b) throws Exception

The signature of this method is:   Codingzap(int, int)

Everything else on that line, like public, static, the return type int, the names ‘a’ and ‘b’, and the throws part, is useful information about the method. But none of it is the signature. This is also how the official Java Tutorials from Oracle define it: the signature is "the method's name and the parameter types."

Note that method signatures are unique, therefore, if there is more than one method having the same method signature in the same class, it will lead to a compilation error. Thus, we should be careful while defining a Java method signature.

Now, let us learn about the components of a method signature in detail. Keep reading to know!

What Are The Components Of A Java Method Signature?

As stated above, a method signature consists of two components: the method name and the parameter list. A method declaration has a few more parts around them, like the return type and the modifiers. We will go through those as well, because you cannot write a method without them, and because this is where the confusion starts.

Let us know more about these components below.

Components Of A Java Method Signature

Method Name:

This signifies the name of the method you are creating the method signature for. A healthy practice for defining methods would be to follow the naming conventions so that your method name acts as a valid identifier.

Let us consider an example and name our method as Codingzap() and we will see how we can create a method signature for it. (By the Java naming convention, a method name should start with a lowercase letter, like calculateTotal(). We are using a capital ‘C’ here only because it is our name.)

Parameter List:

A parameter list or an argument list is nothing but a list of arguments or parameters that a method takes or expects to receive. This list of parameters is written inside the parenthesis that is followed by a method name. It is the same as a typical method declaration.

Here, let us suppose that our method Codingzap() is taking two method parameters 'a' and 'b'. The parameter types of these are int. So, how can we write its syntax for method declaration? See below!

void Codingzap(int a, int b)

For the signature, three things about the parameter list matter: how many parameters there are, what their types are, and in which order they come. The names ‘a’ and ‘b’ do not matter at all. We could rename them to ‘x’ and ‘y’ and the signature would still be Codingzap(int, int).

These two components, the name and the parameter types, are the whole signature. The parts below are written on the same line, but they are not part of it.

Return Type (Not Part Of The Signature):

A return type defines or specifies the data type of the value a method returns. So, for instance, if a method is returning a value, we need to specify its type before the method name.

In the above line, we have used the return type as 'void.' This is used if the method is not returning any value. Let us consider that our Codingzap() method adds the two parameters and returns their sum. Thus, the return type of it will be int.

Thus, the above method declaration will be written as:

int Codingzap(int a, int b)

We changed void to int, but the signature did not change. It was Codingzap(int, int) before, and it is Codingzap(int, int) now.

Besides these, we also have some additional components to the method declaration that may or may not be required depending on the program we are writing. However, it is also a bonus to know about them. These are the different modifiers like static, final, etc as well as access modifiers. Let us have a quick look at them as well.

Access Modifiers (Not Part Of The Signature):

We do not consider these as a part of the signature for a method, however, providing these to the method helps to determine how and where we can access the method.

There are three access modifier keywords in Java. These are public, private, and protected. A public method can be accessed anywhere in the program, while a private one is only accessible in the class. If we write none of the three, the method can be used by the classes of the same package. An example of syntax is below.

public double calculateAnswer()

Do Not Take Our Word For It: Let Us Ask The Compiler

So far, we have only said what is and what is not a part of the signature. Now, let us prove it. The rule we will use is simple. A class cannot have two methods with the same signature. So, we will write two methods that differ in just one thing and try to compile the class. If the compiler complains, that one thing is not part of the signature. If it compiles, it is.

Let us start with the big question, the return type.

public class Test {
    int Codingzap(int a, int b) {
        return a + b;
    }

    double Codingzap(int a, int b) {   // only the return type is different
        return a + b;
    }
}

The two methods have the same name and the same parameters. Only the return type is different, int in one and double in the other. Here is what the Java compiler (javac) said:

Test.java:6: error: method Codingzap(int,int) is already defined in class Test
    double Codingzap(int a, int b) {   // only the return type is different
           ^
1 error

Read the first line of the error carefully. The compiler itself calls the method Codingzap(int,int). It does not mention int or double as the return type anywhere. For the compiler, both methods are the same method, written twice. So, the answer is clear. The return type is not a part of the method signature.

We repeated the same test for the other parts, changing one thing each time. To save space, we are showing the results in a table. In every failing case, the error message was the same line as above.

What We Changed In The Second MethodDid It Compile?Part Of The Signature?
Return type (int to double)No. "already defined"No
Parameter names (a, b to first, second)No. "already defined"No
Modifiers (public in one, private static in the other)No. "already defined"No
Added throws ExceptionNo. "already defined"No
Parameter type (int to double)YesYes
Number of parameters (one to two)YesYes
Order of parameter types (int, String to String, int)YesYes

The last three rows are the changes that the compiler accepts. Here is the program for them. All five methods have the same name, and the class compiles without any complaint.

public class Legal {
    // Different parameter TYPE
    static String Codingzap(int a)    { return "Codingzap(int)"; }
    static String Codingzap(double a) { return "Codingzap(double)"; }

    // Different NUMBER of parameters
    static String Codingzap(int a, int b) { return "Codingzap(int, int)"; }

    // Different ORDER of parameter types
    static String Codingzap(int a, String b) { return "Codingzap(int, String)"; }
    static String Codingzap(String a, int b) { return "Codingzap(String, int)"; }

    public static void main(String[] args) {
        System.out.println(Codingzap(5));
        System.out.println(Codingzap(5.0));
        System.out.println(Codingzap(5, 6));
        System.out.println(Codingzap(5, "six"));
        System.out.println(Codingzap("five", 6));
    }
}

Output:

Codingzap(int)
Codingzap(double)
Codingzap(int, int)
Codingzap(int, String)
Codingzap(String, int)

For every call, Java looked at the arguments we passed and picked the method whose signature matched them.

Then Why Do Some Websites Say The Return Type Is Included?

One likely reason for the mix-up is worth knowing. Java code runs on the Java Virtual Machine (JVM), and inside the compiled .class file, the JVM keeps its own short description of every method. That description does include the return type. We can see it with the javap tool that comes with the JDK. We compiled this small Calculator class with two add() methods and ran javap -s Calculator on it.

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public double add(double a, double b) {
        return a + b;
    }
}

And this is what javap printed:

Compiled from "Calculator.java"
public class Calculator {
  public Calculator();
    descriptor: ()V

  public int add(int, int);
    descriptor: (II)I

  public double add(double, double);
    descriptor: (DD)D
}

In the descriptor lines, (II)I means "takes two ints, returns an int," and (DD)D means "takes two doubles, returns a double." So, at the JVM level, the return type is recorded. But that is the internal format of the class file. When your professor, your textbook, or the Java Language Specification says "method signature," they mean the language-level one: the name and the parameter types. That is the definition to write on your exam.

Method Declaration, Method Header, And Method Signature: Are They The Same?

These three terms are often used as if they mean the same thing. They do not, and questions like "write the signature of this method" depend on the difference.

  • The method declaration is the complete method: the first line and the body inside the braces.
  • The method header is only the first line: modifiers, return type, name, parameters, and the throws part.
  • The method signature is the smallest of the three: the name and the parameter types.

Let us practice reading the signature out of a header. Cover the right column with your hand and try each one first.

Method HeaderIts Signature
public int Codingzap(int a, int b)Codingzap(int, int)
private static double average(double[] scores)average(double[])
public void printReport()printReport()
protected String join(String first, char separator, String second) throws IOExceptionjoin(String, char, String)
public static void main(String[] args)main(String[])
boolean equals(Object other)equals(Object)

One caution. Some instructors use the word "signature" loosely and expect the whole header as the answer. If a question in your course says "write the method signature" and the sample answers in your notes include the return type, follow your instructor's format. But know that the strict meaning is the one in the right column.

Understand Concepts Related To Java Method Signature

Now, In Java, a method signature can be considered as a part of a method declaration. There are a few concepts that are necessary to know to go further in detail on this topic.

These concepts are Method Overloading, Exceptions, and Method Overriding. Let us have a look at them with the help of code examples below.

Method Overloading

Method overloading occurs when a class consists of two methods or more than two methods having the same name but different method signatures. So, for example, our method Codingzap() can share its name, but not the same parameter types or numbers.

The following code represents how overloaded methods work in Java with different signatures. Have a look to understand.

public class MethodSignatures {
    // Method with no parameters
    public void Codingzap() {
        System.out.println("No parameters to add.");
    }
    // Method with two int parameters
    public int Codingzap(int a, int b) {
        return a + b;
    }

    // Method with three integer parameters
    public int Codingzap(int a, int b, int c) {
        return a + b + c;
    }

    public static void main(String[] args) {
        MethodSignatures obj = new MethodSignatures();
        // Calling the different overloaded methods
        obj.Codingzap();  // No parameters
        int result1 = obj.Codingzap(10, 20);  // Two int parameters
        System.out.println("Sum of 10 and 20 is: " + result1);

        int result2 = obj.Codingzap(5, 10, 15);  // Three int parameters
        System.out.println("Sum of 5, 10 and 15 is: " + result2);
    }
}

In the above code, we have multiple methods in the class MethodSignatures having the same name i.e. Codingzap(). However, the part of the signature that makes them different is the parameter lists.

As we can see, the first method takes no arguments and only prints a message, so its return type is void. The other two methods have some arguments. The parameter type is the same, however, each method consists of a different number of input parameters in their method declarations.

Although both are performing addition as seen in the method body, the two methods differ with different numbers of required elements in the parameter lists. So, we can call them overloaded methods.

Output:

No parameters to add.
Sum of 10 and 20 is: 30
Sum of 5, 10 and 15 is: 30

As seen in the output of the program, we are invoking all the methods, and as the method signature includes different argument lists, we are able to run each one of them. In case two methods with the same name also share the same signature, a compile-time error will be thrown.

Overloading is also how Java programmers give a method "optional" values, since Java has no default parameters. We have a full guide on optional parameters in Java that builds on this idea.

Understanding method overloading is crucial for writing efficient and reusable Java code. If you're struggling with implementing method overloading in your assignments, you can work through it with a Java tutor from our team.

Which Overloaded Method Does Java Pick?

When the arguments match one signature exactly, the choice is easy. But what if no signature matches exactly? Java does not give up at once. It tries three things, in this order. First, it looks for a wider primitive type, like long for an int. If that fails, it tries the wrapper class, like Integer for an int. And only at the end, it tries a method with variable-length parameters (the three dots).

In the following program, we pass an int every time, but none of the methods takes a plain int.

public class Pick {
    // Set 1: an exact match is not available, but a wider primitive type is
    static void first(long x)    { System.out.println("first(long)"); }
    static void first(Integer x) { System.out.println("first(Integer)"); }
    static void first(int... x)  { System.out.println("first(int...)"); }

    // Set 2: no primitive match at all, so Java tries the wrapper class
    static void second(Integer x) { System.out.println("second(Integer)"); }
    static void second(int... x)  { System.out.println("second(int...)"); }

    // Set 3: only the variable-length version can take it
    static void third(String x)  { System.out.println("third(String)"); }
    static void third(int... x)  { System.out.println("third(int...)"); }

    public static void main(String[] args) {
        int number = 5;
        first(number);
        second(number);
        third(number);
    }
}

Output:

first(long)
second(Integer)
third(int...)

From the above output, we can see the order at work. In the first set, all three methods could take the value, and Java chose long. In the second set, with no long available, it chose Integer. In the third set, a String cannot hold an int, so only the variable-length method was left.

Sometimes, two signatures fit equally well, and Java cannot decide. Then it refuses to compile. Look at this pair.

public class Test {
    static void show(int a, double b) { System.out.println("int, double"); }
    static void show(double a, int b) { System.out.println("double, int"); }

    public static void main(String[] args) {
        show(1, 2);   // both versions fit equally well
    }
}
Test.java:6: error: reference to show is ambiguous
        show(1, 2);   // both versions fit equally well
        ^
  both method show(int,double) in Test and method show(double,int) in Test match
1 error

The two signatures are different, so the class itself is legal. The problem is the call. For show(1, 2), the first method is the better fit for the first argument, and the second method is the better fit for the second argument. Neither one is better on both, so there is no winner. The fix is to make the call clear, like show(1, 2.0).

The same error appears when we pass null to a method that is overloaded for two unrelated classes, like show(String) and show(Integer). A null fits both.

Exceptions

Exceptions are errors that may arise during the run-time and handling these are necessary to prevent program termination. If a method may throw one or more exceptions, we can list them in the method header.

For this purpose, we use the throws keyword which is then followed by the exception list. As our compiler test showed, this list is a part of the method declaration, but it is not a part of the method signature. Have a look at the code example below.

public class MethodSignatures {

    // Method with no exception
    public int Codingzap(int a, int b) {
        return a + b;
    }
    // Method with a string parameter to demonstrate exception handling
    public int Codingzap(String a, String b) throws NumberFormatException {
        int num1 = Integer.parseInt(a);
        int num2 = Integer.parseInt(b);
        return num1 + num2;
    }

    public static void main(String[] args) {
        MethodSignatures obj = new MethodSignatures();
        int result1 = obj.Codingzap(10, 20);  
        System.out.println("Sum of 10 and 20 is: " + result1);

        //  handling the exception  for string to int conversion
        try {
            int result2 = obj.Codingzap("10", "twenty");  // Invalid string input
            System.out.println("Sum of '10' and 'twenty' is: " + result2);
        } catch (NumberFormatException e) {
            System.out.println("Error: Invalid number format. " + e.getMessage());
        }
    }
}

Here, we have used another method having the int return type but its parameters have the string data types. An exception will arise if we pass the in-word or spelling of a number to be added, instead of simply writing the desired number.

You can also see that the method header includes the exception NumberFormatException. This helps in representing what kind of exception is thrown.

One side note: NumberFormatException is an unchecked exception, so Java does not force us to write the throws part here. It is written to make the risk visible to whoever calls the method.

Notice why this class compiles. The two methods are not different because one of them has a throws part. They are different because one takes (int, int) and the other takes (String, String).

Below is the output for this code. Let's see and understand it in a better way.

Output:

Sum of 10 and 20 is: 30
Error: Invalid number format. For input string: "twenty"

Here, you can clearly see that our first method is working properly. However, the second method throws an exception and provides us with an error message.

Method Overriding

Overloading needs different signatures in the same class. Overriding is the opposite. A child class writes a method with exactly the same signature as a method of its parent class, to replace the parent's behavior.

class Shape {
    double area(double side) {
        return 0;
    }
}

class Square extends Shape {
    @Override
    double area(double side) {       // same signature as the parent: this is overriding
        return side * side;
    }
}

public class Shapes {
    public static void main(String[] args) {
        Shape s = new Square();
        System.out.println("Area: " + s.area(4));
    }
}

Output:

Area: 16.0

Now, see what a tiny change in the signature does. In the next version, we changed the parameter in the Square class from double to int and removed the @Override line.

class Shape {
    double area(double side) {
        return 0;
    }
}

class Square extends Shape {
    double area(int side) {          // no @Override this time
        return side * side;
    }
}

public class Shapes {
    public static void main(String[] args) {
        Shape s = new Square();
        System.out.println("Area: " + s.area(4));
    }
}

Output:

Area: 0.0

There is no error, but the answer is wrong. With a different signature, area(int) is no longer an override. It is a brand new overloaded method sitting next to the parent's area(double). Why was area(int) not chosen, when 4 is an int? Because the variable ‘s’ is declared as a Shape, and the compiler only looks at the methods that Shape has. Shape knows only area(double). So, the call went to the parent's version, which returns 0. This kind of bug is very hard to find by reading the output.

This is the job of the @Override annotation. If we put it back, the compiler checks the signature for us and stops at once:

Shapes.java:8: error: method does not override or implement a method from a supertype
    @Override
    ^
1 error

So, always write @Override when you mean to override. It costs one line and catches this kind of mistake.

One more rule applies only to overriding. Here, the return type does matter. The child's method must return the same type as the parent's method, or a subtype of it.

Two Pairs Of Methods That Look Different But Still Clash

There are two cases where the code looks like valid overloading to our eyes, but the two methods end up the same after compiling. Both of them come up once students start using arrays and lists in their methods.

1. Three dots and an array. A parameter written as int... is turned into int[] by the compiler. So, these two methods clash:

public class Test {
    static int sum(int... numbers) { return 0; }
    static int sum(int[] numbers)  { return 0; }
}
Test.java:3: error: cannot declare both sum(int[]) and sum(int...) in Test
    static int sum(int[] numbers)  { return 0; }
               ^
1 error

2. Lists of different types. We may think that List<String> and List<Integer> are two different parameter types. In the source code, they are. But after compiling, Java removes the part inside the angle brackets. This is called type erasure. Both parameters become a plain List.

import java.util.List;

public class Test {
    static void print(List<String> names)   { }
    static void print(List<Integer> scores) { }
}
Test.java:5: error: name clash: print(List<Integer>) and print(List<String>) have the same erasure
    static void print(List<Integer> scores) { }
                ^
1 error

The usual way out is to give the two methods different names, like printNames() and printScores().

What About The Signature Of The main Method?

Every Java program you have written so far has this line: public static void main(String[] args). The Java launcher looks for a method with the signature main(String[]). If it does not find one, the program compiles but will not start. In the class below, we wrote String in place of String[].

public class Hello {
    public static void main(String args) {   // String, not String[]
        System.out.println("Hello");
    }
}

It compiled without any error. But when we ran it, this was printed:

Error: Main method not found in class Hello, please define the main method as:
   public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application

For the compiler, main(String) is a perfectly fine method. It is just not the one the launcher wants. On Java 21, the words public, static, and void all have to be there. What are we allowed to change, then? The name ‘args’ can be anything, because parameter names are not part of the signature. The words public and static can be swapped. And String[] can be written as String..., because, as we just saw, both give the same signature. The following version runs fine.

public class Hello {
    static public void main(String... words) {   // order of modifiers and the name changed
        System.out.println("Hello");
    }
}

Output:

Hello

A note on versions: we ran these programs on Java 21. The newest Java releases (Java 25 onward) also accept a shorter main() with no parameters at all. Most courses still teach the classic line, so that is the one to learn first.

Comparison Table On Method Signature Between Java And Other Programming Languages:

The Method Signature is a concept that is not only present in the Java Programming Language. But, there are some other programming languages as well where a similar type of concept is present.

In this section, we will learn all about them by drawing a Comparison Table. We will make a Comparison Table on Method Signature between Java and Other Programming Languages.

CriteriaJavaPythonC++JavaScript
TypingStaticDynamicStaticDynamic
OverloadingYesNoYesNo
Based On Name OnlyNoYesNoYes
Parameter CheckingStrictFlexibleStrictFlexible
Method UniquenessSignatureNameSignatureName
Two Methods With The Same NameBoth are kept if the signatures differThe later one replaces the earlier oneBoth are kept if the signatures differThe later one replaces the earlier one

If you are coming to Java from Python, the last row is the one to remember. In Python, writing a second function with the same name quietly overwrites the first. In Java, it either becomes an overload or gives a compile error.

What Are Some Real-World Applications Of Method Signature In Java?

Method Signature in Java is a fundamental concept. The importance of the concept can be felt when we go through the list of Real-world Applications of Java Method Signature.

That is the reason why, in this section, we will discuss some of the Real-world Applications of Java Method signatures. From there, you will understand the high necessity of it.

1. Banking Applications:

When we are developing any Banking Application with the Java Language, the need for Method Signature can be felt at different phases while taking different inputs from the users.

When To Use In Real-World Applications:

  • With Method Signature, we can get the Account Details by taking the Account Number input. One more method with the same name can find the account by email. findAccount(long) and findAccount(String) can live side by side.
  • Using different Method Signatures, we can calculate the different types of account interests.

2. Java Frameworks:

Not only in Banking Applications but in some Java Frameworks as well, the Method Signature concept is highly used. In Spring Framework, when an HTTP Request arrives, Spring reads the parameter list of our method to decide what values to pass into it.

When To Use In Real-World Applications:

  • The parameter list is what Spring reads on a method marked with @RequestMapping in REST APIs.
  • The Method Signature is also used to define the Service Layer Methods. An interface lists the signatures, and every class that implements it must provide methods that match them.
  • Testing tools like JUnit expect a certain shape too. A test method normally takes no parameters and returns void.

3. Integrated Development Environments:

In different Integrated Development Environments or IDEs, the Method Signatures are used to ensure a smooth code compilation. Also, it helps in detecting errors in the code.

When To Use In Real-World Applications:

  • When we type a method name and an opening parenthesis in IntelliJ IDEA or Eclipse, the small popup that lists the possible parameters is a list of the signatures of that method.
  • Method Signature is highly used in the Large Scale Application development in collaboration. Two programmers can agree on the signatures first and then write their parts separately.
  • In the Static Analyzing Tool, the Method Signature is used to check consistency, for example, a call that does not match any signature.

Conclusion:

Method Signature in Java is a part of the method declarations that is simply the combination of the method names and parameter lists. While the method names can be the same in a class, the signatures should be different.

If this is not followed, our program will not run because of a compilation error. Therefore, it is important to make note of the methods and perform tasks like polymorphism carefully. You should also follow naming conventions and provide method names that signify their functions or tasks.

Takeaways:

  • The Java method signature consists of two components. These are the name of the method and the list of parameter types.
  • The return type, modifiers, parameter names, and throws part are not included. We confirmed each one with the compiler.
  • No two methods in a class can have the same signature. If this happens, our code will not compile.
  • However, performing method overloading is perfectly legal if you follow the proper procedure.
  • For overriding, the child's method must have the same signature as the parent's. The @Override annotation makes the compiler check it.
  • It is important to note that one method can have the same name as other methods but can never have the same signature in Java programming language.

Frequently Asked Questions

What is a method signature, in one line?

A method signature is the name of a method together with the types of its parameters, in order. For the method public int add(int a, int b), the signature is add(int, int).

Is the return type part of the method signature in Java?

No. Two methods that differ only in their return type have the same signature, and the compiler rejects the class with an "already defined" error. The return type is part of the method header, not the signature.

Can two methods have the same name in Java?

Yes, as long as their parameter lists are different in the number, the types, or the order of the types. This is called method overloading. They cannot differ only by return type, parameter names, modifiers, or the throws part.

Are parameter names part of the method signature?

No. Only the parameter types count. The methods add(int a, int b) and add(int x, int y) have the same signature, add(int, int).

What is the difference between a method signature and a method header?

The method header is the whole first line of a method, including modifiers, return type, name, parameters, and the throws part. The method signature is only the name and the parameter types taken from that line.

What is the signature of the main method in Java?

Strictly, it is main(String[]). The full header that the Java launcher looks for is public static void main(String[] args). The parameter name can be changed, and String... can be used in place of String[].

Do constructors have signatures?

They follow the same rule. A class can have several constructors as long as their parameter lists are different, which is called constructor overloading. Two constructors with the same parameter types will not compile.