MediumJava Methods. A method is a block of code defined… | by Omkar Bhavare | Medium
Sitemap
Omkar Bhavare

Omkar Bhavare

Articulating the 'why' behind the code. I dissect JS quirks, React's render cycle, Java fundamentals & DSA patterns to reveal the elegant systems beneath.

Java Methods

12 min readAug 10, 2026

--

A method is a block of code defined inside a class that performs a specific operation or behaviour. We use methods mainly to reuse logic, avoid code duplication, and keep the code modular and maintainable.

A method can have parameters, a return type, and an access modifier like public, protected, or private. It can be an instance method or a static method. Methods can also be overloaded, and in inheritance they can be overridden to achieve runtime polymorphism.

Get Omkar Bhavare’s stories in your inbox

Join Medium for free to get updates from this writer.

For example, public int add(int a, int b) has public as the access modifier, int as the return type, add as the method name, and a and b as parameters.

Press enter or click to view image in full size

1. Method Signature & Overloading

What is a method signature in Java?

“So basically, a method signature in Java consists of the method name and the parameter list — meaning the number, type, and order of parameters.

For method overloading, Java uses the method name and parameter list to determine whether two methods are different. The return type, access modifier, static, final, and parameter names are not part of the method signature.

For example, add(int, int) and add(double, double) have different signatures, so they can be overloaded. But add(int, int) with only a different return type is not valid overloading.

Can two methods have the same name and parameters but different return types?

No, Java does not allow this as method overloading. If two methods have the same method name and same parameter list, Java considers them the same method signature. The return type is not part of the method signature, so changing only the return type doesn’t create a new method.

The reason is that when we call a method, Java identifies the method using the method name and arguments, not the return type. For example, if both add(int, int) return int and double, the call add(10, 20) would be ambiguous from the method-selection point of view.

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

double add(int a, int b) { // ❌ Compile-time error
return a + b;
}

Can methods be overloaded by changing only parameter names, access modifiers, static, final, or return type?

No. For method overloading, the parameter list must be different. That means we need to change the number, type, or order of parameters.

Just changing the parameter name, access modifier, static, final, or return type is not enough because these are not part of the method signature.

For example, static changes the method from an instance method to a class-level method, and final prevents overriding. Similarly, public and private control accessibility, while the return type defines what the method returns. But none of these changes the method signature.

 1. METHOD OVERLOADING
---------------------
Method overloading means:
- Same method name
- Different parameter list
- Usually happens inside the same class
- Return type / Access Modifier CANNOT create overloading

void add(int a, int b) {}
void add(int x, int y) {} // ❌ Not overloaded

void m1(int a) {}
public void m1(int a) { } // ❌ Not overloaded

void m2(){}
void m2(int a){} // over loaded

Can a method be overloaded by changing parameter types, parameter count, or parameter order?

“Yes, these are the three main ways we create method overloading in Java. The method name remains the same, but the parameter list changes.

1. Different parameter type:

void add(int a) {}
void add(double a) {} // ✅

2. Different parameter count:

void add(int a) {}
void add(int a, int b) {} // ✅

3. Different parameter order:

void add(int a, double b) {}
void add(double a, int b) {} // ✅

Can main() be overloaded, and if yes, which main() method will JVM execute?

“Yes, main() can be overloaded because it is a normal static method, so we can create multiple main() methods with different parameter lists.

But the main(String[] args) method is the entry point and JVM executes that method first. [ Basically, the JVM needs a predefined method signature to know where the Java application should start execution. By Java specification, the launcher looks for a public static main method with a String[] parameter.]

The overloaded main(int) will execute only when we explicitly call it from the program.

class Main {

public static void main(String[] args) {
System.out.println("JVM main");
main(10);
}

public static void main(int number) {
System.out.println("Overloaded main");
}
}
Press enter or click to view image in full size

When multiple overloaded methods are available, how does Java decide which method to call?

“Basically, Java decides which overloaded method to call at compile time, based on the arguments we pass. It looks at the method name and tries to find the most specific applicable parameter list.

If an exact match is not available, Java can consider widening conversions, boxing/unboxing, and then varargs according to overload-resolution rules.

void test(int x) {
System.out.println("int");
}

void test(double x) {
System.out.println("double");
}

test(10);

void test1(long x) {
System.out.println("long");
}

void test1(double x) {
System.out.println("double");
}

test1(10); // test1(long)

If overloaded methods involve exact match, widening, boxing/unboxing, and varargs, which one gets priority?

“Java generally chooses the least costly conversion for the arguments. So the priority is:

1. Exact match → 2. Widening → 3. Boxing/Unboxing → 4. Varargs

void test(int x) {
System.out.println("int");
}

void test(long x) {
System.out.println("long");
}

void test(Integer x) {
System.out.println("Integer");
}

void test(int... x) {
System.out.println("varargs");
}

test(10);

What happens when overloaded methods become ambiguous?

