Session 7 Lecture Notes for First Course in Java
course homepage      course calendar

29 April 2002

This lecture covers the reading in Day 15: Packages, Interfaces, and Other Class Features


Packages, Interfaces, and Other Class Features (Day 15)


Access Control

http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html

Controlling Access to Members of a Class

One of the benefits of classes is that classes can protect their member variables and methods from access by other objects. Why is this important? Well, consider this. You're writing a class that represents a query on a database that contains all kinds of secret information, say employee records or income statements for your startup company.

Certain information and queries contained in the class, the ones supported by the publicly accessible methods and variables in your query object, are OK for the consumption of any other object in the system. Other queries contained in the class are there simply for the personal use of the class. They support the operation of the class but should not be used by objects of another type--you've got secret information to protect. You'd like to be able to protect these personal variables and methods at the language level and disallow access by objects of another type.

In Java, you can use access specifiers to protect both a class's variables and its methods when you declare them. The Java language supports four distinct access levels for member variables and methods: private, protected, public, and, if left unspecified, package.

 


Note: The 1.0 release of the Java language supported five access levels: the four listed above plus private protected. The private protected access level is not supported in versions of Java higher than 1.0; you should no longer be using it in your Java programs.

The following chart shows the access level permitted by each specifier.

 
Specifier class subclass package world
private X      
protected X X* X  
public X X X X
package X   X  

The first column indicates whether the class itself has access to the member defined by the access specifier. As you can see, a class always has access to its own members. The second column indicates whether subclasses of the class (regardless of which package they are in) have access to the member. The third column indicates whether classes in the same package as the class (regardless of their parentage) have access to the member. The fourth column indicates whether all classes have access to the member.

Note that the protected/subclass intersection has an '*' . This particular access case has a special caveat discussed in detail later.

Let's look at each access level in more detail.

Private

The most restrictive access level is private. A private member is accessible only to the class in which it is defined. Use this access to declare members that should only be used by the class. This includes variables that contain information that if accessed by an outsider could put the object in an inconsistent state, or methods that, if invoked by an outsider, could jeopardize the state of the object or the program in which it's running. Private members are like secrets you never tell anybody.

To declare a private member, use the private keyword in its declaration. The following class contains one private member variable and one private method:

class Alpha {
    private int iamprivate;
    private void privateMethod() {
        System.out.println("privateMethod");
    }
}
Objects of type Alpha can inspect or modify the iamprivate variable and can invoke privateMethod, but objects of other types cannot. For example, the Beta class defined here:
class Beta {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iamprivate = 10;      // illegal
        a.privateMethod();      // illegal
    }
}
cannot access the iamprivate variable or invoke privateMethod on an object of type Alpha because Beta is not of type Alpha.

When one of your classes is attempting to access a member varible to which it does not have access, the compiler prints an error message similar to the following and refuses to compile your program:

Beta.java:9: Variable iamprivate in class Alpha not 
accessible from class Beta.
        a.iamprivate = 10;     // illegal
         ^
1 error
Also, if your program is attempting to access a method to which it does not have access, you will see a compiler error like this:
Beta.java:12: No method matching privateMethod()
found in class Alpha.
        a.privateMethod();         // illegal
1 error
New Java programmers might ask if one Alpha object can access the private members of another Alpha object. This is illustrated by the following example. Suppose the Alpha class contained an instance method that compared the current Alpha object (this) to another object based on their iamprivate variables:
class Alpha {
    private int iamprivate;
    boolean isEqualTo(Alpha anotherAlpha) {
        if (this.iamprivate == anotherAlpha.iamprivate)
            return true;
        else
            return false;
    }
}
This is perfectly legal. Objects of the same type have access to one another's private members. This is because access restrictions apply at the class or type level (all instances of a class) rather than at the object level (this particular instance of a class).

 


Note: this is a Java language keyword that refers to the current object. For more information about how to use this see The Method Body.

Protected

The next access level specifier is protected, which allows the class itself, subclasses (with the caveat that we referred to earlier), and all classes in the same package to access the members. Use the protected access level when it's appropriate for a class's subclasses to have access to the member, but not unrelated classes. Protected members are like family secrets--you don't mind if the whole family knows, and even a few trusted friends but you wouldn't want any outsiders to know.

To declare a protected member, use the keyword protected. First, let's look at how the protected specifier affects access for classes in the same package. Consider this version of the Alpha class which is now declared to be within a package named Greek and which has one protected member variable and one protected method declared in it:

package Greek;

