September 16, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Packaging Objects to Preserve Encapsulation

  • September 7, 2005
  • By Matt Weisfeld
  • Send Email »
  • More Articles »

Packages Explained

One of the major features provided by the various Java releases was that of packages. Many structured programmers are familiar with the concept of code libraries. In some ways, packages can be thought of in the same way as code libraries - but they have many important differences. Perhaps the best way to describe a package is to actually show packages. This can be easily accomplished by inspecting a file called rt.jar.

Remember that a Java program is run inside of a virtual machine. The operative term here is virtual. When you run a Java application you do so by invoking the Java executable java.exe. After you install the SDK, you can find the java.exe file in the bin directory of the Java installation as seen in figure 5.



Click here for a larger image.

Figure 5.

The great thing about using a virtual machine, and specifically in the case of Java, is that your Java code can be run on any computer that has a virtual machine installed. The not-so-great thing is that there are computers that do not have a Java virtual machine installed. Thus, if you ship your application to a computer without a resident Java virtual machine, that computer will not be able to run your application. Another problem, and this can get somewhat sticky, is that the target computer may have a version of the SDK that is different from the version that you developed the application with. So, you may ask how we can safely ship an application if we have 2 unknowns:

  1. Don't know if the target computer has Java installed.
  2. If it does, what version of the SDK does it have installed?

You may have guessed that the way to solve this problem is to actually ship the version of the JVM with your application. In this way, you know that the application will run with the same version of the JVM that you developed it with.

Some may find it odd that you would think of shipping a virtual machine with the application; however, this is a viable solution because you don't need to ship the entire SDK.

You may have noticed in figure 5 that the SDK contains several directories (some installation may have different directory names):

  • bin
  • demo
  • include
  • jre
  • lib

The virtual machine java.exe is, as we have seen, in the bin directory. Many of the other directories include the tools you will need for development. However, all that you need to ship with the application is a subset of the SDK. The directory jre contains all this material you need to execute a Java application. The name jre stands for java runtime environment. The jre can be bundled with your application to ensure that it will run on a target machine.

Inside the jre directory is a file called rt.jar that we can use to illustrate our package example. Figure 6 shows the jre with the file rt.jar highlighted.

Figure 6

The extension jar stands for Java Archive. The great thing about these jar files is that they are built on zip technology (just like WinZip). In fact, you can actually use Winzip to open a jar file as seen in figure 7.

Figure 7

The only visible difference between a regular zip file and a jar file is the first file Manifest.mf which designates this as a Java jar file.

For example, when you want to develop Java Swing applications you must include the rt.jar file in your classpath and then import the Swing package that is included in the rt.jar file. You can easily find the Swing package inside the rt.jar file as seen in figure 8.

Figure 8

In figure 8, the class Boxview.class is selected. The file Boxview.class is part of the swing package and you can see that the packages are identified on the far right under the Path column.

Using packages is how Java bundles the development tools as well as the runtime environment. We can create our own packages to make development much more secure and productive. With this background on packages complete, we can now see how to create our own packages to solve the problem we encountered above when inheritance appears to break encapsulation.

Packaging Solution

Let's create a design that will solve the problem we began this discussion with. Make the following changed to Mammal as seen in listing 8.

// Class Mammal
   package Mammals;            // add this line
    public class Mammal {
    protected String color;
    public void growHair(){
        System.out.println("Hair Growing");
    }
}

Listing 8

The line in red creates a package called Mammal. Once this is created we can use and distribute this library and we can place the appropriate class files inside.

A Java package, to a certain degree, equates to a directory and its corresponding directory structure. Thus, to physically create our Mammals package we can simply create a sub-directory called Mammals. Inside your application directory, which here is called Packaging, create a subdirectory called Mammals and move the Mammal class inside this directory. Now let's compile the project again and see what happens. Listing 9 shows how you need to adjust your compilation syntax. Note that you must include the directory path for the new package.

c:j2sdk1.4.2_05binjavac -classpath . ./Mammals/Mammal.java
c:j2sdk1.4.2_05binjavac -classpath . Dog.java

Listing 9

