Chapter 6. Packages, Interfaces, and Other Class Features

Classes, the templates used to create objects that can store data and accomplish tasks, turn up in everything you do with the Java language.

Today, you extend your knowledge of classes by learning more about how to create them, use them, organize them, and establish rules for how other classes can use them.

The following subjects are covered:

  • Controlling access to methods and variables from outside a class

  • Finalizing classes, methods, and variables so that their values or definitions cannot be subclasses or cannot be overridden

  • Creating abstract classes and methods for factoring common behavior into superclasses

  • Grouping classes into packages

  • Using interfaces to bridge gaps in a class hierarchy

Modifiers

During this week, you have learned how to define classes, methods, and variables in Java. The techniques for programming that you learn today involve different ways of thinking about how a class is organized. All these techniques use special modifier keywords in the Java language.

Modifiers are keywords that you add to those definitions to change their meanings.

The Java language has a wide variety of modifiers, including the following:

  • Modifiers for controlling access to a class, method, or variable: public, protected, and private

  • The static modifier for creating class methods and variables

  • The final modifier for finalizing the implementations of classes, methods, and variables

  • The abstract modifier for creating abstract classes and methods

  • The synchronized and volatile modifiers, which are used for threads

To use a modifier, you include its keyword in the definition of a class, method, or variable. The modifier precedes the rest of the statement, as in the following examples:

public class Calc extends javax.swing.JApplet {
    // ...
}

private boolean offline;

static final double weeks = 9.5;

protected static final int MEANING_OF_LIFE = 42;

public static void main(String[] arguments) {
    // body of method
}

If you’re using more than one modifier in a statement, you can place them in any order, as long as all modifiers precede the element they are modifying. Make sure to avoid treating a method’s return type—such as void—as if it were one of the modifiers.

Modifiers are optional—as you might realize after using few of them in the preceding five days. There are many good reasons to use them, though, as you see today.

Access Control for Methods and Variables

The modifiers that you will use the most often control access to methods and variables: public, private, and protected. These modifiers determine which variables and methods of a class are visible to other classes.

By using access control, you can dictate how your class is used by other classes. Some variables and methods in a class are of use only within the class itself and should be hidden from other classes. This process is called encapsulation: An object controls what the outside world can know about it and how the outside world can interact with it.

Encapsulation is the process that prevents class variables from being read or modified by other classes. The only way to use these variables is by calling methods of the class, if they are available.

The Java language provides four levels of access control: public, private, protected, and a default level specified by using none of these access control modifiers.

Default Access

Variables and methods can be declared without any modifiers, as in the following examples:

String version = "0.7a";

boolean processOrder() {
    return true;
}

A variable or method declared without any access control modifier is available to any other class in the same package. The Java class library is organized into packages such as javax.swing, which are windowing classes for use primarily in graphical user interface programming, and java.util, a useful group of utility classes.

Any variable declared without a modifier can be read or changed by any other class in the same package. Any method declared the same way can be called by any other class in the same package. No other classes can access these elements in any way.

This level of access control doesn’t control much access, so it’s less useful when you begin thinking about how you want a class to be used by other classes.

Note

The preceding discussion raises the question about what package your own classes have been in up to this point. As you see later today, you can make your class a member of a package by using the package declaration. If you don’t use this approach, the class is put into an unnamed package with all other classes that don’t belong to any other packages.

Private Access

To completely hide a method or variable from being used by any other classes, use the private modifier. The only place these methods or variables can be accessed is from within their own class.

A private instance variable, for example, can be used by methods in its own class but not by objects of any other class. Private methods can be called by other methods in their own class but cannot be called by any others. This restriction also affects inheritance: Neither private variables nor private methods are inherited by subclasses.

Private variables are useful in two circumstances:

  • When other classes have no reason to use that variable

  • When another class could wreak havoc by changing the variable in an inappropriate way

For example, consider a Java class called CouponMachine that generates discounts for an Internet shopping site. A variable in that class called salesRatio could control the size of discounts based on product sales. As you can imagine, this variable has a big impact on the bottom line at the site. If the variable were changed by other classes, the performance of CouponMachine would change greatly. To guard against this scenario, you can declare the salesRatio variable as private.

The following class uses private access control:

class Logger {
    private String format;

    public String getFormat() {
        return this.format;
    }

    public void setFormat(String format) {
        if ( (format.equals("common")) ! (format.equals("combined")) ) {
            this.format = format;
        }
    }
}

In this code example, the format variable of the Logger class is private, so there’s no way for other classes to retrieve or set its value directly.

Instead, it’s available through two public methods: getFormat(), which returns the value of format, and setFormat(String), which sets its value.

The latter method contains logic that only allows the variable to be set to “common” or “combined.” This demonstrates the benefit of using public methods as the only means of accessing instance variables of a class—the methods can give the class control over how the variable is accessed and the values it can take.

Using the private modifier is the main way that an object encapsulates itself. You can’t limit the ways in which a class is used without using private in many places to hide variables and methods. Another class is free to change the variables inside a class and call its methods in many possible ways if you don’t control access.

A big advantage of privacy is that it gives you a way to change the implementation of a class without affecting the users of that class. If you come up with a better way to accomplish something, you can rewrite the class as long as its public methods take the same arguments and return the same kinds of values.

Public Access

In some cases, you might want a method or variable in a class to be completely available to any other class that wants to use it. For example, the Color class in the java.awt package has public variables for common colors such as black. This variable is used when a graphical class wants to use the color black, so black should have no access control at all.

Class variables often are declared to be public. An example would be a set of variables in a Football class that represent the number of points used in scoring. The TOUCHDOWN variable could equal 6, the FIELD_GOAL variable could equal 3, and so on. If these variables are public, other classes could use them in statements such as the following:

if (yard < 0) {
    System.out.println("Touchdown!");
    score = score + Football.TOUCHDOWN;
}

The public modifier makes a method or variable completely available to all classes. You have used it in every application you have written so far, with a statement such as the following:

public static void main(String[] arguments) {
    // ...
}

The main() method of an application has to be public. Otherwise, it could not be called by a Java interpreter (such as java) to run the class.

Because of class inheritance, all public methods and variables of a class are inherited by its subclasses.

Protected Access

The third level of access control is to limit a method and variable to use by the following two groups:

  • Subclasses of a class

  • Other classes in the same package

You do so by using the protected modifier, as in the following statement:

protected boolean outOfData = true;

Note