public class Alpha {
    protected int iamprotected;
    protected void protectedMethod() {
        System.out.println("protectedMethod");
    }
}
Now, suppose that the class Gamma was also declared to be a member of the Greek package (and is not a subclass of Alpha). The Gamma class can legally access an Alpha object's iamprotected member variable and can legally invoke its protectedMethod:
package Greek;

class Gamma {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iamprotected = 10;    // legal
        a.protectedMethod();    // legal
    }
}
That's pretty straightforward. Now, let's investigate how the protected specifier affects access for subclasses of Alpha.

Let's introduce a new class, Delta, that derives from Alpha but lives in a different package--Latin. The Delta class can access both iamprotected and protectedMethod, but only on objects of type Delta or its subclasses. The Delta class cannot access iamprotected or protectedMethod on objects of type Alpha. accessMethod in the following code sample attempts to access the iamprotected member variable on an object of type Alpha, which is illegal, and on an object of type Delta, which is legal. Similarly, accessMethod attempts to invoke an Alpha object's protectedMethod which is also illegal:

package Latin;

import Greek.*;

class Delta extends Alpha {
    void accessMethod(Alpha a, Delta d) {
        a.iamprotected = 10;    // illegal
        d.iamprotected = 10;    // legal
        a.protectedMethod();    // illegal
        d.protectedMethod();    // legal
    }
}
If a class is both a subclass of and in the same package as the class with the protected member, then the class has access to the protected member.

Public

The easiest access specifier is public. Any class, in any package, has access to a class's public members. Declare public members only if such access cannot produce undesirable results if an outsider uses them. There are no personal or family secrets here; this is for stuff you don't mind anybody else knowing.

To declare a public member, use the keyword public. For example,

package Greek;

public class Alpha {
    public int iampublic;
    public void publicMethod() {
        System.out.println("publicMethod");
    }
}
Let's rewrite our Beta class one more time and put it in a different package than Alpha and make sure that it is completely unrelated to (not a subclass of) Alpha:
package Roman;

import Greek.*;

class Beta {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iampublic = 10;       // legal
        a.publicMethod();       // legal
    }
}
As you can see from the above code snippet, Beta can legally inspect and modify the iampublic variable in the Alpha class and can legally invoke publicMethod.

Package

The package access level is what you get if you don't explicitly set a member's access to one of the other levels. This access level allows classes in the same package as your class to access the members. This level of access assumes that classes in the same package are trusted friends. This level of trust is like that which you extend to your closest friends but wouldn't trust even to your family.

For example, this version of the Alpha class declares a single package-access member variable and a single package-access method. Alpha lives in the Greek package:

package Greek;

class Alpha {
    int iampackage;
    void packageMethod() {
        System.out.println("packageMethod");
    }
}
The Alpha class has access both to iampackage and packageMethod. In addition, all the classes declared within the same package as Alpha also have access to iampackage and packageMethod. Suppose that both Alpha and Beta were declared as part of the Greek package:
package Greek;

class Beta {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iampackage = 10;     // legal
        a.packageMethod();     // legal
    }
}
Beta can legally access iampackage and packageMethod as shown.

Modifiers

The modifier keywords include

http://java.sun.com/docs/books/tutorial/reflect/class/getModifiers.html

Discovering Class Modifiers

A class declaration may include the following modifiers: public, abstract, or final. The class modifiers precede the class keyword in the class definition. In the following example, the class modifiers are public and final:
public final Coordinate {int x, int y, int z}
To identify the modifiers of a class at runtime you perform these steps:
  1. Invoke getModifiers on a Class object to retrieve a set of modifiers.
  2. Check the modifiers by calling isPublic, isAbstract, and isFinal.
The following program identifies the modifiers of the String class.
import java.lang.reflect.*;
import java.awt.*;

class SampleModifier {

   public static void main(String[] args) {
      String s = new String();
      printModifiers(s);
   }

   public static void printModifiers(Object o) {
      Class c = o.getClass();
      int m = c.getModifiers();
      if (Modifier.isPublic(m))
         System.out.println("public");
      if (Modifier.isAbstract(m))
         System.out.println("abstract");
      if (Modifier.isFinal(m))
         System.out.println("final");
   }
}
The output of the sample program reveals that the modifiers of the String class are public and final:
public
final

Static Variables and Methods

The output is:

Starting with 0 instances
Created 10 instances

Final Classes, Methods, and Variables

http://java.sun.com/docs/books/tutorial/java/nutsandbolts/finalVariables.html

Final Variables

You can declare a variable in any scope to be final (in the glossary). The value of a final variable cannot change after it has been initialized. Such variables are similar to constants in other programming languages.

