Writing Abstract Classes and Methods

Sometimes, a class that you define represents an abstract concept and, as such, should not be instantiated. Take, for example, food in the real world. Have you ever seen an instance of food? No. What you see instead are instances of carrot, apple, and (our favorite) chocolate. Food represents the abstract concept of things that we all can eat. It doesn't make sense for an instance of food to exist.

Similarly in object-oriented programming, you may want to model an abstract concept without being able to create an instance of it. For example, the Number class in the java.lang package represents the abstract concept of numbers. It makes sense to model numbers in a program, but it doesn't make sense to create a generic number object. Instead, the Number class makes sense only as a superclass to classes like Integer and Float, both of which implement specific kinds of numbers. A class such as Number, which represents an abstract concept and should not be instantiated, is called an abstract class. An abstract class is a class that can only be subclassed-- it cannot be instantiated.

To declare that your class is an abstract class, use the keyword abstract before the class keyword in your class declaration:

abstract class Number {

    . . .

}

If you attempt to instantiate an abstract class, the compiler displays an error similar to the following and refuses to compile your program:

AbstractTest.java:6: class AbstractTest is an abstract class.

It can't be instantiated.

        new AbstractTest();

        ^

1 error

Abstract Methods

An abstract class may contain abstract methods, that is, methods with no implementation. In this way, an abstract class can define a complete programming interface, thereby providing its subclasses with the method declarations for all of the methods necessary to implement that programming interface. However, the abstract class can leave some or all of the implementation details of those methods up to its subclasses.

Let's look at an example of when you might want to create an abstract class with an abstract method in it. In an object-oriented drawing application, you can draw circles, rectangles, lines, Bezier curves, and so on. Each of these graphic objects share certain states (position, bounding box) and behavior (move, resize, draw). You can take advantage of these similarities and declare them all to inherit from the same parent object--GraphicObject.

However, the graphic objects are also substantially different in many ways: drawing a circle is quite different from drawing a rectangle. The graphics objects cannot share these types of states or behavior. On the other hand, all GraphicObjects must know how to draw themselves; they just differ in how they are drawn. This is a perfect situation for an abstract superclass.

First you would declare an abstract class, GraphicObject, to provide member variables and methods that were wholly shared by all subclasses, such as the current position and the moveTo method. GraphicObject also declares abstract methods for methods, such as draw, that need to be implemented by all subclasses, but are implemented in entirely different ways (no default implementation in the superclass makes sense). The GraphicObject class would look something like this:

abstract class GraphicObject {

    int x, y;

    . . .

    void moveTo(int newX, int newY) {

        . . .

    }

    abstract void draw();

}

Each non-abstract subclass of GraphicObject, such as Circle and Rectangle, would have to provide an implementation for the draw method.

class Circle extends GraphicObject {

    void draw() {

        . . .

    }

}

class Rectangle extends GraphicObject {

    void draw() {

        . . .

    }

}

An abstract class is not required to have an abstract method in it. But any class that has an abstract method in it or that does not provide an implementation for any abstract methods declared in its superclasses must be declared as an abstract class.

 

Questions and Exercises: Managing Inheritance

Questions

1. Consider the following two classes:

public class ClassA {

    public void methodOne(int i) {

    }

    public void methodTwo(int i) {

    }

    public static void methodThree(int i) {

    }

    public static void methodFour(int i) {

    }

}

 

public class ClassB extends ClassA {

    public static void methodOne(int i) {

    }

    public void methodTwo(int i) {

    }

    public void methodThree(int i) {

    }

    public static void methodFour(int i) {

    }

}

a. Which method overrides a method in the superclass?
b. Which method hides a method in the superclass?
c. What do the other methods do?


2. Consider the Card (in a .java source file), Deck (in a .java source file), and DisplayDeck (in a .java source file) classes you wrote in the previous exercise. What Object methods should each of these classes override?

Exercises

1. Write the implementations for the methods that you answered in question 2.

2. Write an abstract class. Write at least two of its nonabstract subclasses.

 

Check your answers. (in the Learning the Java Language trail)

Implementing Nested Classes

Java lets you define a class as a member of another class. Such a class is called a nested class and is illustrated here:

class EnclosingClass{

    . . .

    class ANestedClass {

        . . .

    }

}


Definition:  A nested class is a class that is a member of another class.


You use nested classes to reflect and enforce the relationship between two classes. You should define a class within another class when the nested class makes sense only in the context of its enclosing class or when it relies on the enclosing class for its function. For example, a text cursor makes sense only in the context of a particular text component.

As a member of its enclosing class, a nested class has a special privilege: It has unlimited access to its enclosing class's members, even if they are declared private. However, this special privilege isn't really special at all. It is fully consistent with the meaning of private and the other access specifiers. The access specifiers restrict access to members for classes outside of the enclosing class. The nested class is inside of its enclosing class so that it has access to its enclosing class's members.

Like other members, a nested class can be declared static (or not). A static nested class is called just that: a static nested class. A nonstatic nested class is called an inner class. These are illustrated in the following code:

class EnclosingClass{

    . . .

    static class AStaticNestedClass {

        . . .

    }

    class InnerClass {

        . . .

    }

}

As with static methods and variables (normally called class methods and variables), a static nested class is associated with its enclosing class. And like class methods, a static nested class cannot refer directly to instance variables or methods defined in its enclosing class-it can use them only through an object reference.

As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's instance variables and methods. Also, because an inner class is associated with an instance, it cannot define any static members itself.

To help differentiate the terms nested class and inner class further, we suggest you think about them in the following way. The term "nested class" reflects the syntactic relationship between two classes; that is, syntactically, the code for one class appears within the code of another. In contrast, the term "inner class" reflects the relationship between instances of the two classes. Consider the following classes:

class EnclosingClass {

    . . .

    class InnerClass {

        . . .

    }

}

The interesting feature about the relationship between these two classes is not that InnerClass is syntactically defined within EnclosingClass. Rather, it's that an instance of InnerClass can exist only within an instance of EnclosingClass and that it has direct access to instance variables and methods of its enclosing instance. The following diagram illustrates this idea.

You may encounter nested classes of both kinds in the Java API and be required to use them. However, most nested classes that you write will be inner classes.


Definition:  An inner class is a nested class whose instance exists within an instance of its enclosing class and has direct access to the instance members of its enclosing instance.


Other Facts about Nested Classes

Like other classes, nested classes can be declared abstract or final. The meaning of these two modifiers for nested classes is the same as for other classes. Also, the access specifiers--private, public, protected, and package--- may be used to restrict access to nested classes just as they do to other class members.

Any nested class, not just anonymous ones, can be declared in any block of code. A nested class declared within a method or other smaller block of code has access to any final, local variables in scope.

 

Inner Classes

To help you get a handle on inner classes and what they are good for, let's revisit the Stack class. Suppose you want to add a feature to this class that lets another class enumerate over the elements in the stack using the interface defined in java.util.Enumeration. This interface contains two method declarations:

public boolean hasMoreElements();

public Object nextElement();

The Enumeration interface defines the interface for a single loop over the elements:

while (hasMoreElements())

    nextElement()

If Stack implemented the Enumeration interface itself, you could not restart the loop and you could not enumerate the contents more than once. Also, you couldn't allow two enumerations to happen simultaneously. So Stack shouldn't implement Enumeration. Rather, a helper class should do the work for Stack.

The helper class must have access to the Stack's elements. It also must be able to access them directly because the Stack's public interface supports only LIFO access. This is where inner classes come in.

Here's an implementation of Stack that defines a helper class (called an adapter class) for enumerating over its elements:

public class Stack {

    private Vector items;

 

    ...//code for Stack's methods and constructors not shown...

 

    public Enumeration enumerator() {

        return new StackEnum();

    }

 

    class StackEnum implements Enumeration {

        int currentItem = items.size() - 1;

        public boolean hasMoreElements() {

            return (currentItem >= 0);

        }

        public Object nextElement() {

            if (!hasMoreElements())

                throw new NoSuchElementException();

            else

                return items.elementAt(currentItem--);

        }

    }

}

Note that the StackEnum class refers directly to Stack's items instance variable.

Inner classes are used primarily to implement adapter classes like the one shown in this example. If you plan on handling events from the AWT, then you'll want to know about using adapter classes because the event-handling mechanism in the AWT makes extensive use of them.

Anonymous Classes

You can declare an inner class without naming it. Here's yet another version of the now-tired Stack class, in this case using an anonymous class for its enumerator:

public class Stack {

    private Vector items;

 

    ...//code for Stack's methods and constructors not shown...

 

    public Enumeration enumerator() {

        return new Enumeration() {

            int currentItem = items.size() - 1;

            public boolean hasMoreElements() {

                return (currentItem >= 0);

            }

            public Object nextElement() {

                if (!hasMoreElements())

                    throw new NoSuchElementException();

                else

                    return items.elementAt(currentItem--);

            }

        }

    }

}

Anonymous classes can make code difficult to read. You should limit their use to those classes that are very small (no more than a method or two) and whose use is well-understood (like the AWT event-handling adapter classes).

 

Questions and Exercises: Implementing Nested Classes

