[1.4] Import other Java packages to make them accessible in your code
This exam covers importing packages into other classes. But with more than a decade and a half of experience, I’ve learned that before starting to import other packages into your own code, it’s important to understand what packages are, the difference between classes that are defined in a package and the classes that aren’t defined in a package, and why you need to import packages in your code.
In this section, you’ll learn what Java packages are and how to create them. You’ll use the import statement, which enables you to use simple names for classes and interfaces defined in separate packages.
Why do you think we need packages? First, answer this question: do you remember having known more than one Amit, Paul, Anu, or John in your life? Harry knows more than one Paul (six, to be precise), whom he categorizes as managers, friends, and cousins. These are subcategorized by their location and relation, as shown in figure 1.10.
Similarly, you can use a package to group together a related set of classes and interfaces (I won’t discuss enums here because they aren’t covered on this exam). Packages also provide access protection and namespace management. You can create separate packages to define classes for separate projects, such as Android games and online healthcare systems. Further, you can create subpackages within these packages, such as separate subpackages for GUIs, database access, networking, and so on.
In real-life projects, you’ll rarely work with a package-less class or interface. Almost all organizations that develop software have strict package-naming rules, which are often documented.
All classes and interfaces are defined in a package. If you don’t include an explicit package statement in a class or an interface, it’s part of a default package.
You can indicate that a class or an interface is defined in a package by using the package statement as the first statement in code. Here’s an example:
The class in the preceding code defines an ExamQuestion class in the certification package. You can define an interface, MultipleChoice, in a similar manner:
package certification; interface MultipleChoice { void choice1(); void choice2(); }
Figure 1.11 shows a UML class diagram depicting the relationship of the package certification to the class ExamQuestion and the interface MultipleChoice.
The name of the package in the previous examples is certification. You may use such names for small projects that contain only a few classes and interfaces, but it’s common for organizations to use subpackages to define all their classes. For example, if the folks at Oracle were to define a class to store exam questions for a Java Associate exam, they might use the package name com.oracle.javacert.associate. Figure 1.12 shows its UML representation, together with the corresponding class definition.
A package is made of multiple sections that go from the more-generic (left) to the more-specific (right). The package name com.oracle.javacert.associate follows a package-naming convention recommended by Oracle and shown in table 1.2.
Package or subpackage name |
Its meaning |
---|---|
com |
Commercial. A couple of the commonly used three-letter package abbreviations are
|
oracle | Name of the organization |
javacert | Further categorization of the project at Oracle |
associate | Further subcategorization of Java certification |
Here are a few of important rules about packages:
A fully qualified name for a class or interface is formed by prefixing its package name with its name (separated by a dot). The fully qualified name of the class ExamQuestion is certification.ExamQuestion in figure 1.11 and com.oracle.javacert.associate.ExamQuestion in figure 1.12.
The hierarchy of classes and interfaces defined in packages must match the hierarchy of the directories in which these classes and interfaces are defined in the code. For example, the class ExamQuestion in the certification package should be defined in a directory with the name “certification.” The name of the directory “certification” and its location are governed by the rules shown in figure 1.13.
For the package example shown in figure 1.13, note that there isn’t any constraint on the location of the base directory in which the directory structure is defined, as shown in figure 1.14.
To enable the Java Runtime Environment (JRE) to find your classes, add the base directory that contains your packaged Java code to the classpath.
For example, to enable the JRE to locate the certification.ExamQuestion class from the previous examples, add the directory C:MyCode to the classpath. To enable the JRE to locate the class com.oracle.javacert.associate.ExamQuestion, add the directory C:ProjectCode to the classpath.
You needn’t bother setting the classpath if you’re working with an IDE. But I strongly encourage you to learn how to work with a simple text editor and how to set a classpath. This can be helpful with your projects at work. The exam expects you to spot code with compilation errors, which isn’t easy to do if you didn’t learn how to do it without an IDE (IDEs usually include code autocorrection or autocompletion features).
The import statement enables you to use simple names instead of using fully qualified names for classes and interfaces defined in separate packages.
Let’s work with a real-life example. Imagine your home and your office. LivingRoom and Kitchen within your home can refer to each other without mentioning that they exist within the same home. Similarly, in an office, a Cubicle and a ConferenceHall can reference each other without explicitly mentioning that they exist within the same office. But Home and Office can’t access each other’s rooms or cubicles without stating that they exist in a separate home or office. This situation is represented in figure 1.15.
To refer to the LivingRoom in Cubicle, you must specify its complete location, as shown in the left part of the figure 1.16. As you can see in this figure, repeated references to the location of LivingRoom make the description of LivingRoom look tedious and redundant. To avoid this, you can display a notice in Cubicle that all occurrences of LivingRoom refer to LivingRoom in Home and thereafter use its simple name. Home and Office are like Java packages, and this notice is the equivalent of the import statement. Figure 1.16 shows the difference in using fully qualified names and simple names for LivingRoom in Cubicle.
Let’s implement the preceding example in code, where classes LivingRoom and Kitchen are defined in the package home and classes Cubicle and ConferenceHall are defined in the package office. Class Cubicle uses (is associated to) class LivingRoom in the package home, as shown in figure 1.17.
Class Cubicle can refer to class LivingRoom without using an import statement:
Class Cubicle can use the simple name for class LivingRoom by using the import statement:
The import statement doesn’t embed the contents of the imported class in your class, which means that importing more classes doesn’t increase the size of your own class.
It’s possible to use a packaged class or interface without using the import statement, by using its fully qualified name:
But using a fully qualified class name can clutter your code if you create multiple variables of interfaces and classes defined in other packages. Don’t use this approach in real projects.
You don’t need an explicit import statement to use members from the java.lang package. Classes and interfaces in this package are automatically imported in all other Java classes, interfaces, or enums.
For the exam, it’s important to note that you can’t use the import statement to access multiple classes or interfaces with the same names from different packages. For example, the Java API defines class Date in two commonly used packages: java.util and java.sql. To define variables of these classes in a class, use their fully qualified names with the variable declaration:
An attempt to use an import statement to import both these classes in the same class will not compile:
An alternate approach (which works well in real projects) is to use the import definition with the class or interface that you use more often and fully reference the one that you use just from time to time:
You can import either a single member or all members (classes and interfaces) of a package using the import statement. First, revisit the UML notation of the certification package, as shown in figure 1.18.
Examine the following code for the class AnnualExam:
By using the wildcard character, an asterisk (*), you can import all the public members, classes, and interfaces of a package. Compare the previous class definition with the following definition of the class AnnualExam:
When overused, using an asterisk to import all members of a package has a drawback. It may be harder to figure out which imported class or interface comes from which package.
When you work with an IDE, it may automatically add import statements for classes and interfaces that you reference in your code.
You can’t import classes from a subpackage by using an asterisk in the import statement. For example, the UML notation in figure 1.19 depicts the package com.oracle.javacert with the class Schedule and two subpackages, associate and webdeveloper. Package associate contains class ExamQuestion, and package webdeveloper contains class MarkSheet.
The following import statement will import only the class Schedule. It won’t import the classes ExamQuestion and MarkSheet:
Similarly, the following import statement will import all the classes from the packages associate and webdeveloper:
What happens if you don’t include a package statement in your classes or interfaces? In that case, they become part of a default, no-name package. This default package is automatically imported in the Java classes and interfaces defined within the same directory on your system.
For example, the classes Person and Office, which aren’t defined in an explicit package, can use each other if they’re defined in the same directory:
A class from a default package can’t be used in any named packaged class, regardless of whether they’re defined within the same directory or not.
Members of a named package can’t access classes and interfaces defined in the default package.
You can import an individual static member of a class or all its static members by using the import static statement. Although accessible using an instance, the static members are better accessed by prefixing their name with the class or interface names. By using static import, you can drop the prefix and just use the name of the static variable or method. In the following code, class ExamQuestion defines a public static variable marks and a public static method print:
The marks variable can be accessed in the class AnnualExam using the import static statement. The order of the keywords import and static can’t be reversed:
This feature is called static imports, but the syntax is import static.
To access all public and static members of class ExamQuestion in class AnnualExam without importing each of them individually, you can use an asterisk with the import static statement:
Because the variable marks and method print are defined as public members, they’re accessible to the class AnnualExam. By using the import static statement, you don’t have to prefix them with their class name.
On real projects, avoid overusing static imports; otherwise, the code might become a bit confusing about which imported component comes from which class.
The accessibility of a class, an interface, and their methods and variables is determined by their access modifiers, which are covered in the next section.
3.133.128.145