To declare a final variable, use the final keyword in the variable declaration before the type:

final int aFinalVar = 0;
The previous statement declares a final variable and initializes it, all at once. Subsequent attempts to assign a value to aFinalVar result in a compiler error. You may, if necessary, defer initialization of a final local variable. Simply declare the local variable and initialize it later, like this:
final int blankfinal;
. . .
blankfinal = 0;
A final local variable that has been declared but not yet initialized is called a blank final. Again, once a final local variable has been initialized, it cannot be set, and any later attempts to assign a value to blankfinal result in a compile-time error.

http://java.sun.com/docs/books/tutorial/java/javaOO/final.html


Abstract Classes and Methods

http://java.sun.com/docs/books/tutorial/java/javaOO/abstract.html

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.

Packages

http://java.sun.com/docs/books/tutorial/java/interpack/packages.html

To make classes easier to find and to use, to avoid naming conflicts, and to control access, programmers bundle groups of related classes and interfaces into packages.

 


Definition:  A package is a collection of related classes and interfaces providing access protection and namespace management.

The classes and interfaces that are part of the Java platform are members of various packages that bundle classes by function: fundamental classes are in java.lang, classes for reading and writing (input and output) are in java.io, and so on. You can put your classes and interfaces in packages, too.

Let's look at a set of classes and examine why you might want to put them in a package. Suppose that you write a group of classes that represent a collection of graphic objects, such as circles, rectangles, lines, and points. You also write an interface, Draggable, that classes implement if they can be dragged with the mouse by the user:

//in the Graphic.java file
public abstract class Graphic {
    . . .
}

//in the Circle.java file
public class Circle extends Graphic implements Draggable {
    . . .
}

//in the Rectangle.java file
public class Rectangle extends Graphic implements Draggable {
    . . .
}

//in the Draggable.java file
public interface Draggable {
    . . .
}

You should bundle these classes and the interface in a package for several reasons:

Creating Packages

http://java.sun.com/docs/books/tutorial/java/interpack/createpkgs.html

To create a package, you put a class or an interface in it. To do this, you put a package statement at the top of the source file in which the class or the interface is defined. For example, the following code appears in the source file Circle.java and puts the Circle class in the graphics package:
package graphics;

public class Circle extends Graphic implements Draggable {
    . . .
}
The Circle class is a public member of the graphics package.

You must include a package statement at the top of every source file that defines a class or an interface that is to be a member of the graphics package. So you would also include the statement in Rectangle.java and so on:

package graphics;

public class Rectangle extends Graphic implements Draggable {
    . . .
}
The scope of the package statement is the entire source file, so all classes and interfaces defined in Circle.java and Rectangle.java are also members of the graphics package. If you put multiple classes in a single source file, only one may be public, and it must share the name of the source files base name. Only public package members are accessible from outside the package.

If you do not use a package statement, your class or interface ends up in the default package, which is a package that has no name. Generally speaking, the default package is only for small or temporary applications or when you are just beginning development. Otherwise, classes and interfaces belong in named packages.

Naming a Package

With programmers all over the world writing classes and interfaces using the Java programming language, it is likely that two programmers will use the same name for two different classes. In fact, the previous example does just that: It defines a Rectangle class when there is already a Rectangle class in the java.awt package. Yet the compiler allows both classes to have the same name. Why? Because they are in different packages, and the fully qualified name of each class includes the package name. That is, the fully qualified name of the Rectangle class in the graphics package is graphics.Rectangle, and the fully qualified name of the Rectangle class in the java.awt package is java.awt.Rectangle.

This generally works just fine unless two independent programmers use the same name for their packages. What prevents this problem? Convention.

 


By Convention:  Companies use their reversed Internet domain name in their package names, like this: com.company.package. Some companies now choose to drop the first element com. in this example from their package names. Name collisions that occur within a single company need to be handled by convention within that company, perhaps by including the region or the project name after the company name, for example, com.company.region.package.

http://java.sun.com/docs/books/tutorial/java/interpack/QandE/packages-answers.html

Answers to Questions and Exercises: Creating and Using Packages

Question 1: Assume that you have written some classes. Belatedly, you decide that they should be split into three packages, as listed in the table below. Furthermore, assume that the classes are currently in the default package (they have no package statements).

Package Name

Class Name

mygame.server

Server

mygame.shared

Utilities

mygame.client

Client

a. What line of code will you need to add to each source file to put each class in the right package?
Answer 1a: The first line of each file must specify the package:

