Passing objects to methods

Passing objects to methods in Java allows you to manipulate and operate on complex data structures within your methods. When you pass an object to a method, you are passing the reference to the object, not the actual object itself. This means that changes made to the object within the method affect the original object outside the method.

Key Concepts of Passing Objects to Methods

  1. Passing by Value: In Java, all method parameters are passed by value. For primitive types, this means passing a copy of the actual value. For objects, this means passing a copy of the reference to the object.
  2. Modifying Object State: Since the reference to the object is passed, methods can modify the object’s state.
  3. Immutable vs. Mutable Objects: Immutable objects cannot be changed after they are created, while mutable objects can be modified.

Example of Passing Objects to Methods

Consider a simple class Person:

class Person {
    String name;
    int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

Passing and Modifying Objects

Here’s an example where we pass a Person object to a method and modify its state:

public class PassingObjectsExample {
    public static void main(String[] args) {
        Person person = new Person("John", 25);
        System.out.println("Before: " + person.name + ", " + person.age); // Output: John, 25

        modifyPerson(person);

        System.out.println("After: " + person.name + ", " + person.age); // Output: Alice, 30
    }

    static void modifyPerson(Person p) {
        p.name = "Alice";
        p.age = 30;
    }
}

In this example, the modifyPerson method changes the name and age of the Person object. The changes are reflected outside the method because the reference to the original object is passed.

Example of Reassigning Object Reference

If you reassign the object reference within the method, the original reference remains unchanged outside the method:

public class PassingObjectsExample {
    public static void main(String[] args) {
        Person person = new Person("John", 25);
        System.out.println("Before: " + person.name + ", " + person.age); // Output: John, 25

        reassignPerson(person);

        System.out.println("After: " + person.name + ", " + person.age); // Output: John, 25
    }

    static void reassignPerson(Person p) {
        p = new Person("Alice", 30); // This reassigns the local reference, not the original reference
    }
}

In this example, the reassignPerson method reassigns the parameter p to a new Person object. However, this reassignment does not affect the original person object outside the method because only the local copy of the reference is changed.

Immutable Objects

Immutable objects cannot be changed after they are created. A common example of an immutable object in Java is the String class.

Example of Immutable Object

public class ImmutableExample {
    public static void main(String[] args) {
        String str = "Hello";
        System.out.println("Before: " + str); // Output: Hello

        modifyString(str);

        System.out.println("After: " + str); // Output: Hello
    }

    static void modifyString(String s) {
        s = "Goodbye"; // This creates a new String object, does not change the original one
    }
}

In this example, the modifyString method attempts to change the String object. However, since String is immutable, the original string remains unchanged.

Mutable Objects

Mutable objects can be changed after they are created. Most custom objects and collections in Java are mutable.

Example of Mutable Object

Consider a List object:

import java.util.ArrayList;
import java.util.List;

public class MutableExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Apple");
        System.out.println("Before: " + list); // Output: [Apple]

        modifyList(list);

        System.out.println("After: " + list); // Output: [Apple, Banana]
    }

    static void modifyList(List<String> l) {
        l.add("Banana");
    }
}

In this example, the modifyList method adds an element to the List object. The change is reflected outside the method because the reference to the original List object is passed.

Practical Use Cases

Passing objects to methods is commonly used for:

  1. Encapsulation: Methods can operate on object states without exposing internal details.
  2. Data Transfer: Objects can carry complex data structures as method parameters.
  3. Reusable Code: Methods can be designed to operate on different objects, increasing code reusability.
  4. Modifying State: Methods can modify the state of objects, which is useful in many design patterns (e.g., Observer, Strategy).