Questions

1. Match each situation in the first column with the most appropriate type of nested class in the second column.

 a. The only users of this nested class will be instances of the enclosing class or instances of the enclosing class's subclasses.

 1. anonymous inner class

 b. Anyone can use this nested class.

 2. protected inner class

 c. Only instances of the declaring class need to use this nested class, and a particular instance might use it several times.

 3. public static nested class

 d. This tiny nested class is used just once, to create an object that implements an interface.

 4. protected static nested class

 e. This nested class has information about its enclosing class (not about instances of the enclosing class) and is used only by its enclosing class and perhaps their subclasses.

 5. private static nested class

 f. Similar situation as the preceding (choice e), but not intended to be used by subclasses.

 6. private inner class

2. The program Problem.java (in a .java source file) doesn't compile. What do you need to do to make it compile? Why?

3. Use the 1.3 API documentation for the Box (in the API reference documentation) class (in the javax.swing package) to help you answer the following questions.

a. What static nested class does Box define?
b. What inner class does Box define?
c. What is the superclass of Box’s inner class?
d. Which of Box’s nested classes can you use from any class?
e. How do you create an instance of Box’s Filler class?

Exercises

1. First, get the source file InnerClassDemo.java (in a .java source file)

a. Compile and run InnerClassDemo.java (in a .java source file).

b. Make a copy of InnerClassDemo. Add to it an inner class named MyActionListener that implements the ActionListener interface. The ActionListener interface defines a single method. Put the following code into your implementation of the method: quit();