In Client.java add:
package mygame.client;
In Server.java add:
package mygame.server;:
In Utilities.java add:
package mygame.shared;
b. To adhere to the directory structure, you will need to create some subdirectories in your development directory, and put source files in the correct subdirectories. What subdirectories must you create? Which subdirectory does each source file go in?
Answer 1b: Within the mygame directory, you need to create three subdirectories: client, server, and shared.
In mygame/client/ place:
Client.java
In mygame/server/ place:
Server.java
In mygame/shared/ place:
Utilities.java
c. Do you think you'll need to make any other changes to the source files to make them compile correctly? If so, what?
Answer 1c: Yes, you need to add import statements. Client.java and Server.java need to import the Utilities class, which they can do in one of two ways:
import mygame.shared.*;
import mygame.shared.Utilities;

Interfaces

http://java.sun.com/docs/books/tutorial/java/concepts/interface.html

What Is an Interface?

In English, an interface is a device or a system that unrelated entities use to interact. According to this definition, a remote control is an interface between you and a television set, the English language is an interface between two people, and the protocol of behavior enforced in the military is the interface between people of different ranks. Within the Java programming language, an interface(in the glossary) is a device that unrelated objects use to interact with each other. An interface is probably most analogous to a protocol (an agreed on behavior). In fact, other object-oriented languages have the functionality of interfaces, but they call their interfaces protocols.

The bicycle class and its class hierarchy defines what a bicycle can and cannot do in terms of its "bicycleness." But bicycles interact with the world on other terms. For example, a bicycle in a store could be managed by an inventory program. An inventory program doesn't care what class of items it manages as long as each item provides certain information, such as price and tracking number. Instead of forcing class relationships on otherwise unrelated items, the inventory program sets up a protocol of communication. This protocol comes in the form of a set of constant and method definitions contained within an interface. The inventory interface would define, but not implement, methods that set and get the retail price, assign a tracking number, and so on.

To work in the inventory program, the bicycle class must agree to this protocol by implementing the interface. When a class implements an interface, the class agrees to implement all the methods defined in the interface. Thus, the bicycle class would provide the implementations for the methods that set and get retail price, assign a tracking number, and so on.

You use an interface to define a protocol of behavior that can be implemented by any class anywhere in the class hierarchy. Interfaces are useful for the following:

Creating and Extending Interfaces

http://java.sun.com/docs/books/tutorial/java/interpack/interfaces.html

The Java programming language supports interfaces that you use to define a protocol of behavior that can be implemented by any class anywhere in the class hierarchy.
What Is an Interface?
This section defines the term "interface," shows you an example of an interface and how to use it, and talks about why you may need interfaces in your programs.
Defining an Interface
Defining an interface is similar to creating a new class. An interface definition has two components: the interface declaration and the interface body.
interfaceDeclaration {
    interfaceBody
}
The interfaceDeclaration declares various attributes about the interface such as its name and whether it extends another interface. The interfaceBody contains the constant and method declarations within the interface.
Implementing an Interface
To use an interface, you write a class that implements the interface. When a class claims to implement an interface, the class is claiming that it provides a method implementation for all of the methods declared within the interface (and its superinterfaces).
Using an Interface as a Type
When you define a new interface you are in essence defining a new reference data type. You can use interface names anywhere you'd use any other type name: variable declarations, method parameters and so on.
Warning! Interfaces Cannot Grow
If you ship public interfaces to other programmers, here's a limitation of interfaces that you should be aware of: Interfaces cannot grow. Let's look at why this is the case.
Summary
A summary of important concepts covered in this section.

http://java.sun.com/docs/books/tutorial/java/interpack/QandE/interfaces-answers.html

Question 1: What methods would a class that implements the java.util.Iterator interface have to implement?
Answer 1: next, hasNext, and remove

Question 2: What is wrong with the following interface?

public interface SomethingIsWrong {
    public void aMethod(int aValue) {
        System.out.println("Hi Mom");
    }
}
Answer 2: It has a method implementation in it. It should just have a declaration.

Question 3: Fix the interface in Question 2.
Answer 3:

public interface SomethingIsWrong {
    public void aMethod(int aValue);
}

Question 4: Is the following interface valid?

public interface Marker {
}
Answer 4: Yes. Methods are not required. Empty interfaces can be used as types and to mark classes without requiring any particular method implementations. For an example of a useful empty interface, see java.io.Serializable.

Inner Classes

http://java.sun.com/docs/books/tutorial/java/javaOO/innerclasses.html


Homework Assignments due 06 May:  

  1. p. 416, 2nd bullet
  2. p. 441, 2nd bullet

______________
course homepage      course calendar