You can write `someObject.staticField` to reach a static member through an instance. Why is this allowed but discouraged?
answer
- object is ignored; resolves to the declared type at compile time
- misleading: looks per-instance, is class-shared
- static is NOT polymorphic (binds to declared type)
- works even on a null reference (no NPE)
- prefer ClassName.member; IDEs warn
basics
~20 sJava lets you reach a static member through an object reference, but it really just resolves to the class. It's discouraged because it misleads readers into thinking the value is per-object when it's actually shared by the whole class. Use ClassName.member instead.
solid answer
~40 sStatic members can be accessed through an instance reference (`obj.staticField`, `obj.staticMethod()`), but the compiler ignores the object and resolves the access against the *declared type* of the reference at compile time. The object is not used at all, which leads to two surprises: it's misleading (it reads like per-instance state when the member is class-wide and shared), and with subtype references it can resolve to the wrong class because static access is *not* polymorphic. A notorious gotcha: `obj.staticMethod()` still executes even when `obj` is `null`, because no instance is dereferenced. For these reasons style guides and IDEs flag instance-qualified static access; the idiomatic and clear form is `ClassName.member`. The feature exists mostly for historical/Java-language-spec reasons, not because it's useful.
go deeper
Knows the preferred form is ClassName.member and that accessing statics via an object is discouraged.
Explains that the object is ignored and the access resolves to the declared type, making it misleading; cites the null-reference and non-polymorphism surprises.
Connects it to static hiding vs overriding and compile-time binding; treats IDE/style warnings as enforceable conventions.
Frames it as a JLS legacy/grammar artifact, weighs backward-compat constraints, and sets team-wide lint policy to forbid it.
## Setup A **static member** belongs to the class (one shared copy / no instance needed). The normal way to access it is by the class name: `Math.PI`, `Integer.parseInt(...)`. Java *also* lets you reach a static member through an **instance reference**: ```java Integer i = 5; int x = i.parseInt("10"); // legal, but parseInt is static! ``` This compiles. But it's misleading and discouraged. Here's why. ## What actually happens: the object is ignored When you write `i.parseInt("10")`, the compiler sees that `parseInt` is static and **rewrites the call to `Integer.parseInt("10")`**. The reference `i` is used only to determine the *type* (`Integer`) at **compile time**; the actual object is never touched. Consequences: ### 1) It reads as per-instance state but isn't ```java order.taxRate // looks like this order's tax rate ``` If `taxRate` is static, every order shares one value — changing it for one 'changes it' for all. A reader scanning the code is misled. `Order.taxRate` makes the class-wide nature obvious. ### 2) Static access is not polymorphic — it binds to the declared type ```java class A { static String who() { return "A"; } } class B extends A { static String who() { return "B"; } } A ref = new B(); String r = ref.who(); // "A", not "B"! ``` Because static resolution uses the *declared* type `A` (compile-time), not the runtime object `B`, you get `A`. Instance method overriding would have given `B`. This surprise is a direct trap of instance-qualified static access. ### 3) It "works" even on `null` ```java Integer n = null; n.parseInt("7"); // does NOT throw NPE ``` Since the object is never dereferenced (only its compile-time type matters), a `null` reference still calls the static method successfully. That's confusing — every other `null.member` access throws `NullPointerException`. ## The recommended form Always qualify with the class: ```java Integer.parseInt("10"); Math.PI; A.who(); ``` IDEs (IntelliJ, Eclipse), `checkstyle`, and many style guides emit a warning like "Static member accessed via instance reference" and offer to rewrite it to class-qualified form. ## Why does the language allow it at all? Mostly historical: the Java Language Specification permits it for grammar uniformity (a field/method access expression doesn't have to know statically whether the member is static). It survives for backward compatibility, not because it's good style. Treat it as a legacy quirk to avoid.
- Given `A ref = new B();` with a static `who()` overridden-looking method in both, what does `ref.who()` return and why?It returns `"A"`. Static methods are not overridden but hidden, and access resolves against the *declared* type `A` at compile time, ignoring the runtime `B` object.
- Why doesn't `nullRef.staticMethod()` throw a NullPointerException?Because the call is resolved to `ClassName.staticMethod()` at compile time and the object is never dereferenced; only the reference's compile-time type is used.
saying these in an interview costs you the question
- Thinking the instance somehow selects which copy is used (there's only one copy)
- Expecting `ref.staticMethod()` to dispatch to the runtime type (it uses declared type)
- Expecting a NullPointerException when the reference is null
- Believing it's idiomatic just because it compiles