Delete the double forward slashes (//) in front of the following line of code:

     //button.addActionListener(new MyActionListener());

Now compile and run the program. What is the difference in behavior between this version and the previous version of InnerClassDemo?

c. Make a copy of the program you created in exercise 1b. Change your ActionListener implementation to be an anonymous inner class. (Hint: The program has another anonymous inner class, a WindowAdapter, which you can refer to for syntax help.)

2. Get the file Class1.java (in a .java source file).

a. Compile and run Class1. What is the output?

b. Create a file called Class2.java that defines subclasses of both Class1 and its inner class, InnerClass1. (Call the subclasses Class2 and InnerClass2, respectively.) InnerClass2 should override the getAnotherString method to return "InnerClass2 version of getAnotherString invoked". Class2 should define one constructor and one method:

·         A no-argument constructor that initializes the inherited ic instance variable to be an instance of InnerClass2

·         A main method that creates an instance of Class2 and invokes displayStrings on that instance

What is the output when you run Class2?

 

What Is an Interface?

This section shows you how to create and to use interfaces and talks about why you would use an interface instead of a class.

An interface defines a protocol of behavior that can be implemented by any class anywhere in the class hierarchy. An interface defines a set of methods but does not implement them. A class that implements the interface agrees to implement all the methods defined in the interface, thereby agreeing to certain behavior.


Definition: An interface is a named collection of method definitions (without implementations). An interface can also declare constants.


Because an interface is simply a list of unimplemented, and therefore abstract, methods, you might wonder how an interface differs from an abstract class. The differences are significant.

·         An interface cannot implement any methods, whereas an abstract class can.

·         A class can implement many interfaces but can have only one superclass.

·         An interface is not part of the class hierarchy. Unrelated classes can implement the same interface.

Let's set up the example we'll be using in this section. Suppose that you have written a class that can watch stock prices coming over a data feed. This class allows other classes to register to be notified when the value of a particular stock changes. First, your class, which we'll call StockMonitor, would implement a method that lets other objects register for notification:

public class StockMonitor {

     public void watchStock(StockWatcher watcher,

     String tickerSymbol, double delta) {

     ...

     }

}

The first argument to this method is a StockWatcher object. StockWatcher is the name of an interface whose code you will see in the next section. That interface declares one method: valueChanged. An object that wants to be notified of stock changes must be an instance of a class that implements this interface and thus implements the valueChanged method. The other two arguments provide the symbol of the stock to watch and the amount of change that the watcher considers interesting enough to be notified of. When the StockMonitor class detects an interesting change, it calls the valueChanged method of the watcher.

The watchStock method ensures, through the data type of its first argument, that all registered objects implement the valueChanged method. It makes sense to use an interface data type here because it matters only that registrants implement a particular method. If StockMonitor had used a class name as the data type, that would artificially force a class relationship on its users. Because a class can have only one superclass, it would also limit what type of objects can use this service. By using an interface, the registered objects class could be anything--Applet or Thread--for instance, thus allowing any class anywhere in the class hierarchy to use this service.

Defining an Interface

The figure below shows that an interface definition has two components: the interface declaration and the interface body. The interface declaration declares various attributes about the interface, such as its name and whether it extends other interfaces. The interface body contains the constant and the method declarations for that interface.

The StockWatcher interface and the structure of an interface definition.

public interface StockWatcher {
    final String
    sunTicker = "SUNW";
    final String oracleTicker = "ORCL";
    final String ciscoTicker = "CSCO";
    void valueChanged(String tickerSymbol, double newValue);
}

The interface shown in the figure above is the StockWatcher interface mentioned previously. This interface defines three constants, which are the ticker symbols of watchable stocks. This interface also declares, but does not implement, the valueChanged method. Classes that implement this interface provide the implementation for that method.

The Interface Declaration

The following figure shows all possible components of an interface declaration.

The possible components of an interface declaration and their purposes.

Two elements are required in an interface declaration--the interface keyword and the name of the interface. The public access specifier indicates that the interface can be used by any class in any package. If you do not specify that your interface is public, your interface will be accessible only to classes that are defined in the same package as the interface.

An interface declaration can have one other component: a list of superinterfaces. An interface can extend other interfaces, just as a class can extend or subclass another class. However, whereas a class can extend only one other class, an interface can extend any number of interfaces. The list of superinterfaces is a comma-separated list of all the interfaces extended by the new interface.

The Interface Body

The interface body contains method declarations for all the methods included in the interface. A method declaration within an interface is followed by a semicolon (;) because an interface does not provide implementations for the methods declared within it. All methods declared in an interface are implicitly public and abstract.

An interface can contain constant declarations in addition to method declarations. All constant values defined in an interface are implicitly public, static, and final.

Member declarations in an interface disallow the use of some declaration modifiers; you cannot use transient, volatile, or synchronized in a member declaration in an interface. Also, you may not use the private and protected specifiers when declaring members of an interface.


Note:  Previous releases of the Java platform allowed you to use the abstract modifier on interface declarations and on method declarations within interfaces. However, this is unnecessary, because interfaces and their methods are implicitly abstract. You should not use abstract in your interface declarations or in your method declarations within interfaces.


 

Implementing an Interface

An interface defines a protocol of behavior. A class that implements an interface adheres to the protocol defined by that interface. To declare a class that implements an interface, include an implements clause in the class declaration. Your class can implement more than one interface (the Java platform supports multiple inheritance for interfaces), so the implements keyword is followed by a comma-separated list of the interfaces implemented by the class.


By Convention:  The implements clause follows the extends clause, if it exists.


Here's a partial example of an applet that implements the StockWatcher interface:

public class StockApplet extends Applet implements StockWatcher {

    ...

 

    public void valueChanged(String tickerSymbol, double newValue) {

        if (tickerSymbol.equals(sunTicker)) {

            ...

        } else if (tickerSymbol.equals(oracleTicker)) {

            ...

        } else if (tickerSymbol.equals(ciscoTicker)) {

            ...

        }

    }

}

Note that this class refers to each constant defined in StockWatcher,sunTicker, oracle-Ticker, simple name. Classes that implement an interface inherit the constants defined within that interface. So those classes can use simple names to refer to the constants. Any other class can use an interfaces constants with a qualified name, like this:

StockWatcher.sunTicker

When a class implements an interface, it is essentially signing a contract. Either the class must implement all the methods declared in the interface and its superinterfaces, or the class must be declared abstract. The method signature--the name and the number and type of arguments in the class--must match the method signature as it appears in the interface. The StockApplet implements the StockWatcher interface, so the applet provides an implementation for the valueChanged method. The method ostensibly updates the applets display or otherwise uses this information.

 

Using an Interface as a Type

When you define a new interface, you are defining a new reference data type. You can use interface names anywhere you can use any other data type name. Recall that the data type for the first argument to the watchStock method in the StockMonitor class is StockWatcher:

public class StockMonitor {

    public void watchStock(StockWatcher watcher,

                           String tickerSymbol, double delta) {

    ...

    }

}

Only an instance of a class that implements the interface can be assigned to a reference variable whose type is an interface name. So only instances of a class that implements the StockWatcher interface can register to be notified of stock value changes. StockWatcher objects are guaranteed to have a valueChanged method.

 

Warning! Interfaces Cannot Grow

Suppose that you want to add some functionality to StockWatcher. For instance, suppose that you want to add a method that reports the current stock price, regardless of whether the value changed:

public interface StockWatcher {

    final String sunTicker = "SUNW";

    final String oracleTicker = "ORCL";

    final String ciscoTicker = "CSCO";

   

    void valueChanged(String tickerSymbol, double newValue);

    void currentValue(String tickerSymbol, double newValue);

}