Methods & Overloading
Learn how to define methods in Java, work with parameters and return types, and understand method overloading.
Defining Methods
Methods in Java encapsulate reusable blocks of code and are always defined within a class. Each method has an access modifier, a return type, a name, and optional parameters. The void keyword indicates that a method does not return a value, while other methods must include a return statement matching their declared return type. Well-designed methods follow the single responsibility principle, performing one specific task and keeping code organized.
public class MethodDemo {
// Method with no parameters and no return value
public static void sayHello() {
System.out.println("Hello!");
}
// Method with parameters and a return value
public static int add(int a, int b) {
return a + b;
}
// Method with multiple return paths
public static String classify(int number) {
if (number > 0) {
return "positive";
} else if (number < 0) {
return "negative";
}
return "zero";
}
public static void main(String[] args) {
sayHello(); // "Hello!"
int sum = add(5, 3);
System.out.println("Sum: " + sum); // "Sum: 8"
System.out.println(classify(-7)); // "negative"
}
}
Static vs Instance Methods
Static methods belong to the class itself and can be called without creating an instance. Instance methods operate on a specific object and can access its instance variables through the this keyword. Static methods cannot access instance variables or call instance methods directly because there is no object context. Utility classes like Math and Collections contain only static methods, while most domain objects rely on instance methods.
public class Calculator {
private double memory = 0;
// Static method - no instance needed
public static double square(double x) {
return x * x;
}
// Instance methods - operate on object state
public void store(double value) {
this.memory = value;
}
public double recall() {
return this.memory;
}
public void addToMemory(double value) {
this.memory += value;
}
public static void main(String[] args) {
// Calling static method
double result = Calculator.square(5);
System.out.println("5 squared: " + result); // 25.0
// Creating instance and calling instance methods
Calculator calc = new Calculator();
calc.store(100);
calc.addToMemory(50);
System.out.println("Memory: " + calc.recall()); // 150.0
}
}
Parameters and Return Types
Java passes primitive arguments by value, meaning changes inside the method do not affect the original variable. Reference types are also passed by value, but the value is a reference to the object, so modifications to the object's state are visible to the caller. Methods can return any type including arrays, objects, and even other functional interfaces. Understanding pass-by-value semantics in Java prevents common bugs when working with mutable objects.
import java.util.Arrays;
public class ParameterDemo {
// Primitives are passed by value (copy)
public static void tryToChange(int x) {
x = 999; // Does not affect the caller
}
// Objects are passed by reference value
public static void modifyArray(int[] arr) {
arr[0] = 999; // This DOES affect the caller
}
// Returning an array
public static int[] generateRange(int start, int end) {
int[] result = new int[end - start];
for (int i = 0; i < result.length; i++) {
result[i] = start + i;
}
return result;
}
// Varargs (variable number of arguments)
public static double average(double... numbers) {
double sum = 0;
for (double n : numbers) {
sum += n;
}
return sum / numbers.length;
}
public static void main(String[] args) {
int num = 10;
tryToChange(num);
System.out.println(num); // 10 (unchanged)
int[] arr = {1, 2, 3};
modifyArray(arr);
System.out.println(arr[0]); // 999 (changed)
int[] range = generateRange(1, 6);
System.out.println(Arrays.toString(range)); // [1, 2, 3, 4, 5]
System.out.println(average(10, 20, 30)); // 20.0
}
}
Method Overloading
Method overloading allows you to define multiple methods with the same name but different parameter lists within the same class. The compiler determines which overloaded method to call based on the number, types, and order of arguments. Overloading is a form of compile-time polymorphism and is commonly used to provide convenience methods with different levels of detail. Note that changing only the return type is not sufficient for overloading; the parameter list must differ.
public class Formatter {
// Overloaded format methods
public static String format(String text) {
return text.trim().toLowerCase();
}
public static String format(String text, boolean uppercase) {
String trimmed = text.trim();
return uppercase ? trimmed.toUpperCase() : trimmed.toLowerCase();
}
public static String format(String text, int maxLength) {
String trimmed = text.trim();
if (trimmed.length() > maxLength) {
return trimmed.substring(0, maxLength) + "...";
}
return trimmed;
}
public static String format(String text, String prefix, String suffix) {
return prefix + text.trim() + suffix;
}
public static void main(String[] args) {
System.out.println(format(" Hello World "));
// "hello world"
System.out.println(format(" Hello World ", true));
// "HELLO WORLD"
System.out.println(format(" Hello World ", 5));
// "Hello..."
System.out.println(format("Hello", "[", "]"));
// "[Hello]"
}
}