When building a software system, we can encapsulate things on several levels:
A project contains
packages, which contain
classes, which contain
methods and fields.
Note: the notion of a "project" is specific to Eclipse, but the rest are Java terms (also used by other object-oriented languages).
This would have been overkill heretofore, but as we begin to build systems with more and more classes, packages help us keep them organized.
Package names in Java are normally all lower case, run together, with no underscores. Each package corresponds to a directory (folder). For complex systems, these folders may be nested, giving rise to package names with dots in them. For example, suppose we were building a science fiction game called Space Disagreement!. We might have packages spacedisagreement.graphics, spacedisagreement.physics, spacedisagreement.ai, and so on.
When a company or other organization develops a package to be distributed elsewhere, it will often follow the convention that the organization's internet domain is included in the package name. Since more specific things should appear farther to the right in a long package name, the domain is put at the left and in reverse order. Thus, if Space Disagreement! were developed here, we might have package names like edu.lclark.spacedisagreement.graphics.
Two things must happen if a class is to be in a package. It must be located in the right folder and it must have a statement like
package edu.lclark.spacedisagreement.graphics;
as the first line, before any imports and before the class definition starts.
Within a package, we can safely pretend to live in a world where only that package exists. If we ever need a class from another package, we can either import it or use its full name. For example, if we want to use the ArrayList class in the java.util package, we can either refer to it by its full name (java.util.ArrayList) or import it and refer to it by its simple name ArrayList.
Packages relieve us of the burden of coming up with new names. If we have a package social and a package fruit, we might have a class Date in each one. Within the social package, Date means social.Date; within the fruit package, Date means fruit.Date.
Classes placed at the top of the source code directory tree (in Eclipse, under src) are in the nameless default package. This is fine for very small programs; in fact, the textbook largely ignores packages. Once we start using packages, it is best to avoid using the default package. Using the default package would be like organizing all of your files into folders, but leaving some of them on the desktop.
The classes in the built-in package java.lang, such as String and Math, can be used without importing. This is why we can call Math.sqrt() without importing java.lang.Math or using the full name java.lang.Math.sqrt().
It's important to understand the difference between regular imports and static imports. When we say
import java.util.ArrayList;
we are telling Java, "If I refer to ArrayList, I mean the version from the java.util package."
When we say
import static java.lang.Math.sqrt;
we are telling Java, "If I refer to (the static method) sqrt, I mean the version from the Math class in the java.lang package."
So: regular imports get you classes, while static imports get you methods and fields.
A Java import is not the same thing as a C #include. The former merely tells the system where to find things, while the latter effectively pastes the code from the other file in place of the #include statement.
A * can be used to import every class in a package or every static method and field in a class. If we plan to use a lot of mathematical functions, we might:
import static java.lang.Math.*;
This does not work for importing nested packages, so
import java.*;
does not import all of the classes in java.util. (It would import any classes placed directly in the java package folder.)
It is not possible to import from the default package.
Every Java method or field has a visibility level, also called an access level. This controls who can see that method or field. There are four levels:
The package level is in parentheses because there is no keyword for this; it is the default if no other level is specified.
"Descendants" means subclasses (classes that extend this one), subclasses of subclasses, and so on.
Fields should generally be private. Constants (static final fields) are an exception; they can be public.
Methods should generally be public or protected. Private or package methods should usually be avoided because they cannot be seen by descendants.
UML is the Unified Modeling Language. One part of UML is the specification for class diagrams, which show the relationships between classes.
In the simplest type of UML class diagram, each class is represented as a rectangle labeled with the name of the class. These are connected by arrows.
A wire-headed arrow indicates a "has-a" relationship. In the diagram below, a Car has-a Wheel. In the code, this means that the Car class will have a field of type Wheel (or, more likely, Wheel[]).
A hollow-headed arrow indicates an "is-a" relationship. In the diagram below, a Velociraptor is-a Dinosar. In code, the definition of Velociraptor will begin public class Velociraptor extends Dinosaur { ... }.
A second kind of "is-a" relationship occurs when a class implements an interface. Suppose the interface Appliance specifies that a class has a turnOn() method. The class WashingMachine implements this interface (beginning with public class WashingMachine implements Appliance { ... }). This relationship is shown below, using a hollow-headed arrow on a dashed line.
(The arrowhead itself should not be dashed; that's due to a bug in the drawing program I'm using.)
Packages are shown in UML as file folders containing their classes.
The quiz refers to the following UML diagram.