Java Keywords (Part XIII): Import Keyword and the Concept of Java Packages
Java keyword list
abstract | continue | for | new | switch |
assert | default | goto* | package | synchronized |
boolean | do | if | private | this |
break | double | implements | protected | throw |
byte | else | import | public | throws |
case | enum | instanceof | return | transient |
catch | extends | int | short | try |
char | final | interface | static | void |
class | finally | long | strictfp | volatile |
const* | float | native | super | while |
Packages
The purpose of the keyword package, is to define the namespace for the classes contained in it.
The simplest way to think of a package is as a folder; mainly because it is indeed a folder. We use folders primarily to keep things organized in a logical way. Most computer Operating Systems offer a series of folders out of the box, to help us stayed organized: Photos, Videos, Music, Documents, Desktop. When we want to store photos, it makes sense to store them in the "Photos" folder. We can also create our own subfolders to further organize the contents of a folder. For instance, you may want to store last year's vacation photos in "Vacation 2019" insde the Photos folder. Likewise, we can use packages and sub-packages to compartmentalize our classes in groups that make some logical sense. This partitioning provides a namespace for our classes. Namespaces help with avoiding collisions with other classes that may have the same name; just like you cannot have two files with the same name in the same folder. So, if you need to tell the operating system that you need a certain file, providing the full path and name of the file guarantees that you will get precisely the file you need. In Java, the combination of the package (path) and class name is known as the Canonical Name. For more information on packages, please visit my article on this very topic.
Going back to the original point, defining a namespace means that classes inside a package have a specific definition that is different than classes with similar name elsewhere. Suppose you have two table classes:package1.Table
and package2.Table
. Even if these classes do the exact same work, you have to assume they are different from one another for the simple fact that they are defined in different packages. Therefore, instances of one "Table" class are not necessarily compatible with instances of the other "Table" class. More about this "conflict" on the Importing Classes section.
Another benefit of packages, is that serves as a way to encapsulate features of a program or library. For example, there might be classes inside a package that may not be suitable for direct access by external entities. Thefore, declaring these classes with default access modification (see Part I of this series for a refresher) "hides" these classes from the outside. This information hiding helps in keeping your API simpler, by only making visible those classes suitable for external access.
Importing classes
Importing classes mean that you want to bring in (use) functionality that exist in another namespace without having to use the canonical name of a class (or fully qualified name). Obviously, if two classes share the same name that are used in a single class file, you have no choice but to resolve at least one with its fully qualified name. In the previous example of "Table" classes in two different packages:
package package3;
import package1.Table;
public class MyApp {
public static void main (String[] args) {
Table t1 = new Table();
package2.Table t2 = new package2.Table();
}
}
When you import, it is considered a good practice to import only the classes you need from any given package. However, Java supports the use of the asterisk symbol (*) to import all classes inside the named package. It will not import classes in subpackages. In the example above, you cannot import two classes with the same name, even if they are defined in different packages. On the surface, this might not make sense to you. But, if you really think about it, this is necessary because you won't be able to differentiate in the body of a class one type of object from the other. Consider this example:
package package3;
import package1.Table;
import package2.Table; // This import will cause a compiling error
public class MyApp {
public static void main (String[] args) {
Table t1 = new Table();
Table t2 = new Table();
}
}
t1
and t2
? If you think you can get around this issue by using import all wildcard on one of the import statements, the code will assume that you want to use the class type that is explicitly declared. If you use the wildcard on both import statements, both t1
and t2
declarations will result in a compiling error until one is explicitly imported and the other one declared with its fully qualified name, just like in the orgininal code snippet.
You may be asking yourself "when do I need to "import"? You need to import classes when they reside outside the declaring class (namespace) package.
Notice on the image above how the IDE is indicating an error with the use of the "MyClass" class. This is because "MyClass" and "MyOtherClass" exist in two different packages. Therefore, if not using "MyOtherClass" fully qualified (canonical) name, I must include an import statement to use it.
/*
* Programming Corner
* Professor Fontanez
* www.professorfontanez.com
* May 9, 2020: 10:58:09 AM
*/
package package1.subpackage;
import package1.*; // import all classes in package1 (assume MyClass resides in that package)
public class MyOtherClass {
public MyClass myAttrib;
}
Next up, Part XIV: Using instanceof Operator
Comments
Post a Comment