When we run this we see that the Dog class cannot find the Mammal source code to extend it - just as we expected since we moved the Mammal.java file. This can be seen in figure 9.

Figure 9

To address this problem we simply import the Mammal package in the Dog class as can be seen in the red line in listing 10.

//Class Dog
import Mammals.*; 
public class Dog extends Mammal{
 private int barkFrequency;
 public void bark(){
  System.out.println("Dog Barking"); 
  color = "blue"; 
 }
}

Listing 10

Listing 11 shows the necessary added line in the Packaging class.

import Mammals.*; 
public class Packaging {
 public static void main (String args[]){
  Mammal mammal = new Mammal();
  mammal.growHair();
  mammal.color = "blue";
    }
}

Listing 11

This deals successfully with the problem of the Dog class finding the Mammal class; however, an error message appears when the Package class is compiled as can be seen in figure 10.

Figure 10

The error message states that the color attribute is protected and thus cannot be accessed from the Package application. Actually, this is exactly the behavior that we want! Now the color attribute can be successfully accessed from the Dog class (which is a valid inheritance relationship) - but not from the application (which we want to avoid like the plague per our encapsulation rule).

Protected Status

There is one more issue to explore in this discussion of packages. There is actually another type of access modifier - one we will call default protected, or package protected.

Take a look at listing 12 and the red line of code.

// Class Mammal
package Mammals;   
public class Mammal {
 String color; 
 public void growHair(){
  System.out.println("Hair Growing");
 }
}

Listing 12

Notice in this case that the color attribute appears to have no access modifier; however, it is provided a default access modifier. This default modifier is basically a protected modifier within the package only - it excludes subclasses. Thus, when we really do use the protected access modifier, this includes the inheritance hierarchy tree. Perhaps we can call this inheritance protected.

When we compile with this version of the Mammal class we get the results seen in figure 11.

Figure 11

This is because the Dog class is not in the Mammals package. We can solve this problem by including Dog in the Mammals package. Take a look at the red line of code in listing 13.

//Class Dog
package Mammals; 
public class Dog extends Mammal{
 private int barkFrequency;
 public void bark(){
  System.out.println("Dog Barking"); 
  color = "blue"; 
 }  
}

Listing 13

When we compile this we get the desired result. Dog is now part of the Mammals package so it has access to the attributes in Mammal; however, the application Packaging cannot access them.

Conclusion

At first, the encapsulation/inheritance dilemma covered in the past 2 articles may seem confusing. In fact, you may start to wonder if the whole paradigm is simply too intricate for its own good. Yet, once you finally do understand the issues behind these examples, they really do become interesting intellectual exercises and useful development techniques.

We have seen that at one level encapsulation and inheritance do conflict with each other. However, using Java packaging, you can successfully enforce both the inheritance rule and the encapsulation rule.

References

Gilbert, Stephen, and Bill McCarty: Object-Oriented Design in Java. The Waite Group, 1998.

Meyers, Scott: Effective C++. Addison-Wesley, 1992.

Tyma, Paul, Gabriel Torok and Troy Downing: Java Primer Plus. The Waite Group, 1996.

Ambler, Scott: The Object Primer. Cambridge University Press, 1998.

Jaworski, Jamie: Java 1.1 Developers Guide. Sams Publishing, 1997.

www.javasoft.com

About the Author

Matt Weisfeld is a faculty member at Cuyahoga Community College (Tri-C) in Cleveland, Ohio. Matt is a member of the Information Technology department, teaching programming languages such as C++, Java, and C# .NET as well as various web technologies. Prior to joining Tri-C, Matt spent 20 years in the information technology industry gaining experience in software development, project management, business development, corporate training, and part-time teaching. Matt holds an MS in computer science and an MBA in project management. Besides the first edition of The Object-Oriented Thought Process, Matt has published two other computer books, and more than a dozen articles in magazines and journals such as Dr. Dobb's Journal, The C/C++ Users Journal, Software Development Magazine, Java Report, and the international journal Project Management. Matt has presented at conferences throughout the United States and Canada.





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 



Rocket Fuel