Reputation: 2546
Moving from C++, one of the big differences was the difference in scoping: In C++ every identifier is relative to the current scope (class
or namespace
) and you could write an absolute path with the scope resolution operator ::
in the beginning.
However, in Java I could not find a way to access to an identifier from other package without importing it to the current scope or writing its full path.
It could be a problem if I have a few classes with the same name (then, in C++ I would address them as Module1::Foo and Module2::Foo, which is not possible in Java as long as I want to save my sanity since com.company.project.module1.Foo
is too long for my taste).
Here's an example for accessing the class Tools.Useless.Foo
from Java and C++ (with no import
or using
)
Tools/Useless/Foo.hpp
:
namespace Tools {
namespace Useless {
class Foo {
};
}
}
Tools/Bar.hpp
namespace Tools {
...
// Use Foo with a relative identifier
Useless::Foo foo;
// Use Foo with an absolute identifier.
::Tools::Useless::Foo bar;
...
}
And that's how it would look in Java:
com/company/project/Tools/Useless/Foo.java
:
package com.company.project.Tools.Useless;
public class Foo { }
com/company/project/Tools/Bar.java
:
...
// Use Foo with a relative identifier
???
// Use Foo with an absolute identifier.
com.company.project.Tools.Useless.Foo foo;
...
Foo
from package Tools.Useless
without specifying Tools.Useless
full package name (and importing it; since importing it will bind it to the current scope)?ToolsUselessFoo
instead of just Foo
).import path.to.module.*
instead of import path.to.module.Foo
and then access Foo
the the needed packages to resolve any ambiguity. The problem is that sometimes the package names has a meaning (e.g. Tools.Useless.Foo
and Tools.Useful.Foo
).Upvotes: 1
Views: 1715
Reputation: 298103
Java packages are not nested. While their names may have common prefixes, that has no meaning within the Java programming language.
Also the fact that their class files are stored in nested directories when the storage is a file system, has no additional meaning. When classes are stored in a jar file, they are stored with entry names matching their qualified names without actually forming directories at all (though a lot of tools like to present them as-if being in a hierarchical structure to mimic a file system).
So the packages com.company.project.tools.useless
and com.company.project.tools
have no relationship at all. While we humans tend to organize code in such a way, that a semantic relationship can be assumed here (which is a good thing), there is none on a technical level. There is no relative addressing between them and there are no additional access rights, compared to any other two packages. In fact, both packages could be part of two different modules (starting with Java 9), with even less access permission compared to two other packages with less similar names.
The standard approach to use the class from another package, is to use import com.company.project.Tools.Useless.Foo;
, followed by using Foo
within the class.
It’s not quiet clear, which problem you see with that, i.e. what “since importing it will bind it to the current scope” is supposed to mean. The mere existence of an import
statement, has no effect on the code. All it tells the compiler, is how to resolve occurrences of the simple name Foo
, if no other Foo
is in scope.
In other words, local scopes still have precedence, even including inherited members. Further, at places where variables and types could appear, variables have precedence. E.g. for an occurrence of Foo.bar()
, a variable called Foo
would have precedence, a local variable before member variables within the same type, an outer class or inherited ones. Otherwise, member types, outer types or inherited member types would be used. Only if none of them exist, the import
statement would be used to resolve Foo
.
Needless to say, you should avoid having so many items with the same simple name that you would have to think about the details of the resolving process. That’s why the naming conventions suggest to start variable names with a lowercase letter and class names with an upper case letter.
And yes, avoid giving classes the same simple name. Once you have to deal with both classes within the same compilation unit, there is no way around accessing one of them with its (fully¹) qualified name throughout the entire compilation unit. (Using a *
in import doesn’t help you in any way with such a scenario)
As explained, the term “fully” is obsolete in Java, as qualified names are always complete.
Upvotes: 3