Basically, when Java finds multiple overloaded methods that are equally applicable and cannot decide which one is more specific, it gives a compile-time error called an ambiguous method call.

For example, if one method needs widening on the first argument and another method needs widening on the second argument, both methods may be equally valid. Java cannot prefer either one.

void test(int a, double b) {
System.out.println("int, double");
}

void test(double a, int b) {
System.out.println("double, int");
}

test(10, 10);

Here 10 is an int. Java can widen either argument:

test(int, double) → second int → double
test(double, int) → first int → double

Both methods require the same level of conversion, so Java cannot decide which one is better.

Therefore:

❌ Compile-time error: reference to test is ambiguous

We can resolve it by making the call more specific, for example:

test(10, 10.0); // calls test(int, double)

How does Java choose between byte, short, int, long, Integer, Number, Object, and varargs?

“Java resolves overloaded methods in phases. It first tries to find a method without boxing or varargs. So if an exact primitive match is available, that gets priority. If there is no exact match, Java can use primitive widening. Only after that does it consider boxing and reference widening, and finally varargs.

Note: In Java Integer literals are int by default. Java doesn’t automatically select the smallest data type based on the value. Therefore, test(10) selects the int overload as an exact match.

void test(byte x)    { System.out.println("byte"); }
void test(short x) { System.out.println("short"); }
void test(int x) { System.out.println("int"); }
void test(long x) { System.out.println("long"); }
void test(Integer x) { System.out.println("Integer"); }
void test(Number x) { System.out.println("Number"); }
void test(Object x) { System.out.println("Object"); }
void test(int... x) { System.out.println("varargs"); }

test(10); // int

// If test(int) is removed: test(long) is selected because widening is considered before boxing.

Can autoboxing/unboxing and widening together affect overloaded method selection?

Yes. Autoboxing, unboxing, and widening can affect overload resolution, but Java follows specific conversion phases. Java first prefers methods that can be called without boxing/unboxing, and only then considers boxing or unboxing.

void test(long x) {
System.out.println("long");
}

void test(Integer x) {
System.out.println("Integer");
}

Integer value = 10;
test(value); // Integer

because it doesn't need unboxing and widening.
=============================================================================
void test1(long x) {
System.out.println("long");
}

void test1(Integer x) {
System.out.println("Integer");
}

test1(10); // long Java considers widening before boxing, so test(long) is selected.

Java can use:
int → long // primitive widening
int → Integer // boxing
Press enter or click to view image in full size

What is the difference between method overloading and method overriding, and when does each happen?

“Basically, overloading means having multiple methods with the same name but a different parameter list, usually within the same class. Java decides which overloaded method to call at compile time, based on the arguments passed.

Overriding happens when a child class provides its own implementation of a parent class method with the same method signature. The actual method to execute is decided at runtime, based on the actual object.

class Calculator {
void add(int a, int b) {}
void add(double a, double b) {} // Overloading
double add(double a, double b) {} // Compile time Error
}
=================================================================

class Animal {
void sound() {
System.out.println("Animal");
}
}

class Dog extends Animal {
@Override
void sound() { // Overriding
System.out.println("Dog");
}
}

Animal a = new Dog();
a.sound(); // Dog

Can a method call involve both overloading and overriding?

Yes. This can happen when we have inheritance plus overloaded methods. Java basically works in two steps: first, the compiler selects the overloaded method using the reference type and compile-time argument types. Then, at runtime, if that selected method is overridden, Java chooses the implementation based on the actual object type.

class Parent {
void test(int x) {
System.out.println("Parent int");
}

void test(String x) {
System.out.println("Parent String");
}
}

class Child extends Parent {
@Override
void test(int x) {
System.out.println("Child int");
}
}

Parent p = new Child();
p.test(10);

First, overloading is resolved at compile time:

p.test(10)
↓
argument = int
↓
test(int) selected

Then overriding is resolved at runtime:

actual object = Child
↓
Child.test(int)
↓
"Child int"

So the flow is:

Compile time → select overloaded method → Runtime → select overridden implementation
Press enter or click to view image in full size

Can an overriding method change the return type, and what is a covariant return type?

Yes, an overriding method can change its return type, but only under a specific rule. The return type can be covariant, which means the child method can return a subtype of the parent’s return type.

Press enter or click to view image in full size

Can an overriding method change the access modifier?

An overriding method cannot reduce the parent method’s visibility because the child object should be usable wherever the parent object is expected. If the child reduces the access, code that could access the parent method may no longer be able to access the child method. This breaks substitutability and violates the parent class contract.

If the parent method is public, any caller can use it. If the child changes it to protected, that caller loses access when working with the child object. That is why Java does not allow reducing visibility.

Reducing visibility would break the parent contract. This would break polymorphism and the Liskov Substitution Principle (LSP).

class Parent {
protected void show() {
System.out.println("Parent");
}
}

class Child1 extends Parent {
@Override
public void show() { // ✅ visibility increased
System.out.println("Child");
}
}

