CS102: Packages and Protection

Copyright © 1999, Kenneth J. Goldman

What is a package?


Package- a collection of classes and interfaces grouped together as a logical unit.

Packages have an API (Application Programmers Interface) which contains the public classes and interfaces and their public members. Think of Packages as another level in Layers of Java Components. (See Fig.1)

examples:
java.awt-Java's Graphics package for building user interfaces
java.io-Java's package for interacting with the file system

Why do we need Packages?

  1. Abstraction-as software packages grow larger, the sheer number of different classes can be overwhelming, so we try to organize them in some logical way. Class hierarchies do that to some extent, but often several hierarchies are related so the class hierarchy doesn't capture their relationships. So, packages provide an abstraction for logically related classes, and a way to think about building systems in layers. In Figure 1, we can think of the application as being built on top of java.lang, java.awt, and cs101.canvas. In reality, there is further layering, since java.awt builds on java.lang and cs101.canvas builds on both java.lang and java.awt. However, the application makes direct use of all three packages.

    Fig.1
    application
    java.lang java.awt cs101.canvas
    Java VM
    Operating System
    Hardware

    Basically, we group a bunch of classes and interfaces together and give them a name. Then, we begin to think of them as a unit, rather than a bunch of separate classes.

  2. Protection-Suppose we have some classes that we want to be publicly used (outside our implementation by other programmers), but there are other classes we want used only within our implementation(such as a ListItem class use be a public LinkedList class)

    Using Packages we can choose which classes may be used outside the package, and which ones can't. We can even say which classes can be extended outside the package and which methods can be overridden.

  3. Convenience-
    • Provides a way to manage large software projects. People agree on what the packages will provide, and different programmers can write to them.
    • Provides a way to augment the language withouth replacing it


  4. Name Space Control- Two classes can have the same name, provided they are in different packages. So, different programmers don't have to be concerned about using names already used in other packages.

Creating a Package

  1. Choose a name for the package (all lower case letters)
  2. Create a new directory (folder) with that name
  3. for each classe or interface that you want to be part of the package,
    1. Create a .java file in the directory you created
    2. put the line: package xxx;
      at the top of the file (first non-comment line)

    Note: Multiple classes can exist in one file, and all of them will be part of the package. Only one class in a file can be public, and the file must have the same name as that class. Directories may be nested to create "subpackages".

    For example, to create the canvas package inside the cs101 package we:
    • created a folder called canvas inside the cs101 folder
    • wrote the line: package cs101.canvas;
      at the top of each file.
    • made sure that each file had at most one public class and the file had the same name.

Using a Package:

To use a class or interface from a package, you can either:
  1. give its fully qualified name as in:
    screen = new cs101.canvas.CS101Canvas();

    OR

  2. import the class or interface at the top of the file, such as:
    import cs101.canvas.CS101Canvas;
    and then you can use just the class name:
    screen = new CS101Canvas();

    OR

  3. import all the classes and interfaces from the package as in:
    import cs101.canvas.*
    and then you can use any class in the package by its name, as in:
    screen = new CS101Canvas();
    screen.add(new Rect(10,10,50,50));


How Java finds class files:
The Compiler refers to a list of directory names (seperated by semicolons) called CLASSPATH, to find out where you want it to look for class files. For example;

CLASSPATH = .;C:Cafe\Java\Lib

Here the . means the current working directory and the second item (C:\Cafe\Java\Lib) is another directory to search from.

Java expects that the directory structure matches the package names inside of the directories in the CLASSPATH list.

What happens if you import two classes with the same name?
Depending onf the CLASSPATH, Java may find the "wrong" one first, and it will complain, for example, that the method you want to call on that object is not available, or there's no such constructor. (The error message may not tell you there's a name conflict.) To disambiguate in this situation, use the fully qualified class name.

Protection

There are four levels of protection:
  1. Public
  2. default ("package" or "friendly")
  3. protected
  4. private

Each class can either be public, meaning anyone can create one, or "friendly", meaning it can be instantiated only by methods of classes in the package.

Any of the 4 pretection levels can be chosen for any instance variable (data member), method, or class variable (static variable).

The following table summarizes what they imply:

access is available to: public proteted default private
All Classes X
All Subclasses X X
Classes in the Same Package X X X
The Class Itself X X X X


Note:Within a project, all classes are considered to be in the same package (i.e., anything not imported is together in the "default package")

Making Choices About Protection:

When I'm creating a package, how do I decide which level of protection is appropriate?

Short Answer: Try to limit access as much as you can without preventing reasonable use.

Long Answer:
Suppose you're creating a casino package that could be used by programmers wanting to write applications for games of chance.

In your package, you might provide:
  • Dice - that could be rolled
  • Cards - Ace through King in 4 suites plus Jokers
  • Decks of Cards - That can be shuffled and dealt
  • Wheels with labeled & colored pieces - that can be spun
  • Card Hands - That hold some number of cards
  • Slot Machines - The containg collections of wheels
  • ...

At first, it may sem like all classes should be public, but what we listed here are the things we would expect the user of the package to want (those should be public). But, there will be other classes (such as, perhaps, a ListItem class for a circular list) that are part of the internal representation of the public classes. These internal items should not be public for two reasons:
  1. The users doesn't care about them, so making them public just clutters up the user's view of the package (the API)
  2. Making them public ties your hands. It can prevent you from making changes to the internal representation later, since users of the package may depend on those classes being there.

So, the rule of thumb for classes is:
If the user of the package needs it, make it public, but if its part of the internal representation, keep it at the default ("package") level.

What about methods and instance variables?

The reasoning is similar, but there are more protection levels to choose from.

Here's a rule of thumb for methods & instance variables:

if (access from outside this class could falsify a representation invariant){
make it private so it's accessible only by this class.
for variables, control external access using accessor/mutator (get/set) methods.
(Note: Most of the time, instance variable should be private.)
}
else if (access is required by the package user){
make it public so it's part of the API
}
else if (access would be useful for subclasses, and would not expose the represenatation to overly restrict future implementations){
make it protected so subclasses can use/override it
}
else{
use the default ("friendly" or "package") protection
}

For example, in the casino package, what would you do with...
the method in roll() in the Dice Class? public (part of API)

the instance variable numCardsLeft in Deck Class? private (with public "get" accesor)

the method next() in the class ListOfCards? package (assuming ListOfCards is not public & only deck uses it.)

the instance variable suit in class Card? private (wouldn't want it changed) OR public final because you don't want to change it.

Final can also be used in conjunction with protection.

if a class is final, you can't extend it & all its methods are automatically final.
if a method is final, you can't override it.

Also, when a method is final, the compiler can "inline" it, meaning that it puts the body of the method in place of the call to avoid the runtime overhead involved in creating an activation record & copying parameter values (but this is a bad idea if the method is large because the class files get large).