You might be wondering how these two groups are different. After all, aren’t subclasses part of the same package as their superclass? Not always. An example is the JApplet class. It is a subclass of java.applet.Applet but is actually in the javax.swing package. Protected access differs from default access this way; protected variables are available to subclasses, even if they aren’t in the same package.

This level of access control is useful if you want to make it easier for a subclass to implement itself. Your class might use a method or variable to help the class do its job. Because a subclass inherits much of the same behavior and attributes, it might have the same job to do. Protected access gives the subclass a chance to use the helper method or variable, while preventing a nonrelated class from trying to use it.

Consider the example of a class called AudioPlayer that plays a digital audio file. AudioPlayer has a method called openSpeaker(), which is an internal method that interacts with the hardware to prepare the speaker for playing. openSpeaker() isn’t important to anyone outside the AudioPlayer class, so at first glance you might want to make it private. A snippet of AudioPlayer might look something like this:

class AudioPlayer {

    private boolean openSpeaker(Speaker sp) {
        // implementation details
    }
}

This code works fine if AudioPlayer isn’t going to be subclassed. But what if you were going to create a class called StreamingAudioPlayer that is a subclass of AudioPlayer? That class needs access to the openSpeaker() method to override it and provide support for streaming audio devices. You still don’t want the method generally available to random objects (and so it shouldn’t be public), but you want the subclass to have access to it.

Comparing Levels of Access Control

The differences among the various protection types can become confusing, particularly in the case of protected methods and variables. Table 6.1, which summarizes exactly what is allowed where, helps clarify the differences from the least restrictive (public) to the most restrictive (private) forms of protection.

Table 6.1. The Different Levels of Access Control

Visibility

public

protected

default

private

From the same class

yes

yes

yes

yes

From any class in the same package

yes

yes

yes

no

From any class outside the package

yes

no

no

no

From a subclass in the same package

yes

yes

yes

no

From a subclass outside the same package

yes

yes

no

no

Access Control and Inheritance

One last issue regarding access control for methods involves subclasses. When you create a subclass and override a method, you must consider the access control in place on the original method.

As a general rule, you cannot override a method in Java and make the new method more restrictively controlled than the original. You can, however, make it more public. The following rules for inherited methods are enforced:

  • Methods declared public in a superclass also must be public in all subclasses.

  • Methods declared protected in a superclass must either be protected or public in subclasses; they cannot be private.

  • Methods declared without access control (no modifier was used) can be declared more private in subclasses.

Methods declared private are not inherited at all, so the rules don’t apply.

Accessor Methods

In many cases, you may have an instance variable in a class that has strict rules for the values it can contain. An example would be a zipCode variable. A ZIP Code in the United States must be a number that is five digits long.

To prevent an external class from setting the zipCode variable incorrectly, you can declare it private with a statement such as the following:

private int zipCode;

However, what if other classes must be able to set the zipCode variable for the class to be useful? In that circumstance, you can give other classes access to a private variable by using an accessor method inside the same class as zipCode.

An accessor method provides access to a variable that otherwise would be off-limits. By using a method to provide access to a private variable, you can control how that variable is used. In the ZIP Code example, the class could prevent anyone else from setting zipCode to an incorrect value.

Often, separate accessor methods to read and write a variable are available. Reading methods have a name beginning with get, and writing methods have a name beginning with set, as in setZipCode(int) and getZipCode().

Using methods to access instance variables is a frequently used technique in object-oriented programming. This approach makes classes more reusable because it guards against a class being used improperly.

Note

The Java class library makes extensive use of accessor methods that follow the same format as the getZipCode() and setZipCode(int) examples in this section. JavaBeans, a technology for creating Java objects whose variables can be manipulated in an integrated development environment, also employs them.

Static Variables and Methods

A modifier that you already have used in programs is static, which was introduced during Day 5, “Creating Classes and Methods.” The static modifier is used to create class methods and variables, as in the following example:

public class Circle {
    public static float PI = 3.14159265F;

    public float area(float r) {
        return PI * r * r;
    }
}

Class variables and methods can be accessed using the class name followed by a dot and the name of the variable or method, as in Color.black or Circle.PI. You also can use the name of an object of the class, but for class variables and methods, using the class name is better. This approach makes clearer what kind of variable or method you’re working with; instance variables and methods can never be referred to by a class name.

The following statements use class variables and methods:

float circumference = 2 * Circle.PI * getRadius();
float randomNumber = Math.random();

Tip

For the same reason as instance variables, class variables can benefit from being private and limiting their use to accessor methods only.

The first project you undertake today is a class called InstanceCounter that uses class and instance variables to keep track of how many instances of that class have been created. It’s shown in Listing 6.1.

Example 6.1. The Full Text of InstanceCounter.java

 1: public class InstanceCounter {
 2:     private static int numInstances = 0;
 3:
 4:     protected static int getCount() {
 5:         return numInstances;
 6:      }
 7:
 8:      private static void addInstance() {
 9:          numInstances++;
10:      }
11:
12:      InstanceCounter() {
13:          InstanceCounter.addInstance();
14:      }
15:
16:      public static void main(String[] arguments) {
17:          System.out.println("Starting with " +
18:              InstanceCounter.getCount() + " instances");
19:          for (int  i = 0; i < 500; ++i)
20:              new InstanceCounter();
21:          System.out.println("Created " +
22:              InstanceCounter.getCount() + " instances");
23:      }
24: }

The output of this program is as follows:

Started with 0 instances
Created 500 instances

This example demonstrates several features. In line 2, a private class variable is declared to hold the number of instances. It is a class variable (declared static) because the number of instances is relevant to the class as a whole, not to any particular instance, and it’s private so that it can be retrieved only with an accessor method.

Note the initialization of numInstances. Just as an instance variable is initialized when its instance is created, a class variable is initialized when its class is created. This class initialization happens essentially before anything else can happen to that class, or its instances, so that the class in the example will work as planned.

In lines 4–6, a get method is defined so that the private instance variable’s value can be retrieved. This method also is declared as a class method because it applies directly to the class variable. The getCount() method is declared protected, as opposed to public, because only this class and perhaps its subclasses are interested in that value; other random classes are, therefore, restricted from seeing it.

Note that there is no accessor method to set the value. The value of the variable should be incremented only when a new instance is created; it should not be set to any random value. Instead of creating an accessor method, a special private method called addInstance() is defined in lines 8–10 that increments the value of numInstances by 1.

Lines 12–14 create the constructor method for this class. Constructors are called when a new object is created, which makes this the most logical place to call addInstance() and to increment the variable.

The main() method indicates that you can run this as a Java application and test all the other methods. In the main() method, 500 instances of the InstanceCounter class are created and then the value of the numInstances class variable is displayed.

Final Classes, Methods, and Variables

The final modifier is used with classes, methods, and variables to indicate that they will not be changed. It has different meanings for each thing that can be made final, as follows:

  • A final class cannot be subclassed.

  • A final method cannot be overridden by any subclasses.

  • A final variable cannot change in value.

Variables

Final variables are often called constant variables (or just constants) because they do not change in value at any time.

With variables, the final modifier often is used with static to make the constant a class variable. If the value never changes, you don’t have much reason to give each object in the same class its own copy of the value. They all can use the class variable with the same functionality.

The following statements are examples of declaring constants:

public static final int TOUCHDOWN = 6;
static final String TITLE = "Captain";

Methods

Final methods are those that can never be overridden by a subclass. You declare them using the final modifier in the class declaration, as in the following example:

public final void getSignature() {
    // body of method
}

The most common reason to declare a method final is to make the class run more efficiently. Normally, when a Java runtime environment such as the java interpreter runs a method, it checks the current class to find the method first, checks its superclass second, and onward up the class hierarchy until the method is found. This process sacrifices some speed in the name of flexibility and ease of development.

If a method is final, the Java compiler can put the executable bytecode of the method directly into any program that calls the method. After all, the method won’t ever change because of a subclass that overrides it.

When you are first developing a class, you won’t have much reason to use final. However, if you need to make the class execute more quickly, you can change a few methods into final methods to speed up the process. Doing so removes the possibility of the method being overridden in a subclass later on, so consider this change carefully before continuing.

The Java class library declares many of the commonly used methods final so that they can be executed more quickly when utilized in programs that call them.

Note

Private methods are final without being declared that way because they can’t be overridden in a subclass under any circumstance.

Classes

You finalize classes by using the final modifier in the declaration for the class, as in the following:

public final class ChatServer {
    // body of method
}

A final class cannot be subclassed by another class. As with final methods, this process introduces some speed benefits to the Java language at the expense of flexibility.

If you’re wondering what you’re losing by using final classes, you must not have tried to subclass something in the Java class library yet. Many of the popular classes are final, such as java.lang.String, java.lang.Math, and java.net.URL. If you want to create a class that behaves like strings but with some new changes, you can’t subclass String and define only the behavior that is different. You have to start from scratch.

All methods in a final class automatically are final themselves, so you don’t have to use a modifier in their declarations.

Because classes that can provide behavior and attributes to subclasses are much more useful, you should strongly consider whether the benefit of using final on one of your classes is outweighed by the cost.

Abstract Classes and Methods

In a class hierarchy, the higher the class, the more abstract its definition. A class at the top of a hierarchy of other classes can define only the behavior and attributes common to all the classes. More specific behavior and attributes are going to fall somewhere lower down the hierarchy.

When you are factoring out common behavior and attributes during the process of defining a hierarchy of classes, you might at times find yourself with a class that doesn’t ever need to be instantiated directly. Instead, such a class serves as a place to hold common behavior and attributes shared by their subclasses.

These classes are called abstract classes, and they are created using the abstract modifier. The following is an example:

public abstract class Palette {
    // ...
}

An example of an abstract class is java.awt.Component, the superclass of graphical user interface components. Because numerous components inherit from this class, it contains methods and variables useful to each of them. However, there’s no such thing as a generic component that can be added to a user interface, so you would never need to create a Component object in a program.

Abstract classes can contain anything a normal class can, including constructor methods, because their subclasses might need to inherit the methods. Abstract classes also can contain abstract methods, which are method signatures with no implementation. These methods are implemented in subclasses of the abstract class. Abstract methods are declared with the abstract modifier. You cannot declare an abstract method in a class that isn’t itself abstract. If an abstract class has nothing but abstract methods, you’re better off using an interface, as you see later today.

Packages

Using packages, as mentioned previously, is a way of organizing groups of classes. A package contains any number of classes that are related in purpose, in scope, or by inheritance.

If your programs are small and use a limited number of classes, you might find that you don’t need to explore packages at all. But as you begin creating more sophisticated projects with many classes related to each other by inheritance, you might discover the benefit of organizing them into packages.

Packages are useful for several broad reasons:

  • They enable you to organize your classes into units. Just as you have folders or directories on your hard disk to organize your files and applications, packages enable you to organize your classes into groups so that you use only what you need for each program.

  • They reduce problems with conflicts about names. As the number of Java classes grows, so does the likelihood that you’ll use the same class name as another developer, opening up the possibility of naming clashes and error messages if you try to integrate groups of classes into a single program. Packages provide a way to refer specifically to the desired class, even if it shares a name with a class in another package.

  • They enable you to protect classes, variables, and methods in larger ways than on a class-by-class basis, as you learned today. You learn more about protections with packages later.

  • Packages can be used to uniquely identify your work.

Using Packages

You’ve been using packages all along in this book. Every time you use the import command, and every time you refer to a class by its full package name (java.util.StringTokenizer, for example), you are using packages.

To use a class contained in a package, you can use one of three techniques:

  • If the class you want to use is in the package java.lang (for example, System or Date), you can simply use the class name to refer to that class. The java.lang classes are automatically available to you in all your programs.

  • If the class you want to use is in some other package, you can refer to that class by its full name, including any package names (for example, java.awt.Font).

  • For classes that you use frequently from other packages, you can import individual classes or a whole package of classes. After a class or a package has been imported, you can refer to that class by its class name.

If you don’t declare that your class belongs to a package, it is put into an unnamed default package. You can refer to that class and any other unpackaged class simply by its class name from anywhere in other classes.

Full Package and Class Names

To refer to a class in another package, use its full name: the class name preceded by its package. You do not have to import the class or the package to use it in this manner, as in this example:

java.awt.Font text = new java.awt.Font()

For classes that you use only once or twice in your program, using the full name makes sense. If you use a class multiple times, you can import the class to save yourself some typing.

When you begin creating your own packages, you’ll place all files in a package in the same folder. Each element of a package name corresponds to its own subfolder.

Consider the example of a BookShipper class that is part of the org.cadenhead.library package.

The following line should be the first statement in the source code of the class, which declares the name of the package to which it belongs:

package org.cadenhead.library;

After you compile the BookShipper class, you must store it in a folder that corresponds with the package name. The JDK and other Java tools will look for the org.cadenhead.library.BookShipper.class file in several different places:

  • The orgcadenheadlibrary subfolder of the folder where the java command was entered. (For example, if the command was made from the C:J21work folder, the BookShipper.class file could be run successfully if it was in the C:J21workorgcadenheadlibrary folder.)

  • The orgcadenheadlibrary subfolder of any folder in your Classpath setting.

  • The orgcadenheadlibrary subfolder of a Java archive file (JAR) in your Classpath.

One way to manage your own packages and any others you use is to add a folder to your Classpath that serves as the root folder for any packages you create or adopt, such as C:javapackages or something similar. After creating subfolders that correspond to the name of a package, place the package’s class files in the correct subfolder.

The import Declaration

To import classes from a package, use the import declaration as you have throughout the examples in the first week. You can import an individual class, as in this statement:

import java.util.Vector;

You also can import an entire package of classes using an asterisk (*) in place of an individual class name, like this:

import java.awt.*;

The asterisk can be used in place of a class name only in an import statement. It does not make it possible to import multiple packages with similar names.

For example, the Java class library includes the java.util, java.util.jar, and java.util.prefs packages. You could not import all three packages with the following statement:

import java.util.*;

This merely imports the java.util package. To make all three available in a class, the following statements are required:

import java.util.*;
import java.util.jar.*;
import java.util.prefs.*;

Also, you cannot indicate partial class names (for example, L* to import all the classes that begin with L). Your only options when using an import declaration are to load all the classes in a package or just a single class.

The import declarations in your class definition go at the top of the file before any class definitions (but after the package declaration, as you see in the next section).

Using individual import declarations or importing packages is mostly a question of your own coding style. Importing a group of classes does not slow down your program or make it any larger; only the classes that you actually use in your code are loaded as they are needed. Importing specific classes makes it easier for readers of your code to figure out where your classes are coming from.

Note

If you’re familiar with C or C++, you might expect the import declaration to work like #include and possibly result in a large executable program because it includes source code from another file. This isn’t the case in Java: import indicates only where the Java compiler can find a class. It doesn’t do anything to expand the size of a compiled class.

The import statement also. can be used to refer to constants in a class by name.

Normally, class constants must be prefaced with the name of the class as in Color.black, Math.PI, and File.separator.

An import static statement makes the constants in an identified class available in shorter form. The keywords import static are followed by the name of an interface or class and an asterisk. For example:

import static java.lang.Math.*;

This statement makes it possible to refer to the constants in the Math class, E and PI, using only their names. Here’s a short example of a class that takes advantage of this feature:

import static java.lang.Math.*;

public class ShortConstants {
    public static void main(String[] arguments) {
        System.out.println("PI: " + PI);
        System.out.println("" + (PI * 3));
    }
}

Class Name Conflicts

After you have imported a class or a package of classes, you usually can refer to a class name simply by its name without the package identifier. There’s one situation where you must be more explicit: when you import two classes from different packages that have the same class name.

One situation where a naming conflict might occur is during database programming, which you undertake on Day 18, “Accessing Databases with JDBC.” This kind of programming can involve the java.util and java.sql packages, which both contain a class named Date.

If you’re working with both packages in a class that reads or writes data in a database, you could import them with these statements:

import java.sql.*;
import java.util.*;

When both these packages are imported, a compiler error occurs when you refer to the Date class without specifying a package name, as in this statement:

Date now = new Date();

The error occurs because the Java compiler has no way of knowing which Date class is being referred to in the statement. The package must be included in the statement, like this:

java.util.Date = new java.util.Date();

A Note About Classpath and Where Classes Are Located

For Java to be able to use a class, it must be able to find that class on the file system. Otherwise, you get an error message indicating that the class does not exist. Java uses two elements to find classes: the package name itself and the directories listed in your Classpath environmental variable (or in a Classpath specified when the class is compiled or run).

Package names map to folder names on a file system, so the class com.naviseek. Mapplet is found in the naviseek directory, which, in turn, is inside the com directory (in other words, com aviseekMapplet.class).

Java looks for a folder inside the folders and JAR files in your Classpath variable, if one is provided in your configuration. If you installed the JDK, you may have used it to indicate where the Java class library, a file called tools.jar, can be found. If no Classpath is provided, the JDK looks only in the current folder for classes.

When Java looks for a class that you’ve referenced in your program, it looks for the package and class name in each of those folders and returns an error message if it can’t find the class file. Most class not found error messages result because of misconfigured Classpath variables.

Note

For help setting your Classpath correctly with the JDK on a Windows or Linux system, read Appendix A, “Using the Java Development Kit.”

To specify the Classpath when compiling or running an application with the JDK, use the -classpath flag followed by a space and a list of folders separated by semicolons (on Windows) or colons (on Linux). For example:

javac -classpath /java/lib/tools.jar;/dev/java/root;. Editor.java

Creating Your Own Packages

Creating a package for some of your classes in Java is not much more complicated than creating a class.

Picking a Package Name

The first step is to decide on a name. The name you choose for your package depends on how you will use those classes. Perhaps you name your package after yourself or a part of the Java system you’re working on (such as graphics or messaging). If you intend to distribute your package as an open source or commercial product, use a package name that uniquely identifies its authorship.

Sun Microsystems recommends that Java developers use an Internet domain name as the basis for a unique package name.

To form the name, reverse the elements so that the last part of the domain becomes the first part of the package name, followed by the second-to-last part. Following this convention, because my personal domain name is cadenhead.org, all Java packages I create begin with the name org.cadenhead (for instance, org.cadenhead.rss).

This convention ensures that no other Java developer will offer a package with the same name, as long as they follow the same rule themselves (as most developers appear to be doing).

By another convention, package names use no capital letters, which distinguishes them from class names. For example, in the full name of the class java.lang.String, you can easily distinguish the package name java.lang from the class name String.

Creating the Folder Structure

Step two in creating packages is to create a folder structure that matches the package name, which requires a separate folder for each part of the name. The package org.cadenhead.rss requires an org folder, a cadenhead folder inside org, and an rss folder inside cadenhead. The classes in the package then are stored in the rss folder.

Adding a Class to a Package

The final step to putting a class inside a package is to add a statement to the class file above any import declarations that are being used. The package declaration is used along with the name of the package, as in the following:

package org.cadenhead.rss;

The package declaration must be the first line of code in your source file, after any comments or blank lines and before any import declarations.

Packages and Class Access Control

Earlier today, you learned about access control modifiers for methods and variables. You also can control access to classes.

Classes have the default access control if no modifier is specified, which means that the class is available to all other classes in the same package but is not visible or available outside that package. It cannot be imported or referred to by name; classes with package protection are hidden inside the package in which they are contained.

To allow a class to be visible and importable outside your package, you can give it public protection by adding the public modifier to its definition:

public class Visible {
    // ...
}

Classes declared as public can be accessed by other classes outside the package.

Note that when you use an import statement with an asterisk, you import only the public classes inside that package. Private classes remain hidden and can be used only by the other classes in that package.

Why would you want to hide a class inside a package? For the same reasons that you want to hide variables and methods inside a class: so that you can have utility classes and behavior that are useful only to your implementation or so that you can limit the interface of your program to minimize the effect of larger changes. As you design your classes, take the whole package into consideration and decide which classes you want to declare public and which you want to be hidden.

Creating a good package consists of defining a small, clean set of public classes and methods for other classes to use and then implementing them by using any number of hidden support classes. You see another use for private classes later today.

Interfaces

Interfaces, like abstract classes and methods, provide templates of behavior that other classes are expected to implement. They also offer significant advantages in class and object design that complements Java’s single inheritance approach to object-oriented programming.

The Problem of Single Inheritance

As you begin turning a project into a hierarchy of classes related by inheritance, you might discover that the simplicity of the class organization is restrictive, particularly when you have some behavior that needs to be used by classes that do not share a common superclass.

Other object-oriented programming (OOP) languages include the concept of multiple inheritance, which solves this problem by letting a class inherit from more than one superclass, acquiring behavior and attributes from all its superclasses at once.

This concept makes a programming language more challenging to learn and to use. Questions of method invocation and how the class hierarchy is organized become far more complicated with multiple inheritance and more open to confusion and ambiguity.

Because one of the goals for Java was that it be simple, multiple inheritance was rejected in favor of single inheritance.

A Java interface is a collection of abstract behavior that can be adopted by any class without being inherited from a superclass.

An interface contains nothing but abstract method definitions and constants—there are no instance variables or method implementations.

Interfaces are implemented and used throughout the Java class library when behavior is expected to be implemented by a number of disparate classes. Later today, you’ll use one of the interfaces in the Java class hierarchy, java.lang.Comparable.

Interfaces and Classes

Classes and interfaces, despite their different definitions, have a great deal in common. Both are declared in source files and compiled into .class files. In most cases, an interface can be used anywhere you can use a class (as a data type for a variable, as the result of a cast, and so on).

You can substitute an interface name for a class name in almost every example in this book. Java programmers often say “class” when they actually mean “class or interface.” Interfaces complement and extend the power of classes, and the two can be treated almost the same, but an interface cannot be instantiated: new only can create an instance of a nonabstract class.

Implementing and Using Interfaces

You can do two things with interfaces: Use them in your own classes and define your own. For now, start with using them in your own classes.

To use an interface, include the implements keyword as part of your class definition:

public class AnimatedSign extends javax.swing.JApplet
    implements Runnable {
    //...
}

In this example, javax.swing.JApplet is the superclass, but the Runnable interface extends the behavior that it implements.

Because interfaces provide nothing but abstract method definitions, you then have to implement those methods in your own classes using the same method signatures from the interface.

To implement an interface, you must offer all the methods in that interface—you can’t pick and choose the methods you need. By implementing an interface, you’re telling users of your class that you support the entire interface.

After your class implements an interface, subclasses of your class inherit those new methods and can override or overload them. If your class inherits from a superclass that implements a given interface, you don’t have to include the implements keyword in your own class definition.

Implementing Multiple Interfaces

Unlike with the singly inherited class hierarchy, you can include as many interfaces as you need in your own classes. Your class will implement the combined behavior of all the included interfaces. To include multiple interfaces in a class, just separate their names with commas:

public class AnimatedSign extends javax.swing.JApplet
    implements Runnable, Observable {

    // ...
}

Note that complications might arise from implementing multiple interfaces. What happens if two different interfaces both define the same method? You can solve this problem in three ways:

  • If the methods in each of the interfaces have identical signatures, you implement one method in your class, and that definition satisfies both interfaces.

  • If the methods have different argument lists, it is a simple case of method overloading; you implement both method signatures, and each definition satisfies its respective interface definition.

  • If the methods have the same argument lists but differ in return type, you cannot create a method that satisfies both. (Remember that method overloading is triggered by parameter lists, not by return type.) In this case, trying to compile a class that implements both interfaces produces a compiler error message. Running across this problem suggests that your interfaces have some design flaws that you might need to reexamine.

Other Uses of Interfaces

Remember that almost everywhere that you can use a class, you can use an interface instead. For example, you can declare a variable to be of an interface type:

Iterator loop = new Iterator()

When a variable is declared to be of an interface type, it simply means that the object is expected to have implemented that interface. In this case, because Iterator contains an object of the type Iterator, the assumption is that you can call all three of the interface’s methods on that object: hasNext(), next(), and remove().

The important point to realize here is that although Iterator is expected to have the three methods, you could write this code long before any classes that qualify are actually implemented.

You also can cast objects to an interface, just as you can cast objects to other classes.

Creating and Extending Interfaces

After you use interfaces for a while, the next step is to define your own interfaces. Interfaces look a lot like classes; they are declared in much the same way and can be arranged into a hierarchy. However, you must follow certain rules for declaring interfaces.

New Interfaces

To create a new interface, you declare it like this:

interface Expandable {
    // ...
}

This declaration is, effectively, the same as a class definition, with the word interface replacing the word class. Inside the interface definition, you have methods and variables.

The method definitions inside the interface are public and abstract methods; you can either declare them explicitly as such, or they will be turned into public and abstract methods if you do not include those modifiers. You cannot declare a method inside an interface to be either private or protected.

As an example, here’s an Expandable interface with one method explicitly declared public and abstract (expand()) and one implicitly declared as (contract()):

public interface Expandable {
    public abstract void expand(); // explicitly public and abstract
    void contract(); // effectively public and abstract
}

Note that as with abstract methods in classes, methods inside interfaces do not have bodies. An interface consists only of a method signature; no implementation is involved.

In addition to methods, interfaces also can have variables, but those variables must be declared public, static, and final (making them constant). As with methods, you can explicitly define a variable to be public, static, and final, or it is implicitly defined as such if you don’t use those modifiers. Here’s that same Expandable definition with two new variables:

public interface Expandable {
    public static final int increment = 10;
    long capacity = 15000; // becomes public static and final

    public abstract void expand(); //explicitly public and abstract
    void contract(); // effectively public and abstract
}

Interfaces must have either public or package protection, just like classes. Note, however, that interfaces without the public modifier do not automatically convert their methods to public and abstract nor their constants to public. A non-public interface also has non-public methods and constants that can be used only by classes and other interfaces in the same package.

Interfaces, like classes, can belong to a package. Interfaces also can import other interfaces and classes from other packages, just as classes can.

Methods Inside Interfaces

Here’s one trick to note about methods inside interfaces: Those methods are supposed to be abstract and apply to any kind of class, but how can you define arguments to those methods? You don’t know what class will be using them! The answer lies in the fact that you use an interface name anywhere a class name can be used, as you learned earlier. By defining your method arguments to be interface types, you can create generic arguments that apply to any class that might use this interface.

Consider the interface Trackable, which defines methods (with no arguments) for track() and quitTracking(). You might also have a method for beginTracking(), which has one argument: the trackable object itself.

What class should that argument be? It should be any object that implements the Trackable interface rather than a particular class and its subclasses. The solution is to declare the argument as simply Trackable in the interface:

public interface Trackable {
    public abstract Trackable beginTracking(Trackable self);
}

Then, in an actual implementation for this method in a class, you can take the generic Trackable argument and cast it to the appropriate object:

public class Monitor implements Trackable {

public  Trackable beginTracking(Trackable self) {
    Monitor mon = (Monitor) self;
    // ...
    }
}

Extending Interfaces

As you can do with classes, you can organize interfaces into a hierarchy. When one interface inherits from another interface, that “subinterface” acquires all the method definitions and constants that its “superinterface” declared.

To extend an interface, you use the extends keyword just as you do in a class definition:

interface PreciselyTrackable extends Trackable {
    // ...
}

Note that unlike classes, the interface hierarchy has no equivalent of the Object class—there is no root superinterface from which all interfaces descend. Interfaces can either exist entirely on their own or inherit from another interface.

Note also that unlike the class hierarchy, the inheritance hierarchy can have multiple inheritance. For example, a single interface can extend as many classes as it needs to (separated by commas in the extends part of the definition), and the new interface contains a combination of all its parent’s methods and constants.

In interfaces, the rules for managing method name conflicts are the same as for classes that use multiple interfaces; methods that differ only in return type result in a compiler error message.

Creating an Online Storefront

To explore all the topics covered up to this point today, the Storefront application uses packages, access control, interfaces, and encapsulation. This application manages the items in an online storefront, handling two main tasks:

  • Calculating the sale price of each item depending on how much of it is presently in stock

  • Sorting items according to sale price

The Storefront application consists of two classes, Storefront and Item. These classes will be organized as a new package called org.cadenhead.ecommerce, so the first task is to define a folder structure on your system where this package’s classes will be stored.

The JDK and other Java development tools look for packages in the folders listed in the system’s Classpath, taking the package name into account. To prepare for this project, create a new folder that will be the root folder for all packages that you create. On my Windows XP system, I’ve designated c:devjava for this purpose.

This folder should be added to your system’s Classpath setting. For instructions on how to do this, read Appendix A.

When you create a new package, create the corresponding folder structure inside your package folder. The structure for this project should be orgcadenheadecommerce.

On my system, I created c:devjavaorgcadenheadecommerce to hold its class files.

After you have created a folder for the package and added it to your Classpath, create Item.java from Listing 6.2.

Example 6.2. The Full Text of Item.java

 1: package org.cadenhead.ecommerce;
 2:
 3: import java.util.*;
 4:
 5: public class Item implements Comparable {
 6:     private String id;
 7:     private String name;
 8:     private double retail;
 9:     private int quantity;
10:     private double price;
11:
12:     Item(String idIn, String nameIn, String retailIn, String quanIn) {
13:         id = idIn;
14:         name = nameIn;
15:         retail = Double.parseDouble(retailIn);
16:         quantity = Integer.parseInt(quanIn);
17:
18:         if (quantity > 400)
19:             price = retail * .5D;
20:         else if (quantity > 200)
21:             price = retail * .6D;
22:         else
23:             price = retail * .7D;
24:         price = Math.floor( price * 100 + .5 ) / 100;
25:     }
26:
27:     public int compareTo(Object obj) {
28:         Item temp = (Item)obj;
29:         if (this.price < temp.price)
30:             return 1;
31:         else if (this.price > temp.price)
32:             return -1;
33:         return 0;
34:     }
35:
36:     public String getId() {
37:         return id;
38:     }
39:
40:     public String getName() {
41:         return name;
42:     }
43:
44:     public double getRetail() {
45:         return retail;
46:     }
47:
48:     public int getQuantity() {
49:         return quantity;
50:     }
51:
52:     public double getPrice() {
53:         return price;
54:     }
55: }

Compile this class and then move the file Item.class to the orgcadenheadecommerce package on your system.

The Item class is a support class that represents a product sold by an online store. There are private instance variables for the product ID code, name, how many are in stock (quantity), and the retail and sale prices.

Because all the instance variables of this class are private, no other class can set or retrieve their values. Simple accessor methods are created in lines 36–54 of Listing 6.2 to provide a way for other programs to retrieve these values. Each method begins with get followed by the capitalized name of the variable, which is standard in the Java class library. For example, getPrice() returns a double containing the value of price. No methods are provided for setting any of these instance variables—that is handled in the constructor method for this class.

Line 1 establishes that the Item class is part of the org.cadenhead.ecommerce package.

Note

Cadenhead.org is the personal domain of this book’s coauthor, so this project follows Sun’s package-naming convention by beginning with a top-level domain (org), following it with the second-level domain name (cadenhead), and then by a name that describes the purpose of the package (ecommerce).

The Item class implements the Comparable interface (line 5), which makes it easy to sort a class’s objects. This interface has only one method, compareTo(Object), which returns an integer.

The compareTo() method compares two objects of a class: the current object and another object passed as an argument to the method. The value returned by the method defines the natural sorting order for objects of this class:

  • If the current object should be sorted above the other object, return -1.

  • If the current object should be sorted below the other object, return 1.

  • If the two objects are equal, return 0.

You determine in the compareTo() method which of an object’s instance variables to consider when sorting. Lines 27–34 override the compareTo() method for the Item class, sorting on the basis of the price variable. Items are sorted by price from highest to lowest.

After you have implemented the Comparable interface for an object, two class methods can be called to sort an array, linked list, or other collection of those objects. You see this when Storefront.class is created.

The Item() constructor in lines 12–25 takes four String objects as arguments and uses them to set up the id, name, retail, and quantity instance variables. The last two must be converted from strings to numeric values using the Double.parseDouble() and Integer.parseInt() class methods, respectively.

The value of the price instance variable depends on how much of that item is presently in stock:

  • If more than 400 are in stock, price is 50% of retail (lines 18–19).

  • If between 201 and 400 are in stock, price is 60% of retail (lines 20–21).

  • For everything else, price is 70% of retail (lines 22–23).

Line 24 rounds off price so that it contains two or fewer decimal places, turning a price such as $6.92999999999999 to $6.99. The Math.floor() method rounds off decimal numbers to the next lowest mathematical integer, returning them as double values.

After you have compiled Item.class, you’re ready to create a class that represents a storefront of these products. Create Storefront.java from Listing 6.3.

Example 6.3. The Full Text of Storefront.java

 1: package org.cadenhead.ecommerce;
 2:
 3: import java.util.*;
 4:
 5: public class Storefront {
 6:     private LinkedList catalog = new LinkedList();
 7:
 8:     public void addItem(String id, String name, String price,
 9:         String quant) {
10:
11:         Item it = new Item(id, name, price, quant);
12:         catalog.add(it);
13:     }
14:
15:     public Item getItem(int i) {
16:         return (Item)catalog.get(i);
17:     }
18:
19:     public int getSize() {
20:         return catalog.size();
21:     }
22:
23:     public void sort() {
24:         Collections.sort(catalog);
25:     }
26: }

To compile Storefront.java, the Item class must be stored in a folder that corresponds to the org.cadenhead.ecommerce package name. After you have compiled Storefront.class, move the file to the same folder as Item.class.

The Storefront.class is used to manage a collection of products in an online store. Each product is an Item object, and they are stored together in a LinkedList instance variable named catalog (line 6).

The addItem() method in lines 8–13 creates a new Item object based on four arguments sent to the method: the ID, name, price, and quantity in stock of the item. After the item is created, it is added to the catalog linked list by calling its add() method with the Item object as an argument.

The getItem() and getSize() methods provide an interface to the information stored in the private catalog variable. The getSize() method in lines 19–21 calls the catalog.size() method, which returns the number of objects contained in catalog.

Because objects in a linked list are numbered like arrays and other data structures, you can retrieve them using an index number. The getItem() method in lines 15–17 calls catalog.get() with an index number as an argument, returning the object stored at that location in the linked list.

The sort() method in lines 23–25 is where you benefit from the implementation of the Comparable interface in the Item class. The class method Collections.sort() sorts a linked list and other data structures based on the natural sort order of the objects they contain, calling the object’s compareTo() method to determine this order.

After you compile Storefront class, you’re ready to develop a program that actually uses the org.cadenhead.ecommerce package. Open the folder on your system where you’ve been creating the programs of this book (such as J21work) and create GiftShop.java from Listing 6.4.

Caution

Don’t save GiftShop.java in the same folder on your system where the classes of the org.cadenhead.ecommerce package are stored. It’s not part of the package (as you’ll note by the absence of a package org.cadenhead.ecommerce statement). The Java compiler exits with an error message because it wasn’t expecting to find Storefront.class in the same folder as the GiftShop application.

Example 6.4. The Full Text of GiftShop.java

 1: import org.cadenhead.ecommerce.*;
 2:
 3: public class GiftShop {
 4:    public static void main(String[] arguments) {
 5:         Storefront store = new Storefront();
 6:         store.addItem("C01", "MUG", "9.99", "150");
 7:         store.addItem("C02", "LG MUG", "12.99", "82");
 8:         store.addItem("C03", "MOUSEPAD", "10.49", "800");
 9:         store.addItem("D01", "T SHIRT", "16.99", "90");
10:         store.sort();
11:
12:         for (int i = 0; i < store.getSize(); i++) {
13:             Item show = (Item)store.getItem(i);
14:             System.out.println("
Item ID: " + show.getId() +
15:                 "
Name: " + show.getName() +
16:                 "
Retail Price: $" + show.getRetail() +
17:                 "
Price: $" + show.getPrice() +
18:                 "
Quantity: " + show.getQuantity());
19:         }
20:     }
21: }

This application uses the org.cadenhead.ecommerce package but does not belong to it.

The GiftShop class demonstrates each part of the public interface that the Storefront and Item classes make available. You can do each of the following:

  1. Create an online store

  2. Add items to it

  3. Sort the items by sale price

  4. Loop through a list of items to display information about each one

Caution

If you have stored Item.class, Storefront.class, or their source code files in the same folder as GiftShop.java, you might not be able to compile the program because the Java compiler expects to find those files in their package folder. Move those files to the orgcadenheadecommerce folder and compile GiftShop.java in another folder, such as J21work.

The output of this program is the following:

Item ID: D01
Name: T SHIRT
Retail Price: $16.99
Price: $11.89
Quantity: 90

Item ID: C02
Name: LG MUG
Retail Price: $12.99
Price: $9.09
Quantity: 82

Item ID: C01
Name: MUG
Retail Price: $9.99
Price: $6.99
Quantity: 150

Item ID: C03
Name: MOUSEPAD
Retail Price: $10.49
Price: $5.25
Quantity: 800

Many implementation details of these classes are hidden from GiftShop and other classes that would use the package.

For instance, the programmer who developed GiftShop doesn’t need to know that Storefront uses a linked list to hold the entire store’s product data. If the developer of Storefront decided later to use a different data structure, as long as getSize() and getItem() returned the expected values, GiftShop would continue to work correctly.

Inner Classes

The classes you have worked with thus far are all members of a package either because you specified a package name with the package declaration or because the default package was used. Classes that belong to a package are known as top-level classes. When Java was introduced, they were the only classes supported by the language.

In the current version of Java, you can define a class inside a class as if it were a method or a variable.

These types of classes are called inner classes. Listing 6.5 contains the SquareTool application, which uses an inner class called Square to square a floating-point number and store the result.

Example 6.5. The Full Text of SquareTool.java

 1: public class SquareTool {
 2:     public SquareTool(String input) {
 3:         try {
 4:             float in = Float.parseFloat(input);
 5:             Square sq = new Square(in);
 6:             float result = sq.value;
 7:            System.out.println("The square of " + input + " is " + result);
 8:         } catch (NumberFormatException nfe) {
 9:             System.out.println(input + " is not a valid number.");
10:         }
11:     }
12:
13:     class Square {
14:         float value;
15:
16:         Square(float x) {
17:             value = x * x;
18:         }
19:     }
20:
21:     public static void main(String[] arguments) {
22:         if (arguments.length < 1) {
23:             System.out.println("Usage: java SquareTool number");
24:         } else {
25:             SquareTool dr = new SquareTool(arguments[0]);
26:         }
27:     }
28: }

After compiling this application, run it with a floating-point number as an argument. For example, with the JDK you could enter the following at a command line:

java SquareTool 13

Here’s the output for that example:

The square of 13 is 169.0

If you run it without any arguments, the following text is displayed before the program exits:

Usage: java SquareTool number

In this application, the Square class isn’t functionally different from a helper class included in the same source file as a program’s main class file. The only difference is that the helper is defined inside the class file, which has several advantages:

  • Inner classes are invisible to all other classes, which means that you don’t have to worry about name conflicts between it and other classes.

  • Inner classes can have access to variables and methods within the scope of a top-level class that they would not have as a separate class.

In many cases, an inner class is a short class file that exists only for a limited purpose. In the SquareTool application, because the Square class doesn’t contain a lot of complex behavior and attributes, it is well suited for implementation as an inner class.

The name of an inner class is associated with the name of the class in which it is contained, and it is assigned automatically when the program is compiled. The Square class is given the name SquareTool$Square.class by the Java compiler.

Caution

When using inner classes, you must be even more careful to include all .class files when making a program available. Each inner class has its own class file, and these class files must be included along with any top-level classes.

Inner classes, although seemingly a minor enhancement, actually represent a significant modification to the language.

Rules governing the scope of an inner class closely match those governing variables. An inner class’s name is not visible outside its scope, except in a fully qualified name, which helps in structuring classes within a package. The code for an inner class can use simple names from enclosing scopes, including class and member variables of enclosing classes, as well as local variables of enclosing blocks.

In addition, you can define a top-level class as a static member of another top-level class. Unlike an inner class, a top-level class cannot directly use the instance variables of any other class. The ability to nest classes in this way allows any top-level class to provide a package-style organization for a logically related group of secondary top-level classes.

Summary

Today, you learned how to encapsulate an object by using access control modifiers for its variables and methods. You also learned how to use other modifiers such as static, final, and abstract in the development of Java classes and class hierarchies.

To further the effort of developing a set of classes and using them, you learned how to group classes into packages. These groupings better organize your programs and enable the sharing of classes with the many other Java programmers making their code publicly available.

Finally, you learned how to implement interfaces and inner classes, two structures that are helpful when designing a class hierarchy.

Q&A

Q

Won’t using accessor methods everywhere slow down my Java code?

A

Not always. As Java compilers improve and can create more optimizations, they will be able to make accessor methods fast automatically, but if you’re concerned about speed, you can always declare accessor methods to be final, and they’ll be comparable in speed to direct instance variable accesses under most circumstances.

Q

Based on what I’ve learned, private abstract methods and final abstract methods or classes don’t seem to make sense. Are they legal?

A

Nope, they’re compile-time error messages, as you have guessed. To be useful, abstract methods must be overridden, and abstract classes must be subclassed, but neither of those two operations would be legal if they were also private or final.

Q

I’ve been told that I should consider using Ant to manage my Java packages and compile applications. What does Ant do?

A

Apache Ant is an open source tool for compiling and packaging Java applications and class libraries that is implemented with Java and Extensible Markup Language (XML). With Ant, you create an XML file that indicates how your classes should be compiled, archived, and organized. You can specify multiple targets for each “build,” the term applied to the process, and easily produce multiple builds for each stage of a project’s development.

Ant, which can be downloaded from the website http://ant.apache.org, was created by programmers for Jakarta, the open source Java project administered by Apache that has produced Struts, Velocity, Tomcat, and many other useful Java class libraries and technologies.

Jakarta projects are extremely extensive, requiring the management of hundreds of Java classes, JAR archives, and other files. Ant was so useful in the creation of the Tomcat web server that it became an Apache development project in its own right. It has subsequently become the most popular build tool for Java programmers.

Quiz

Review today’s material by taking this three-question quiz.

Questions

1.

What packages are automatically imported into your Java classes?

  1. None

  2. The classes stored in the folders of your CLASSPATH

  3. The classes in the java.lang package

2.

According to the convention for naming packages, what should be the first part of the name of a package you create?

  1. Your name followed by a period

  2. Your top-level Internet domain followed by a period

  3. The text java followed by a period

3.

If you create a subclass and override a public method, what access modifiers can you use with that method?

  1. public only

  2. public or protected

  3. public, protected, or default access

Answers

1.

c. All other packages must be imported if you want to use short class names such as LinkedList instead of full package and class names such as java.util.LinkedList.

2.

b. This convention assumes that all Java package developers will own an Internet domain or have access to one so that the package can be made available for download.

3.

a. All public methods must remain public in subclasses.

Certification Practice

The following question is the kind of thing you could expect to be asked on a Java programming certification test. Answer it without looking at today’s material or using the Java compiler to test the code.

Given:

package org.cadenhead.bureau;

public class Information {
    public int duration = 12;
    protected float rate = 3.15F;
    float average = 0.5F;
}

And:

package org.cadenhead.bureau;

import org.cadenhead.bureau.*;

public class MoreInformation extends Information {
    public int quantity = 8;
}

And:

package org.cadenhead.bureau.us;

import org.cadenhead.bureau.*;

public class EvenMoreInformation extends MoreInformation {
    public int quantity = 9;

    EvenMoreInformation() {
        super();
        int i1 = duration;
        float i2 = rate;
        float i3 = average;
    }
}

Which instance variables are visible in the EvenMoreInformation class?

  1. quantity, duration, rate, and average

  2. quantity, duration, and rate

  3. quantity, duration, and average

  4. quantity, rate, and average

The answer is available on the book’s website at http://www.java21days.com. Visit the Day 6 page and click the Certification Practice link.

Exercises

To extend your knowledge of the subjects covered today, try the following exercises:

  1. Create a modified version of the Storefront project that includes a noDiscount variable for each item. When this variable is true, sell the item at the retail price.

  2. Create a ZipCode class that uses access control to ensure that its zipCode instance variable always has a five- or nine-digit value.

Where applicable, exercise solutions are offered on the book’s website at http://www.java21days.com.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset