# reflection Companion code for the ankurm.com post *"Java Reflection and MethodHandles in 2026: How They Work and What They Cost."* One module in `java-core-examples`. Everything the post explains lives in the post itself (accordions per section); this module is the runnable evidence. ## Versions this was built and tested against | Component | Version | Notes | |---|---|---| | JDK | 25.0.5+8 (Temurin, LTS) | All demos and the JMH run. | | JDK (comparison only) | 26.0.2.1+1 (Temurin) | Used for the JEP 500 final-field warning in `output/03`. | | JMH | 1.37 | 3 warmup + 5 measurement iterations, 2 forks. | | JUnit Jupiter | 5.11.0 | Contract tests - they fail if a documented behaviour changes. | | Maven | 3.9.11 | | | Hardware | 2 vCPU Intel Xeon @ 2.30 GHz VM | Shared sandbox: treat ns figures as relative, not absolute. | ## Quickstart ```bash export JAVA_HOME=/path/to/jdk-25 mvn package # compiles, runs the contract tests, builds the JMH jar java src/main/java/com/ankurm/reflection/QuickStart.java java -cp target/classes com.ankurm.reflection.ReflectionBasicsDemo java -cp target/classes com.ankurm.reflection.ModuleRulesDemo java --add-opens java.base/java.lang=ALL-UNNAMED -cp target/classes com.ankurm.reflection.ModuleRulesDemo java -cp target/classes com.ankurm.reflection.FinalFieldDemo java -cp target/classes com.ankurm.reflection.MethodHandlesDemo java -jar target/benchmarks.jar CallBenchmark ``` `scripts/run-all.sh` regenerates every file in `output/` (set `JDK26_HOME` to include the JDK 26 runs). ## What's in here | File | What it shows | |---|---| | `Account.java` | The sample class: public API, private method, private/final fields, a throwing method. | | `QuickStart.java` | Self-contained: one call by `Method`, one by `MethodHandle`. Run with `java QuickStart.java`. | | `ReflectionBasicsDemo.java` | Inspect, construct, invoke; the five exceptions you will meet; extra stack frames. | | `ModuleRulesDemo.java` | `setAccessible` on your class vs. a JDK internal; `--add-opens`. | | `FinalFieldDemo.java` | Final instance / static / record fields; constant-inlining trap; JEP 500 on JDK 26. | | `MethodHandlesDemo.java` | `invokeExact` vs `invoke`, composition, lookup-time access checks, `VarHandle`. | | `CallBenchmark.java` | JMH: direct vs `Method` vs `MethodHandle` vs `Field` vs `VarHandle`, static-final vs instance field. | | `ReflectionContractTest.java` | Eight tests pinning the contracts the post states. | ## Captured output | File | From | |---|---| | `output/01-basics.txt` | `ReflectionBasicsDemo` | | `output/02-module-rules.txt` | `ModuleRulesDemo`, without and with `--add-opens` | | `output/03-final-fields.txt` | `FinalFieldDemo` on JDK 25, JDK 26, and JDK 26 with `--illegal-final-field-mutation=deny` | | `output/04-method-handles.txt` | `MethodHandlesDemo` | | `output/05-call-benchmark.txt` | `CallBenchmark` (non-deterministic; relative ordering is the result) | | `output/06-quickstart.txt` | `QuickStart` | Identity-hash suffixes like `unnamed module @6b95977` change on every run.