skip to content

What is the Adapter pattern, and how does it appear in the JDK?

level: juniorimportance: must knowfreq 70%

answer

  1. Target / Adaptee / Adapter / Client roles
  2. InputStreamReader: bytes -> chars
  3. Arrays.asList: array -> List view
  4. Object adapter = composition (Java's default)
  5. Adapter changes interface; Decorator keeps it

basics

~20 s

Adapter is a wrapper that lets two incompatible interfaces work together. It takes an object with one interface and exposes it as another. In the JDK, InputStreamReader adapts a byte InputStream into a char Reader.

solid answer

~40 s

The Adapter pattern converts the interface a class offers into the interface a client expects, so two otherwise-incompatible types can collaborate. You wrap the existing object (the adaptee) in an adapter that implements the target interface and forwards calls, translating between the two. It is a structural pattern used when you can't change either side, for example when reusing legacy or third-party code. In the JDK, InputStreamReader adapts a byte-oriented InputStream to the char-oriented Reader interface, decoding bytes via a charset; Arrays.asList adapts a backing array to the List interface. The key intent is reuse-without-modification: the client codes only against the target interface and stays unaware of the adaptee.

go deeper

for a junior

Can define Adapter as a wrapper that makes incompatible interfaces work together and name InputStreamReader as a JDK example.

for a middle

Names the Target/Adaptee/Adapter roles, explains InputStreamReader (bytes->chars) and Arrays.asList (array->List view), and distinguishes Adapter from Decorator.

for a senior

Contrasts object vs class adapter, explains why composition dominates in Java, and reasons about the open/closed benefit and the view-semantics gotchas of Arrays.asList.

for a principal

Frames Adapter as an integration/anti-corruption tool at module boundaries, weighs adapter proliferation vs interface redesign, and connects it to API evolution and dependency-inversion strategy.

## The problem Sometimes you have an object that does what you need, but its **interface** (the set of methods it exposes) does not match the interface your code is written against. You can't (or don't want to) edit either side — maybe one is a third-party library, maybe it is legacy code many callers depend on. An **Adapter** is a small class that sits between them and translates. ## The roles - **Target** — the interface the client expects to call (e.g. `Reader`, `List`). - **Adaptee** — the existing object whose interface doesn't match (e.g. `InputStream`, a raw array). - **Adapter** — implements (or extends) the Target and holds/uses the Adaptee, forwarding each Target call to the appropriate Adaptee call, converting data as needed. - **Client** — code that depends only on the Target; it never sees the Adaptee. Analogy: a travel **power-plug adapter** lets a device with a European plug fit a UK socket. Neither the device nor the socket changes; the adapter bridges the shape mismatch. ## JDK examples **`InputStreamReader`** — an `InputStream` produces raw **bytes**; a `Reader` produces **chars**. They are incompatible interfaces. `InputStreamReader extends Reader` and wraps an `InputStream`, decoding the byte stream into characters using a charset (e.g. UTF-8). So `new InputStreamReader(socket.getInputStream(), UTF_8)` lets character-based code consume a byte stream. ```java Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); ``` **`Arrays.asList(T...)`** — turns a Java array into something usable where a `List` is expected. It returns a fixed-size `List` **view** backed by the same array: writes to the list write through to the array, and `set` works, but structural changes (`add`/`remove`) throw `UnsupportedOperationException`. It adapts the array's interface (indexed access) to the `List` interface. ## Object adapter vs class adapter There are two ways to build an adapter: - **Object adapter (composition)** — the adapter *holds a reference* to the adaptee as a field and delegates to it. This is the dominant Java form because Java has single inheritance of classes, and composition is more flexible (you can adapt any subtype of the adaptee, swap it at runtime). - **Class adapter (inheritance)** — the adapter *extends* the adaptee and *implements* the target. In Java this only works when the adaptee is a class you can subclass and the target is an interface, because you cannot extend two classes. `InputStreamReader` is close to this style: it `extends Reader` (target) and is *constructed with* an `InputStream` (adaptee, held internally) — so even it leans on composition for the adaptee. ## Related patterns (don't confuse) - **Decorator** keeps the *same* interface and *adds behavior* (e.g. `BufferedReader` wraps a `Reader` and stays a `Reader`). Adapter *changes* the interface. - **Facade** simplifies a whole subsystem behind one new interface; Adapter targets one specific incompatible interface. ## Why it matters Adapter is the practical tool for integrating mismatched code without rewriting it, honoring the open/closed principle (extend behavior without modifying existing classes).

  • How does Adapter differ from Decorator?
    Adapter changes the interface so two incompatible types can talk; Decorator keeps the same interface and adds behavior. BufferedReader wrapping a Reader is a Decorator (still a Reader); InputStreamReader wrapping an InputStream is an Adapter (InputStream -> Reader).
  • Why is Arrays.asList only a partial List?
    It returns a fixed-size view backed by the original array, so set works (writes through to the array) but add/remove throw UnsupportedOperationException because an array can't change size.

A travel power-plug adapter: it doesn't change the device or the wall socket, it just bridges the shape mismatch so they can connect.

saying these in an interview costs you the question

  • Calling InputStreamReader a Decorator — it changes the interface (bytes to chars), so it's an Adapter.
  • Thinking Arrays.asList returns a fully mutable, growable ArrayList.
  • Saying Adapter modifies the adaptee's source code — the whole point is reuse without modification.

context