请求解析Java中Obscuring(遮蔽)概念并提供代码示例
Let's break down these concepts clearly, since you've already dug into JLS 6.4.2 but didn't get concrete examples to clarify obscuring:
Quick Recap of What You Already Know
- Hiding: Occurs between superclass and subclass fields (or static methods). When a subclass declares a field with the same name as a superclass field, the superclass field is hidden and isn't inherited into the subclass's namespace for direct access.
- Shadowing: Happens when a local variable (or method parameter) shares the same name as a class member field. The local variable "shadows" the member field within its scope—any reference to that name will resolve to the local variable instead of the field.
- As you pointed out, Java keeps separate namespaces for class names, method names, and field names. That's why this code works without conflicts:
class x { void x() { System.out.println("all fine"); } int x = 7; }
What Is Obscuring, and When Does It Occur?
Obscuring is distinct from shadowing and hiding because it happens across different namespaces: when an identifier from one namespace masks an identifier from another. The most common scenarios are:
- A variable name obscuring a class name
- A class name obscuring a package name
Unlike shadowing/hiding (which operate within the same namespace, just across scopes or inheritance levels), obscuring crosses these namespace boundaries, making the original identifier impossible to resolve directly without extra steps.
Your Obscuring Example Explained
The code you found is a perfect demonstration of variable-to-class obscuring:
class C { void m() { String System = ""; // Compile error: java.lang.System is obscured by the local variable System.out.println("Hello World"); // error: out can't be resolved } }
Here's the breakdown:
Systemis a class in thejava.langpackage (part of the class namespace)- You've declared a local variable named
System(part of the variable namespace) in the method scope - When you write
System.out, the compiler prioritizes the variable namespace first—it treatsSystemas your string variable, which has nooutmember, hence the error. Thejava.lang.Systemclass is now obscured and can't be referenced directly by its simple name.
Fixing Obscuring
You can work around this in two standard ways:
- Use the fully qualified class name:
java.lang.System.out.println("Hello World"); - Static import the
outfield beforehand:import static java.lang.System.out; class C { void m() { String System = ""; out.println("Hello World"); // Works perfectly } }
As you noted, in an extreme edge case where you have variables named java and out, even the fully qualified name would fail—since java would be treated as a variable instead of the package name. Thankfully, this scenario is extremely rare in real-world code.
Core Differences at a Glance
| Concept | Context | Key Behavior |
|---|---|---|
| Shadowing | Same namespace, different scopes | Local variable/method parameter masks class member field. |
| Hiding | Same namespace, inheritance hierarchy | Subclass field/static method masks superclass field/static method. |
| Obscuring | Cross-namespace (e.g. variable ↔ class) | Identifier from one namespace masks another, blocking direct access. |
内容的提问来源于stack exchange,提问作者Code Complete

