3

Consider the following code:

import java.util.Calendar;

class Demo
{
    class Calendar {}

    public static void main (String[] args) {
      // System.out.println(Calendar.DAY_OF_WEEK);  // Would be an error.
    }
}

This code compiles fine; but if you refer to Calendar within Demo, you are referring to Demo.Calendar, not java.util.Calendar.

The import is clearly redundant; but it seems strange that it is allowed, considering you're not allowed to import a class with the same simple name as a top-level class defined in the same compilation unit (per JLS Sec 7.5.1):

import java.util.Calendar;  // error: Calendar is already defined in this compilation unit

class Calendar {}

Is there a practical reason why such an import as in the first code example would not be a compile-time error?

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • It's not redundant; it's ineffectual. With that said, I'm pretty sure this is legal simply because the language specification doesn't forbid it. Probably it is a case not considered by the language designers. – davmac Apr 06 '17 at 15:31
  • You misread the JLS. It doesn't forbid importing a name that's the same as a top-level class, it forbids importing a name `n` if "the compilation unit also declares a top level [sic] type whose simple name is `n`". That's not the situation you show. – Lew Bloch Apr 06 '17 at 18:44
  • @LewBloch I don't understand the difference you are pointing out. Please can you provide an example to demonstrate the distinction? – Andy Turner Apr 06 '17 at 18:48
  • What is the name of the top-level class in your example? Is it `Calendar` or something else, like, say, `Demo`? – Lew Bloch Apr 06 '17 at 18:49
  • The case where I'm saying "you're not allowed to import a class with the same name as a top-level class" is the second one, where I am importing `Calendar` and have a top-level class called `Calendar`. I'm saying that I understand why the second case is forbidden, but I'm surprised that the spec doesn't also stipulate that the first case would be forbidden. – Andy Turner Apr 06 '17 at 18:50
  • @LewBloch But irrespective of what I meant, please can you provide an example do illustrate your comment "It doesn't forbid importing a name that's the same as a top-level class, it forbids importing a name n if "the compilation unit also declares a top level [sic] type whose simple name is n". ". I don't see the distinction you are trying to make. – Andy Turner Apr 06 '17 at 18:59
  • 1
    "I'm surprised that the spec doesn't also stipulate that the first case would be forbidden." I can't speak to your surprise, @AndyTurner; it's a psychological reaction. The only conflict is if the simple name imported matches the name of a top-level class in the compilation unit. The distinction is that it only forbids that in the definition of the conflictingly-named top-level class. A class is perfectly free to import a name that is the same as some _other_ top-level class than one in the compilation unit. So `Demo` can import `Calendar` just fine. – Lew Bloch Apr 07 '17 at 01:51

2 Answers2

3

The only case I can come up with is where you have a twice (or more) -nested class with the same name as the import:

import java.util.Calendar;

class Demo {
  static class Nested {
    static class Calendar {}

    static void useNested() {
      System.out.println(Calendar.class);  // Demo.Nested.Calendar
    }
  }

  static void useImported() {
    System.out.println(Calendar.class);  // java.util.Calendar
  }

  public static void main(String[] args) {
    Nested.useNested();
    useImported();
  }
}

Ideone demo

In this case, the nested Calendar isn't automatically visible outside the scope of the Nested class, so the imported Calendar class is used outside, e.g. in the useImported method.

I wouldn't really describe this as a "practical" use, though - it's just plain confusing as to which is used in each context, and definitely worth avoiding. It still interested me that this case exists, though.


I suppose there is another similar case:

import java.util.Calendar;

class Demo {
  static void useImported() { ... }
}

class Demo2 {
  class Calendar {}

  static void useNested() { ... }
}

(where these classes are in the same compilation unit). Basically the same idea as above.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
0

I suppose, if you import a class, it's visible in the global space of that compilation unit. But if you name your compilation unit or top level class the same as the import, then you are basically conflicting it with the import and hence it'll be ambiguous for JVM to know which is which. and since its compiling a class, it'll give an error for import.

Also, when it's inside another class, you are shadowing the import over there. It's just similar in the way as global/class level variables and method level variables hiding them if defined with the same name.

Hope this helps.

Avinash Anand
  • 655
  • 2
  • 15
  • 25
  • "hence it'll be ambiguous for JVM" It's not ambiguous, you simply can't refer to the imported class, so it's prevented. It's just like preventing things like `"" instanceof Integer`: it's not ambiguous to the JVM, it just probably indicates programmer error. – Andy Turner Apr 06 '17 at 15:18
  • @AndyTurner - I was explaining assuming if the JVM allowed the import and top level class names as same in the same compilation unit. Sorry, maybe I was not clear. – Avinash Anand Apr 06 '17 at 15:20
  • Yes, I understood that, and I'm saying that it's not ambiguous: it's *redundant*, in the same way that `"" instanceof Integer` is a redundant way of writing `false`, and thus is disallowed by the compiler. – Andy Turner Apr 06 '17 at 15:21