Java Inter-Class Method Invocation: Three Object Reference Passing Patterns Explained

Nov 20, 2025 · Programming · 8 views · 7.8

Keywords: Java Object-Oriented Programming | Inter-Class Method Invocation | Object Reference Passing

Abstract: This article provides an in-depth exploration of three core implementation approaches for method invocation between different classes in Java: constructor injection, setter method injection, and parameter passing. Through practical examples with Alpha and Beta classes, it details the applicable scenarios, implementation specifics, and design considerations for each pattern, helping developers master best practices for object collaboration in object-oriented programming. The article combines code examples with theoretical analysis to offer comprehensive solutions and extended discussions.

Introduction

In object-oriented programming, collaboration between classes forms the foundation of building complex systems. When a method in one class needs to invoke a method from another class, properly passing object references becomes crucial. This article systematically analyzes three primary object reference passing patterns based on practical programming scenarios.

Problem Scenario Analysis

Consider the following typical scenario: The Alpha class needs to call the Beta class's DoSomethingBeta() method within its DoSomethingAlpha() method. The initial code structure is as follows:

public class Alpha {
    public void DoSomethingAlpha() {
        // Need to call cBeta.DoSomethingBeta() here
    }
}

public class Beta {
    public void DoSomethingBeta() {
        // Specific implementation logic
    }
}

public class MainApp {
    public static void main(String[] args) {
        Alpha cAlpha = new Alpha();
        Beta cBeta = new Beta();
    }
}

The core challenge lies in how to enable the Alpha instance to obtain a reference to the Beta instance, thereby allowing it to invoke its methods.

Solution 1: Constructor Injection

The constructor injection pattern enforces dependency relationships during object creation, ensuring that each Alpha instance possesses a valid Beta reference.

public class Alpha {
    private Beta beta;
    
    public Alpha(Beta beta) {
        this.beta = beta;
    }
    
    public void DoSomethingAlpha() {
        beta.DoSomethingBeta();
    }
}

// Usage
public class MainApp {
    public static void main(String[] args) {
        Beta cBeta = new Beta();
        Alpha cAlpha = new Alpha(cBeta);
        cAlpha.DoSomethingAlpha();
    }
}

Advantages of this pattern include:

Solution 2: Setter Method Injection

Setter injection provides more flexible dependency management, allowing dynamic setting of dependencies during runtime.

public class Alpha {
    private Beta beta;
    
    public void setBeta(Beta beta) {
        this.beta = beta;
    }
    
    public void DoSomethingAlpha() {
        if (beta != null) {
            beta.DoSomethingBeta();
        } else {
            // Handle case where beta is null
        }
    }
}

// Usage
public class MainApp {
    public static void main(String[] args) {
        Alpha cAlpha = new Alpha();
        Beta cBeta = new Beta();
        cAlpha.setBeta(cBeta);
        cAlpha.DoSomethingAlpha();
    }
}

Characteristics of setter injection:

Solution 3: Method Parameter Passing

The parameter passing pattern localizes dependency relationships, passing required objects only during method invocation.

public class Alpha {
    public void DoSomethingAlpha(Beta beta) {
        beta.DoSomethingBeta();
    }
}

// Usage
public class MainApp {
    public static void main(String[] args) {
        Alpha cAlpha = new Alpha();
        Beta cBeta = new Beta();
        cAlpha.DoSomethingAlpha(cBeta);
    }
}

Advantages of parameter passing:

Design Pattern Selection Guidelines

Choosing the appropriate object reference passing pattern requires consideration of multiple factors:

Dependency Relationship Stability

If the dependency relationship between Alpha and Beta remains constant throughout the object's lifecycle, constructor injection is the optimal choice. This strong dependency ensures code robustness and predictability.

Usage Scenario Flexibility

When dependency relationships may change, or only some Alpha instances require Beta functionality, setter injection provides necessary flexibility. This pattern is common in configuration-driven applications.

Method Call Independence

If each method invocation might require different Beta instances, or if maintaining the stateless nature of the Alpha class is desired, parameter passing is the most suitable choice. This pattern is particularly common in utility classes and helper methods.

Extended Discussion

Static Method Invocation

As mentioned in the reference answer, if DoSomethingBeta() is a static method, it can be directly invoked via the class name:

Beta.DoSomethingBeta();

Static method invocation avoids the overhead of object instantiation but sacrifices the polymorphic characteristics of object-oriented programming.

Inheritance Relationships

Implementing method access through inheritance is another option:

public class Alpha extends Beta {
    public void DoSomethingAlpha() {
        DoSomethingBeta();  // Directly call parent class method
    }
}

This approach establishes an is-a relationship, suitable for scenarios where Alpha is truly a specialization of Beta.

Object Creation Strategy

Creating Beta instances within Alpha is another feasible approach:

public class Alpha {
    public void DoSomethingAlpha() {
        Beta beta = new Beta();
        beta.DoSomethingBeta();
    }
}

This method simplifies external dependency management but may lead to tight coupling and testing difficulties.

Best Practice Recommendations

Dependency Injection Principles

Follow the dependency inversion principle by defining dependency relationships through interfaces rather than concrete classes, enhancing code testability and maintainability.

Null Safety Handling

When using setter injection, always perform null checks to avoid NullPointerException. Consider using Optional classes or assertions to enhance code robustness.

Documentation and Conventions

Clear API documentation and naming conventions help other developers understand dependency requirements and usage patterns.

Conclusion

The three main patterns for inter-class method invocation in Java each have their applicable scenarios and advantages. Constructor injection suits stable, strong dependency relationships, setter injection provides runtime flexibility, and parameter passing is ideal for temporary dependencies. Developers should choose the most appropriate solution based on specific business requirements, design goals, and maintenance considerations. Understanding the fundamental differences between these patterns helps in writing more robust and maintainable object-oriented code.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.