How do canAccess and trySetAccessible differ from setAccessible, and when should you use them?
answer
- All three on AccessibleObject
- setAccessible: void, throws on denial
- trySetAccessible: boolean, no throw, no false-arg
- canAccess(obj): pure query, no mutation
- null obj for static/constructor; instance for instance member
basics
~10 ssetAccessible(true) returns nothing and throws if denied. trySetAccessible() does the same enabling but returns true/false instead of throwing. canAccess(obj) just asks whether access would currently succeed, without changing anything.
solid answer
~50 sAll three live on AccessibleObject. setAccessible(boolean) sets the suppress-checks flag and throws InaccessibleObjectException (or SecurityException) if it can't — so it forces the issue and you must catch failures. trySetAccessible(), added in Java 9, attempts the same enabling but returns a boolean: true if access is now available, false if the module system denies it — letting you branch to a fallback without exception handling. canAccess(Object obj), also Java 9, is a pure query: it returns whether the current accessibility state would permit get/set/invoke against that object (you pass the instance for instance members, or null for static/constructors), and never mutates the flag. The pattern for robust library code is: check canAccess, or call trySetAccessible and if it returns false fall back to a public API, MethodHandles, or a clear error message — rather than letting an unchecked InaccessibleObjectException blow up deep in your framework. Use plain setAccessible only when failure truly is fatal and you want the exception.
code
java · 17 linesMethod m = target.getClass().getDeclaredMethod("compute");
// Graceful: enable, but tolerate a module denial
if (m.trySetAccessible()) {
Object result = m.invoke(target);
} else {
// fall back to a public API, or throw an actionable error
throw new IllegalStateException(
"compute() is not reflectively accessible; add --add-opens for its module");
}
// Pure probe, no state change (instance member -> pass the instance):
boolean reachable = m.canAccess(target);
// For a static member or constructor, pass null:
Constructor<?> c = target.getClass().getDeclaredConstructor();
boolean ctorReachable = c.canAccess(null);go deeper
Knows trySetAccessible returns a boolean and canAccess just checks, while setAccessible throws.
Can use trySetAccessible with a fallback branch and knows canAccess takes the instance (or null for static/ctor).
Explains why the soft methods were added (graceful degradation under JPMS) and picks the right one per situation, including actionable error messages.
Designs reflection-heavy libraries to be module-friendly: probe-and-fallback to public APIs or MethodHandles, surface --add-opens guidance, and avoid leaking InaccessibleObjectException to callers.
These three methods all belong to **`java.lang.reflect.AccessibleObject`** (the supertype of `Field`, `Method`, `Constructor`). They are about the *accessible flag* — the per-object switch that decides whether reflection bypasses Java's access checks. **1. `void setAccessible(boolean flag)` (since Java 1.2):** the imperative one. `setAccessible(true)` turns on bypass; `setAccessible(false)` turns it off. It returns nothing. If the module system forbids deep reflection it throws **`InaccessibleObjectException`** (unchecked, Java 9+); under a `SecurityManager` it could throw `SecurityException`. So with `setAccessible` you either succeed or get an exception you must handle. **2. `boolean trySetAccessible()` (since Java 9):** the *soft* version. It tries to enable deep access (equivalent to `setAccessible(true)`) but instead of throwing on a module denial, it **returns `false`**. It returns `true` if access is now available. This lets you write `if (m.trySetAccessible()) { ...use it... } else { ...fallback... }` with no try/catch around module failures. (Note: it does not have a `false` argument — there is no `trySetAccessible(false)`; use `setAccessible(false)` to disable.) **3. `boolean canAccess(Object obj)` (since Java 9):** a *pure query* — it does **not** change the flag. It answers: 'given the current accessible state, would I be allowed to get/set/invoke this member on `obj`?' For an **instance** member you pass the target instance; for a **static** member or a **constructor** you pass `null` (passing a non-null for a static, or a wrong-type instance, throws `IllegalArgumentException`). It returns `true`/`false`. Use it to probe before attempting, or to verify after a `setAccessible` call. **Why the soft methods exist:** before Java 9, `setAccessible` essentially always worked, so libraries called it unconditionally. After JPMS, that call can throw at runtime in environments the library author can't predict (different module configs, different `--add-opens`). `trySetAccessible`/`canAccess` give libraries a way to **degrade gracefully**: detect the denial and fall back to a public constructor, a builder, `MethodHandles.privateLookupIn` with proper access, or a precise actionable error ('add `--add-opens ...`') instead of an opaque `InaccessibleObjectException` surfacing three frames up. **Choosing between them:** - Use **`canAccess`** when you only want to *know* and not mutate state (e.g. caching whether a field is reachable). - Use **`trySetAccessible`** when you want to *enable* access but tolerate failure with a fallback. - Use **`setAccessible(true)`** when failure is genuinely unrecoverable and you prefer the exception (or want to wrap it in your own message), or in simple/test code where you control the runtime. **Subtlety:** `canAccess` reflects the *current* flag state. Right after a successful `setAccessible(true)`, `canAccess` returns `true`; before it, it returns whether *normal* access rules would allow it. So `canAccess` is not the same as 'could I make it accessible' — that's what `trySetAccessible` answers.
- What do you pass to canAccess for a static field versus an instance field?For an instance member pass the target instance; for a static member (or any constructor) pass null. Passing a non-null instance for a static member, or an instance of the wrong type, throws IllegalArgumentException.
- Is there a trySetAccessible(false)?No — trySetAccessible takes no argument and only attempts to ENABLE access (returning a boolean). To disable, call setAccessible(false), which doesn't fail for that direction.
setAccessible is yanking the door handle (it opens or you hit a locked door and stumble). trySetAccessible is trying the handle and noting whether it gave way (so you can take the stairs instead). canAccess is just looking to see if the door is currently unlocked, without touching it.
saying these in an interview costs you the question
- Thinking canAccess enables access — it is read-only and mutates nothing.
- Believing trySetAccessible throws InaccessibleObjectException — it returns false instead.
- Passing the instance to canAccess for a static member (it must be null) — that throws IllegalArgumentException.
- Assuming canAccess answers 'could I make it accessible' — it only reports the current state; trySetAccessible answers the 'could I enable' question.