Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Code Example of "obscuring" as per JLS (6.4.2. Obscuring), especially this "local variable or type can obscure a package"

Tags:

java

Could you give a few examples (code snippets) of obscuring?

I read the JLS, but I didn't understand the concept. JLS gives no code examples.

Hiding is between fields of Base and Derived class.

Shadowing is between a field and a local variable.

Obscuring - between what (?) and what (?)

SIDELINE: Interesting, JLS says that in case of hiding respective field from parent class is not inherited:

Shadowing is distinct from hiding (§8.3, §8.4.8.2, §8.5, §9.3, §9.5), which applies only to members which would otherwise be inherited but are not because of a declaration in a subclass. Shadowing is also distinct from obscuring (§6.4.2).

I also know that class names, method names and field names are all in their different namespaces:

// no problem/conflict with all three x's
class x {
    void x() { System.out.println("all fine"); }
    int x = 7; 
}

EXAMPLES:

Finally found an example and some explanation of what is claimed to be obscuring (it causes compile error):

class C {
    void m() {
        String System = "";
        // Line below won't compile: java.lang.System is obscured 
        // by the local variable  String System = ""
        System.out.println("Hello World");  // error: out can't be resolved          
    }
}

The above situation could be resolved by using the fully qualified name java.lang.System, or by statically importing System.out. If we happened to also have variables called java and out, neither of these workarounds would work and it would be impossible to access System.out.println.

like image 207
Code Complete Avatar asked Jan 09 '19 14:01

Code Complete


4 Answers

Example 1: "package name (java.lang.System) is obscured by a declaration of a parameter or local variable" (JLS)

Local variable named System obscures package name ("package name" is java.lang.System), which is why java.lang.System is not recognized in the line System.out.println(System.out);

public class ObscuringTest { 

    // static class System { } // nested class named `System`   

    public static void main(String[] args) {
        String System; // local var named `System` (breaks convention)      

        System.out.println(System.out); // compile error        
    } 
} 

Example 2: "package name (java.lang.System) is obscured by a field declaration" (JLS)

public class ObscuringTest { 

    String System; // field named `System` (breaks convention)      

    public static void main(String[] args) {

        // Cannot make a static reference to the non-static 
        // field System
        System.out.println(System.out); // compile error    
    } 
} 

Not Obscuring: Shadowing of a Type Declaration by Another Type Declaration (JLS, like Example 6.4.1-2)

 // also produces same shadowing    
 // class System { } // same-package class named `System`   

public class ObscuringTest { 

     static class System { } // nested class named `System` 

     // also produces same shadowing
     //  class System { } // inner class named `System` 

    public static void main(String[] args) {            

        // clash with java.lang.System, no obscuring !
        System obj = new System();  // ObscuringTest$System                 
    } 
} 

JLS: 6.4.2. Obscuring

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.

Obscuring is distinct from shadowing (§6.4.1) and hiding (§8.3, §8.4.8.2, §8.5, §9.3, §9.5).

Method names cannot obscure or be obscured by other names (§6.5.7).

Field names cannot obscure method names.

Constant names cannot obscure method names, because they are distinguished syntactically.

like image 183
Code Complete Avatar answered Nov 03 '22 03:11

Code Complete


In this example A is an obscured name.

public class Main{
    static class A{static int i = 2;}
    static Integer A=1;
    public static void main(String[] args) throws Exception{
        //System.out.println(A.i); cannot do because A is an integer.
        System.out.println(A); //prints out 1.

    }
}

Name resolution will point to the Integer field, and there is no fully qualified name to access the nested class, as in the case of shadowing.

Although new + constructor will reference the type and not the field.

System.out.println(new A()); //prints out class

We could a hold of the class through reflection.

Class<?> c = Class.forName("Main$A");

As mentioned in the jls, a decent naming convention should help avoid this issue.

like image 38
matt Avatar answered Oct 22 '22 21:10

matt


Given the explanation in the JLS:

A simple name may occur in contexts where it may potentially be interpreted as the name of a variable, a type, or a package.

A simple example could be:

int String = 0;
String name = "2";

//Will print 0 as per the JLS
//Would fail without the obscured String variable
System.out.println(String); 

Where the identifier String which is a simple name for the class java.lang.String can be said to be obscured in the declaration of the String local variable.

like image 5
ernest_k Avatar answered Nov 03 '22 03:11

ernest_k


As the JLS says, obscuring happens between a type and a package, or a local variable and a type. Here's a simple example of the second type of obscuring, where the local variable a obscures a class with the same name:

class Foo {
    class a {

    }

    int x() {
        int a = 0;
    }
}
like image 4
yole Avatar answered Nov 03 '22 01:11

yole