skip to content

How do you read and write a field (including a private one) reflectively, and what does setAccessible(true) actually do?

level: middleimportance: should knowfreq 45%

answer

  1. getField (public+inherited) vs getDeclaredField (any access, this class)
  2. setAccessible(true) suppresses the access check, doesn't change the modifier
  3. get(obj)/set(obj,val); null obj for static
  4. primitives boxed; typed getInt/setInt avoid boxing
  5. final writes unreliable; module opens gate setAccessible

basics

~10 s

Get a Field via getDeclaredField("name"), call field.setAccessible(true) if it's private, then field.get(obj) to read and field.set(obj, value) to write. Pass null as the object for static fields.

solid answer

~40 s

You obtain a java.lang.reflect.Field with getField (public only, inherited) or getDeclaredField (any access, this class only). To touch a non-public field you must first call field.setAccessible(true), which suppresses the normal Java access checks for that Field object — it does not change the field's modifier. Then field.get(obj) returns its value as Object (primitives are boxed; there are typed variants like getInt), and field.set(obj, value) assigns it. For static fields, pass null as the instance. Writing a final field is unreliable and largely blocked on modern JDKs. Under the module system (Java 9+), setAccessible only succeeds if the field's package is open to your module, otherwise it throws InaccessibleObjectException. Reflective field access is slower than direct access and breaks encapsulation, so it's a tool of last resort.

code

java · 8 lines
java
Field f = obj.getClass().getDeclaredField("secret");
f.setAccessible(true);          // required for a private field
Object value = f.get(obj);      // read
f.set(obj, "new value");        // write
// static field:
Field s = MyType.class.getDeclaredField("COUNT");
s.setAccessible(true);
int count = s.getInt(null);     // null instance, typed getter avoids boxing

go deeper

for a junior

Can read/write a field with getDeclaredField + setAccessible + get/set, knows null for static.

for a middle

Explains that setAccessible suppresses the check without changing the modifier, and that primitives box.

for a senior

Covers module-system gating (InaccessibleObjectException, opens/--add-opens) and why final writes are unreliable.

for a principal

Weighs the encapsulation/coupling cost, prefers public APIs or VarHandle, and reasons about strong encapsulation impact on library/framework design.

## Goal Sometimes you need to read or modify a field whose name is known only at runtime, or a field that is `private` and has no getter/setter — for example a serialization or dependency-injection framework populating an object. The `java.lang.reflect.Field` API does this. ## Step 1 — get the `Field` - `clazz.getField(String name)` — returns a **public** field, **including inherited** ones. - `clazz.getDeclaredField(String name)` — returns a field of **any** access level (private/protected/package), but **only one declared directly on that class**. ## Step 2 — `setAccessible(true)` (for non-public fields) Java enforces access control: normally you can't read a `private` field of another class. A reflective `Field` object obeys the same rules **unless** you call: ```java field.setAccessible(true); ``` What this *actually does*: it tells the JVM to **suppress the access-control (visibility) checks** for *this particular `Field` object* when you later call `get`/`set`. Key clarifications: - It does **not** change the field's `private` modifier — the field is still private to everyone else; only this reflective handle bypasses the check. - It is a per-object flag on the `Field`, `Method`, or `Constructor` (all `AccessibleObject`s share this). - Since **Java 9 (the module system)**, it only succeeds if the field's package is **open** (via `opens` in `module-info.java`, or running on the classpath/unnamed module). Otherwise it throws **`InaccessibleObjectException`**. This is "strong encapsulation" — modules can refuse reflective access. ## Step 3 — read and write ```java Object value = field.get(obj); // read field.set(obj, newValue); // write ``` - `obj` is the **instance** that owns the field; for a **static** field pass `null`. - `get` returns `Object`; a primitive field's value is **boxed** (an `int` field returns an `Integer`). There are typed helpers — `getInt`, `getLong`, `getBoolean`, etc. — that avoid boxing. - `set` takes an `Object`; the value must be assignment-compatible or you get `IllegalArgumentException`. ## `final` fields Writing to a `final` field reflectively is **unreliable and discouraged**: the JIT may have inlined the constant, and modern JDKs block it for record/hidden/most fields. Treat `final` as truly immutable. ## Exceptions - `NoSuchFieldException` — no such field (from the lookup). - `IllegalAccessException` — not accessible and you didn't enable access. - `IllegalArgumentException` — wrong owner type or incompatible value. - `InaccessibleObjectException` — `setAccessible` denied by the module system. ## Cost & caution Reflective field access is slower than a direct `obj.field` and **breaks encapsulation** — it can read/mutate state the class author meant to protect, and it couples you to private internals that can change. Use it only when there's no public API (frameworks, serialization, tests). From these pieces you can derive how any framework injects values into private fields and why `setAccessible` is both powerful and gated.

  • Does setAccessible(true) change the field's access modifier?
    No. It only suppresses the access check for that one reflective Field/Method/Constructor object. The field stays private for all normal code.
  • On Java 17 with a strongly-encapsulated module, what happens when you call setAccessible(true) on a private field whose package isn't opened?
    It throws InaccessibleObjectException. The module must declare 'opens' for that package (or you must add --add-opens) to permit deep reflection.

saying these in an interview costs you the question

  • Claiming setAccessible(true) removes the private modifier or makes the field public to everyone.
  • Assuming you can freely mutate final fields reflectively on modern JDKs.
  • Forgetting to pass null as the instance for a static field.
  • Ignoring the Java 9+ module 'opens' requirement for deep reflection.

context