How to fully qualify a class whose package name co

2019-05-07 14:59发布

问题:

OK, here's a very curious Java 7 language puzzle for the JLS specialists out there. The following piece of code won't compile, neither with javac nor with Eclipse:

package com.example;

public class X {
    public static X com = new X();

    public void x() {
        System.out.println(com.example.X.com);
        // cannot find symbol  ^^^^^^^
    }
}

It appears as though the member com completely prevents access to the com.* packages from within X. This isn't thoroughly applied, however. The following works, for instance:

public void x() {
    System.out.println(com.example.X.class);
}

My question(s):

  • How is this behaviour justified from the JLS?
  • How can I work around this issue

Note, this is just a simplification for a real problem in generated code, where full qualification of com.example.X is needed and the com member cannot be renamed.

Update: I think it may actually be a similar problem like this one: Why can't I "static import" an "equals" method in Java?

回答1:

This is called obscuring (jls-6.4.2).

A simple name may occur in contexts where it may potentially be interpreted as the name of a variable, a type, or a package. In these situations, the rules of §6.5 specify that a variable will be chosen in preference to a type, and that a type will be chosen in preference to a package. Thus, it is may sometimes be impossible to refer to a visible type or package declaration via its simple name. We say that such a declaration is obscured.



回答2:

Your attribute com.example.X.com is not static so it can't be accessed via your X class in a static way. You can access it only via an instance of X.

More than that, each time you will instanciate an X, it will lead to a new X : I can predict a memory explosion here.

Very bad code :)



回答3:

How can I work around this issue?

Using a fully qualified class name here can be a problem because, in general, package names and variable names both start with lower case letters and thus can collide. But, you do not need to use a fully qualified class name to gain a reference a class's static member; you can reference it qualified just by the class name. Since class names should start with an upper case character, they should never collide with a package name or variable. (And you can import an arbitrary class with its fully qualified class name without issue, because the import statement will never confuse a variable name for a package name.)

public void x() {
    // System.out.println(com.example.X.com);
    // cannot find symbol     ^^^^^^^

    System.out.println(X.com);  // Works fine
}