By WebNest Studio Engineering Team
Java - Core Tutorial
Java RMI (Remote Method Invocation)
Remote Method Invocation (RMI) is a Java-specific mechanism that lets an object living in one Java Virtual Machine call a method on an object living in a different JVM — potentially on an entirely different machine — as though it were a normal local method call. RMI handles the underlying network communication, parameter serialization, and result marshaling transparently.
RMI was a significant part of enterprise Java in the late 1990s and early 2000s, and it still appears in legacy systems and in interview questions about distributed computing concepts. However, it is largely legacy technology today: modern distributed systems overwhelmingly use REST APIs, gRPC, or message queues instead, because those approaches are language-agnostic, easier to secure across networks, and better supported by modern tooling. This lesson presents RMI as historical/interview knowledge rather than a current best practice.
Why it matters
RMI is mostly found in older enterprise systems, but the idea it introduced is the basis of everything that replaced it. Calling a method that actually runs on another machine, through a local stub that sends the arguments over the network, is exactly what gRPC and REST clients do today. Understanding RMI makes those easier to learn, and you may still have to maintain it.
The Basic Pieces of RMI
An RMI application is built from a small number of cooperating pieces.
- Remote interface — an interface extending
java.rmi.Remote, whose methods each declarethrows RemoteExceptionto account for network failures. - Remote implementation — a class implementing that interface, typically extending
UnicastRemoteObject, which provides the machinery to receive and respond to remote calls. - RMI Registry — a simple naming service (started with the
rmiregistrytool, orLocateRegistry.createRegistry()) where a server binds a name to a remote object reference, and a client looks that name up to obtain a proxy (stub) for the remote object. - Stub — a client-side proxy object that implements the same remote interface; calling a method on the stub actually serializes the call and sends it over the network to the real object.
How a Call Flows
A server creates an instance of the remote implementation and binds it to a name in the RMI registry. A client looks up that name in the registry (given the server's host and port) and receives a stub object implementing the shared remote interface. When the client calls a method on the stub, RMI serializes the method name and arguments, sends them over TCP to the server's JVM, the server executes the real method, and the result is serialized back to the client — all of this is hidden behind what looks like an ordinary Java method call.
Why RMI Is Considered Legacy Today
RMI ties both client and server to Java specifically (a client written in another language cannot easily call an RMI service), requires careful handling of classloading and serialization security, and does not play well with firewalls, load balancers, and modern cloud infrastructure the way HTTP-based protocols do. For these reasons, REST APIs (over HTTP/JSON), gRPC (over HTTP/2 with protocol buffers), and message queues (like Kafka or RabbitMQ for asynchronous communication) are the standard choices for new distributed systems. Knowing RMI is still valuable for understanding the concepts behind remote calls and for legacy codebases, but it should not be reached for in new projects.
Example
A minimal RMI remote interface, implementation, server, and client
// --- Remote interface ---
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Calculator extends Remote {
int add(int a, int b) throws RemoteException;
}
// --- Remote implementation ---
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
public class CalculatorImpl extends UnicastRemoteObject implements Calculator {
protected CalculatorImpl() throws RemoteException {
super();
}
public int add(int a, int b) throws RemoteException {
return a + b;
}
}
// --- Server: creates registry and binds the object ---
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.Naming;
public class Server {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.createRegistry(1099);
Calculator calculator = new CalculatorImpl();
Naming.rebind("rmi://localhost/CalculatorService", calculator);
System.out.println("Calculator service is bound and ready.");
}
}
// --- Client: looks up the object and calls it as if local ---
import java.rmi.Naming;
public class Client {
public static void main(String[] args) throws Exception {
Calculator calculator = (Calculator) Naming.lookup("rmi://localhost/CalculatorService");
System.out.println("5 + 7 = " + calculator.add(5, 7));
}
}
(Server terminal) Calculator service is bound and ready.
(Client terminal) 5 + 7 = 12
Common Mistakes
- Forgetting that every method on a Remote interface must declare "throws RemoteException", since network failures are always possible.
- Assuming RMI works across different languages — both client and server must be Java, unlike REST or gRPC.
- Not accounting for serialization: every argument and return type passed through RMI must implement Serializable.
- Choosing RMI for a brand-new project today instead of a REST API, gRPC, or a message queue, which are far better supported and more interoperable.
Exercise
Declare a remote interface Calculator with a method add, following both rules that RMI requires of a remote interface. The implementation is called directly here, without a registry, so the program runs in one JVM.
Expected output: 12
import java.rmi.Remote;
import java.rmi.RemoteException;
// TODO: declare the interface Calculator with a method: int add(int a, int b)
// Rule 1: it must extend Remote
// Rule 2: every method must declare RemoteException
class CalculatorImpl implements Calculator {
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
}
public class RemoteInterfacePractice {
public static void main(String[] args) throws RemoteException {
Calculator calculator = new CalculatorImpl();
System.out.println(calculator.add(5, 7));
}
}
Show hints
- The declaration starts with
interface Calculator extends Remote. - The method is declared as
int add(int a, int b) throws RemoteException;
Show solution
import java.rmi.Remote;
import java.rmi.RemoteException;
interface Calculator extends Remote {
int add(int a, int b) throws RemoteException;
}
class CalculatorImpl implements Calculator {
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
}
public class RemoteInterfacePractice {
public static void main(String[] args) throws RemoteException {
Calculator calculator = new CalculatorImpl();
System.out.println(calculator.add(5, 7)); // 12
}
}
Quick quiz
1. Which interface must a remote interface extend?
- A. Serializable
- B. java.rmi.Remote
- C. Runnable
- D. Cloneable
Show answer
B. Remote is a marker interface that identifies methods that can be called from another JVM.
2. Why must every remote method declare RemoteException?
- A. It is only a convention
- B. It makes the call faster
- C. A network call can fail in ways a local call cannot, and the caller must handle that
- D. The method always throws it
Show answer
C. The server may be down or the connection may drop while the call is in progress.
3. What does the RMI registry do?
- A. Compiles remote classes
- B. Stores the results of calls
- C. Encrypts the connection
- D. Lets a client look up a remote object by name
Show answer
D. The server binds its object under a name, and the client looks that name up to obtain a stub.
Interview questions
How does an RMI call work?
Show answer
The client holds a stub, a local object that implements the remote interface. Calling a method on the stub serializes the arguments and sends them over the network to the server, where the real object runs the method. The return value, or the exception, is serialized and sent back, and the stub returns it to the caller. Arguments and results must therefore be serializable.
Why is RMI rarely chosen for new systems?
Show answer
Both sides must be Java, the classes on each side must match, and it depends on Java serialization, which is a known security risk. Its connections are also awkward to pass through firewalls. REST over HTTP, gRPC and message queues work between any languages and are the usual choices today.
Key Points to Remember
- RMI lets a Java object call a method on another object running in a different JVM as if it were local.
- The core pieces are a Remote interface, a UnicastRemoteObject implementation, and the RMI registry for lookup.
- Calling a stub method transparently serializes the call, sends it over the network, and returns the deserialized result.
- RMI is largely legacy today; modern systems favor REST APIs, gRPC, or message queues for distributed communication.
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering