views:

137

answers:

4

Firstly I'm not a Java guy, but I came across what appears on the surface to be an inconsistency with the way imports work.

Say you have a file and in this file you have your main function and you have also defined a class Foo, now a different implementation of Foo also exists in a package. Suppose you want to use both versions in your functionality.

You cannot explicitly import Foo from it's package, i.e. import mypackage.Foo;

As this will result in a conflict with the class defined locally in the file, so an error is generated at compile time.

What you can do is import the entire package, i.e. import mypackage.*;

This will work and you can access Foo by using the fully qualified name, using the simple name will result in the use of the local Foo. The inconsistency I see is that whilst the former generates an error (you have imported a class and sole purpose of the import is to be able to use the simple name as opposed to the fully qualified name) the latter does not even result in a warning.

I would have thought that both cases would generate a warning i.e. you may be using the wrong class as it is defined in 2 places, or the import statement is redundant as use of the simple name will resolve to the locally defined class, not the imported one.

So my question is: Is there an underlying reason it is implemented in this way?

Yes it is an outlier case, I do understand that.

+9  A: 

You can access Foo by using the fully qualified name even without importing mypackage.*;

About warnings: There's nothing dangerous happening, I guess. You aren't using anything ambiguous.

alamar
It's more that the locally defined class has silent preference in the latter example - you would expect the behaviour of the former example to be consistent with this as in both cases the import is redundant.
Stinomus
If there would be a warning about unused/redundant import, all compilations would suddently spam with hundreds of warnings.And also, nobody writes imports by hand these days.
alamar
Well unused and redundant aren't really the same thing. Are there that many cases where you import a package that has a class within it that is the same name as one of your locally defined classes?
Stinomus
Point is that both ways attempt to achieve the same result, and realistically they should.
Stinomus
+1  A: 

import mypackage.* might be necessary for all the other stuff that is in mypackage. If there was a warning, it would be hard to avoid it at all, i.e. you would have to fully qualify all other classes etc. you use from mypackage. Even worse, consider the case when version 1 of mypackage didn't contain Foo, so there was no conflict and therefore no reason at all to issue a warning. Version 2 contains Foo, but of course it's not the Foo you want to access in your program. Therefore, if the compiler warns about the "import package.*" conflicts, it makes "import package.*" potentially less upward compatible.

ammoQ
+3  A: 

As the above answer says, the import effectively does nothing regarding the Foo in the other package; regardless of whether you import or not, you can't refer to that other Foo via the short classname and you can refer to it via a fully-qualified classname.

Conceptually you can think of "import mypackage.*" not necessarily as "import all classes from * mypackage*", but perhaps "import all non-conflicting classes from * mypackage*". I don't know how the JVM implementation does it, but it could definitely decide not to match mypackage.Foo as part of the wildcard (and thus not import it at all) and the code would work the same either way.

Importing is really just setting up an alias from short class name to fully qualified class name (e.g. when I say "Date" understand that as "java.util.Date"). It's to be expected that you get a warning if you do something that's completely redundant, such as importing just the conflicting class would be. However, if you're pulling in a whole package with *, it would seem wrong to me for the compiler to complain that one of the classnames clashes; this would happen so often in practice, and be harmless 99%+ of the time, that it would engender a "boy who cried wolf" syndrome to the point where you'd be less likely to pay attention to these and other warnings since you just get used to being bombarded with them.

By the way, if you import both java.util.* and java.sql.*, this is allowed and happens without warnings; but if you then try to refer to just Date (without such a class in your local package), you'll get a compilation error as the name is ambiguous.

Andrzej Doyle
The JVM does nothing at all with imports; internally, it always uses fully qualified class names. Imports are only relevant to the compiler.
Michael Borgwardt
Imports are mostly relevant to the developer, because by importing a class you can refer to it by its short name and save yourself typing.
duffymo
Is there any reason they should not both result in the same behaviour though?
Stinomus
+1  A: 

You can think of "import p.*" as meaning "when you can't resolve a name in the current file, try to resolve it in package p". The compiler doesn't import everything in p at the point that it sees the import statement. Instead it looks in p (and other packages named in the import ...* statements) when it finds a name that it cannot resolve in the immediate compilation unit.

Nat