class Child2 extends Parent {
@Override
private void show() { // ❌ cannot reduce visibility
}
}

protected → public

is allowed because public is more accessible.

Public>protected>p

Can an overriding method change the throws clause?

Yes, an overriding method can change the throws clause, but there are rules, especially for checked exceptions.
For
checked exceptions, the child method cannot throw a new or broader checked exception than the parent method. It can throw the same exception, a narrower subclass, or no exception at all.

class Parent {
void read() throws IOException {
System.out.println("Parent");
}
}

class Child1 extends Parent {
@Override
void read() throws FileNotFoundException { // ✅ narrower exception
System.out.println("Child");
}
}
// Here FileNotFoundException is a subclass of IOException, so it is allowed.

class Child2 extends Parent { //
@Override
void read() { // ✅ no checked exception.We can also remove the exception
System.out.println("Child");
}
}

class Child3 extends Parent {
@Override
void read() throws IOException { ✅ // Same Exception is also fine
System.out.println("Child");
}
}

class Child4 extends Parent {
@Override
void read() throws Exception { // ❌ broader checked exception
}
}

Can a child method have a different parameter list and still be considered overriding?

No. For method overriding, the child method must have the same method signature as the parent method — meaning the same method name and the same parameter types in the same order.

If the parameter list changes, Java treats it as a different method, so it becomes method overloading, not overriding.

Can constructors be overridden, and why?

No, constructors cannot be overridden. Overriding requires inheritance and a method with the same signature, but constructors are not inherited by the child class.

A constructor is specifically used to initialize an object of its own class, and it has the same name as the class with no return type.

Press enter or click to view image in full size

Can static, final, and private methods be overridden, and how does Java treat each one?

No, static, final, and private methods cannot be overridden, but Java treats each differently.

final method: A final method cannot be overridden because final explicitly tells Java that the method's implementation must not be changed by subclasses

class Parent {
final void show() {}
}

class Child extends Parent {
// void show() {} // ❌ Cannot override final method
}

static method: Cannot be overridden because static methods belong to the class, not the object. If the child defines a static method with the same signature, it is called method hiding, not overriding.

class Parent {
static void show() {
System.out.println("Parent");
}
}

class Child extends Parent {
static void show() {
System.out.println("Child");
}
}

Parent p = new Child();
p.show(); // Parent

private method: private method is not inherited by the child class, so it cannot be overridden. If the child declares a method with the same name and parameters, it is simply a new, unrelated seperated method.

class Parent {
private void show() {}
}

class Child extends Parent {
private void show() {} // ✅ New method, not overriding
}

If parent and child classes have the same static method, which one executes?

Static methods are resolved based on the reference type, not the actual object type. Therefore, the method belonging to the reference type executes.

It depends on the reference type, because static methods are resolved at compile time.

If the reference is Parent, the Parent static method executes.

If the reference is Child, the Child static method executes.

This is called method hiding, not method overriding.

class Parent {
static void show() {
System.out.println("Parent");
}
}

class Child extends Parent {
static void show() {
System.out.println("Child");
}
}

Parent p = new Child();
p.show(); // Parent

Child c = new Child();
c.show(); // Child

What is method hiding, and how is it different from method overriding?

Basically, method hiding happens when a child class declares a static method with the same signature as a static method in the parent class. Since static methods belong to the class, Java doesn't use runtime polymorphism for them. The method is selected based on the reference type at compile time.

Method overriding, on the other hand, happens with instance methods. The child provides its own implementation of the parent’s method, and Java selects the implementation at runtime based on the actual object.

class Parent {

static void show() {
System.out.println("Parent static");
}

static void m1() {
System.out.println("Parent M1 static");
}

void display() {
System.out.println("Parent instance");
}
}

class Child extends Parent {

static void show() {
System.out.println("Child static"); // Method hiding
}

void m1() { // ❌ Compilation Error It method should be static if in parent it is mentioned as static
System.out.println("Child M1 static"); //
}

@Override
void display() {
System.out.println("Child instance"); // Method overriding
}
}

Parent p = new Child();

p.show(); // Parent static
p.display(); // Child instance

Can static, final, and private methods still be overloaded?

Yes. static, final, and private methods can all be overloaded. The important thing is that overloading depends only on having the same method name with a different parameter list. These keywords affect other aspects of the method, but they don't prevent overloading.

Why can’t a method be abstract with final, private, or static?

An abstract method requires a subclass implementation. final prevents overriding, private prevents inheritance, and static doesn't participate in runtime overriding. Since each conflicts with the purpose of an abstract method, Java doesn't allow these combinations.

Press enter or click to view image in full size

--

--

Omkar Bhavare
Omkar Bhavare

Written by Omkar Bhavare

Articulating the 'why' behind the code. I dissect JS quirks, React's render cycle, Java fundamentals & DSA patterns to reveal the elegant systems beneath.