Java Tech: The Sweet Song of the BlueJ, Part 1
| ||||||||
I recently discovered a Java product called BlueJ. This product, symbolized by the image of a blue jay, is used to teach object orientation to students. In contrast to the harsh-sounding blue jay (which happens to be a member of the crow family), BlueJ is anything but harsh. This simple yet powerful product presents a short learning curve, which is ideal for students.
Welcome to the first installment in a two-part series that explores BlueJ. This article introduces the product, reveals its reason for being (Java instructors, take note), shows how to install BlueJ, and takes a tour of BlueJ's GUI. The article climaxes with an example that illustrates several BlueJ features.
Note: This series is based on BlueJ version 2.0.4 and J2SE 5.0 running on the Windows 98 SE platform.
BlueJ is an integrated Java environment that has been designed to teach object orientation with the Java language. BlueJ is based on the earlier Blue system, a programming language and integrated environment. BlueJ, an almost identical environment to Blue, replaces the Blue language with Java.
BlueJ provides a project manager and an editor. It relies upon an installed Java 2 Standard Edition software development kit for compilation, debugging, and other facilities. Tools are fully integrated in BlueJ: compilation from within the editor, compiler error message display in the editor, setting breakpoints in the editor, and so on.
BlueJ was developed to provide an appropriate environment for
teaching object-orientation concepts to students. Unlike many other
environments, BlueJ emphasizes classes and objects as its basic
units of interaction. Students are not required to learn Java's
public static void main(String [] args) method, or
worry about input/output prior to creating and interacting with
objects: BlueJ takes care of those tasks on behalf of the student.
Regarding main(), BlueJ's developers believe that
introducing students to that method first is problematic. Why begin
teaching object orientation by introducing a method that is
essentially procedural? The BlueJ team discovered that this
approach only confuses students, who must also learn about arrays
right from the start. They found that it was better to first focus
on classes and objects, and introduce the main()
method, input/output, and arrays after the student becomes more
comfortable with Java.
BlueJ is easy to use; students can begin working with BlueJ without needing a lengthy introduction to the environment. BlueJ lets students visually and interactively create classes and interconnect them. Students can then instantiate objects from those classes, invoke methods, specify arguments to those methods via dialogs, view return values via dialogs, and visually inspect object state. This product is freely available, a benefit to students who cannot afford costly licenses (BlueJ cannot be sold for profit).
BlueJ originated at Monash University in Melbourne, Australia. It is currently being maintained as a joint project among Deakin University, the University of Kent, and the University of Southern Denmark.
BlueJ is available for Windows, the Mac OS, Linux/Unix, and other operating systems. Regardless of the operating system, J2SE 1.4 or higher must be installed. Because BlueJ relies on tools made available via the J2SE SDK, installing only the J2SE JRE is not sufficient.
For Windows platforms, the BlueJ distribution is contained in
file bluejsetup-xxx.exe, where
xxx is a version number. For example, the BlueJ
version 2.0.4 distribution is contained in
bluejsetup-204.exe.
The installer portion of the Windows BlueJ distribution lets you
select the directory into which to install BlueJ. It also presents
the option to install a shortcut into the Start menu and on the
desktop. When the installer completes, you'll find
bluej.exe in the installation directory. This program
starts BlueJ.
When BlueJ first runs, it searches for a J2SE 1.4 or higher SDK. If it finds more than one version, BlueJ presents its BlueJ Launcher dialog box, which lets you select the desired SDK. If BlueJ isn't able to find a suitable SDK, this dialog box lets you search for the SDK.
After installing BlueJ with a specific J2SE SDK, you can change
to another SDK version by including bluej.exe's
/select command-line option the next time you run that
program. In response, the BlueJ Launcher dialog box appears.
Note: You can install different versions of BlueJ and associate a different installed version of the J2SE SDK with each BlueJ version. For example, you can associate BlueJ 2.0.1 with J2SE 1.4.2 and associate BlueJ 2.0.4 with J2SE 5.0.
BlueJ manages Java-based projects. The current project is
revealed in its main window. In Figure 1, the main window
presents people--an example project that ships with
BlueJ--as the current project.
Figure 1: BlueJ's main window identifies the people
project
The main window divides into five sections: menu bar, project tool bar, class diagram, object bench, and message area. The menu bar offers Project, Edit, Tools, View, and Help menus:
people project shown in Figure 1.The project tool bar, located on the left side of the main
window and just below the menu bar, consists of four buttons that, respectively, introduce new classes into the current project,
introduce "extends" or "implements" dependencies between classes,
introduce "uses" dependencies between classes (for example, a
Library class uses a Book class by
implementing an array of Book objects), and compile
the entire project.
The class diagram, on the right side of the project tool bar, graphically displays the current project. It presents a project description note icon, class icons, and dependency arrows:
<<abstract>> or
<<interface>> just above the name. The
icon of the current class (that is, the class that will be compiled
when you choose Compile Selected from the Tools menu) is identified
with a darker border and a pair of diagonal stripes in the
lower-right corner of its icon. If a class has not been compiled,
the entire lower-right area consists of diagonal stripes.Staff and Person,
and between Student and Person.
Person is the superclass. Dashed lines indicate "uses"
relationships. Each class pointed to by the arrow is used by the
class on the other end of the dashed line. For example, Figure 1
shows that Person is used by Database. In
other words, Database references Person
in its source code.Right-click the mouse on a class icon and a pop-up menu appears. This menu offers various options, including compilation. If a class's source code has not been compiled, you can compile that source code by choosing Compile from the pop-up menu.
The object bench, toward the bottom of the main window,
identifies various objects that have been created. Objects are
created by right-clicking a compiled class's icon, selecting one of
the "new" constructor menu items from the pop-up menu, and
responding to dialogs that let you name the object and (if
appropriate) pass arguments to the constructor. Figure 1 shows a
single staff1 object icon on the object bench. The
object represented by that icon was created by choosing the top
menu item from the pop-up menu.
A single-line message area appears below the object bench. As you work with BlueJ, various messages appear in this area.
|
Let's use BlueJ to construct a simple payroll application. This application introduces several BlueJ features and will get us comfortable working in this Java environment.
Our payroll application will consist of the abstract class
Employee, the concrete subclasses CEO and
Salesperson, and the concrete driver class
RunPayroll. Although this latter class provides a
main() method for generating a payroll, we'll create
and interact with CEO and Salesperson
objects prior to looking at RunPayroll.
Start BlueJ. Before we introduce classes, we need a project.
From the Project menu, select New Project. A New Project
dialog box appears. Choose an appropriate directory that will
contain the project directory, and enter payroll as
the project/directory name.
The main window's title bar identifies payroll as
the current project. Except for the project description note icon,
the class diagram is empty. If you examine the payroll
directory, you will find two files: bluej.pkg and
README.TXT. The first file contains project settings
and the second file contains a template for documenting the
project.
We should document the project, to assist people wanting to use our project, before introducing any classes. That way, we won't forget to do so later. Double-click the project description note icon and, via the resulting editor window, enter the project title, project purpose, project version or date, instructions for starting the project, project authors, and additional user instructions. Figure 2 reveals the documentation I've chosen.
Figure 2: Document a project to help others learn about and use
that project
The editor window presents a changed/saved indicator in the lower-right corner. This indicator lets you know if there are changes that need to be saved. You can periodically save changes (while performing a lengthy edit) by selecting Save from the Class menu. For now, exit the editor by selecting Close from the Class menu, or by clicking the X button on the right side of the title bar. In response, the editor automatically saves changes.
We're ready to introduce our first class:
Employee. Click the New Class... button on the
project tool bar. A Create New Class dialog box appears. Enter
Employee in the dialog box's Class Name field. Also,
select the Abstract Class radio button in the Class Type group.
Figure 3 presents this dialog box with our choices.
Figure 3. The Create New Class dialog box lets you choose a
class name and a class type
After clicking the OK button, an Employee icon, with
<<abstract>> above its name, appears in
the class diagram. Because we next need to enter source code into
the Employee class, right-click this icon and select
Open Editor from the pop-up menu, or double-click that icon. Either
way, Figure 4 shows the resulting editor window with a class
template for Employee.

Figure 4. Class templates provide skeletal source code for
classes
Employee's class template provides skeletal source
code that must be modified. Key in the source code below (making
appropriate changes to the skeletal source code) and then exit the
editor.
/**
* Abstract class Employee - the superclass for
* CEO, Salesperson, and so on.
*
* @author (Jeff Friesen)
* @version (1.0)
*/
public abstract class Employee
{
// employee name
private String name;
/**
* Construct an employee.
*
* @param name employee name
*/
public Employee (String name)
{
this.name = name;
}
/**
* Retrieve the employee's name.
*
* @return employee's first and last names
*/
public String getName ()
{
return name;
}
/**
* Calculate employee's payment.
*
* @return payment owed to employee
*/
public abstract double payment ();
}
|
For our purposes, an Employee is nothing more than
a name. This class is abstract to reflect the abstract
payment() method: different kinds of employees can be
paid in different ways (weekly, weekly plus commission, and so
on).
Right-click the Employee icon and select Compile from the
pop-up menu. A Compiling... message appears in the message area.
If a syntax error is detected, the editor window appears, that
window highlights the line containing the syntax error, and the
syntax error is identified in the editor window's status area (at
the bottom of the window). For example, if I lowercase
String in private String name;, I receive
the syntax error shown in Figure 5.

Figure 5: A class named string does not
exist
Students learning Java will probably have trouble understanding syntax errors. To help them in this situation, BlueJ's editor window provides a "?" button. Click that button and a Message dialog box appears. That dialog box provides further information about the nature of the syntax error. The Message dialog box in Figure 6 suggests that a class name may have been incorrectly spelled.
Figure 6: The Message dialog box helps students more quickly
discover the cause of a syntax error
Fix the error, close the editor, and recompile. If there are no more errors, a "Compiling...Done" message appears in the message area. Furthermore, the diagonal stripes (apart from the two diagonal stripes that indicate the current class) disappear from the lower half of the compiled class's icon.
There's not much we can do with an abstract class. Therefore,
we'll create a CEO class and connect it to
Employee:
CEO in the Class
Name text field. Make sure the default Class radio button is
selected prior to clicking OK. A CEO class icon appears to the
right of the Employee class icon in the class diagram.CEO and drag it below Employee. Then click the project
tool bar's solid arrow button. The message area tells you to select
the subclass. Click CEO. The message area next tells you to select
the superclass. Click Employee. A solid arrow pointing from the CEO
subclass to the Employee superclass appears.After drawing the arrow, BlueJ makes this connection in
CEO's source code, as shown in Figure 7.
Figure 7. The Employee/CEO class
hierarchy has been established through extends
Employee
As with Employee, CEO's class template
provides skeletal source code that must be modified. Double-click
the CEO icon, key in the source code below (making the appropriate
changes to the skeletal source code), and then exit the editor.
/**
* CEO describes a chief executive officer. This
* employee receives a salary based on a weekly
* rate.
*
* @author (Jeff Friesen)
* @version (1.0)
*/
public class CEO extends Employee
{
// CEO weekly salary
private double weeklySalary;
/**
* Construct a CEO.
*
* @param name CEO's name
* @param weeklySalary CEO's weekly salary
*/
public CEO (String name, double weeklySalary)
{
super (name);
setWeeklySalary (weeklySalary);
}
/**
* Establish the CEO's weekly salary.
*
* @param weeklySalary payment owed to CEO each
* week
*/
public void setWeeklySalary
(double weeklySalary)
{
this.weeklySalary = weeklySalary;
}
/**
* Calculate CEO's payment.
*
* @return payment owed to CEO each week
*/
public double payment ()
{
return weeklySalary;
}
}
|
Compile this class's source code. Assuming compilation succeeds,
let's create a CEO object from our compiled
CEO class. We can then test its methods to make sure
that everything works. Right-click the CEO icon and select the "new
CEO(String name, double weeklySalary)" constructor menu item, shown
in Figure 8.
Figure 8. A compiled class's constructors appear at the top of
its pop-up menu
In response to that menu item, the Create Object dialog box
appears. Enter everything shown in Figure 9 (including the double
quotes around John Doe) and click OK.
Figure 9: The Create Object dialog box lets you name an object
and specify arguments for its constructor
A theBoss object icon appears on the object bench. Right-click
that icon. Figure 10 reveals a menu from which you can invoke
inherited methods, invoke CEO's payment()
and setWeeklySalary() methods, inspect object state,
and remove the object.
Figure 10. An object icon's pop-up menu lets you invoke that
object's methods, inspect its state, and more
Let's invoke the payment() method, by selecting the
"double payment()" menu item. BlueJ runs that method and displays
its return value in a Method Result dialog box. As Figure 11
illustrates, that value is 2000--the weekly salary.

Figure 11. The Method Result dialog box displays a method's
return value
The Method Result dialog box presents Inspect and Get
buttons for inspecting a returned object and getting a new object,
based on the returned object's type to the object bench. Both
buttons are disabled because they make no sense in relation to
primitive types, such as double. Close the dialog
box.
Select the "inherited from Employee" menu item (see Figure 10)
followed by the "String getName()" menu item from the resulting
submenu. This executes the getName() method in the
Employee portion of our theBoss object.
Figure 12 reveals the expected "John Doe" string.
Figure 12. The Method Result dialog box no longer disables the
Inspect and Get buttons
Unlike in the previous Method Result dialog box, the Inspect
and Get buttons are enabled. We can use them to inspect or get a
new "John Doe" String object. Let's
inspect the object by clicking Inspect. Figure 13 shows the
resulting Object Inspector dialog box.
Figure 13. The Object Inspector dialog box displays the values
in an object's instance fields
In addition to presenting instance field values, the Object
Inspector dialog box provides a "Show static fields" button. Click
this button to view the values of a class's static fields (which
are shared by all objects created from that class). Because
String contains no static fields, don't count on
seeing them.
The Object Inspector dialog box presents reference field values
differently than the values of primitive type fields: curved arrows
indicate references. Double-click the arrow or click the Inspect
button (assuming that private char [] value is
highlighted) to inspect the array of characters object. Figure 14
presents a partial view of that object.

Figure 14. A partial view of the array of characters
object
|
Finally, let's take a look at the state of our
theBoss object. Select the Inspect menu item from
the pop-up menu previously shown in Figure 10. Figure 15's Object
Inspector dialog box reveals the contents of theBoss's
instance fields.
Figure 15. The complete state of our theBoss
object
Now that we've constructed the Employee and
CEO portions of our payroll application, let's turn
our attention to Salesperson. Introduce a Salesperson
icon into the class diagram and connect that icon to the Employee
icon. You've already seen how to do this with the CEO icon. Now
open the editor by double-clicking the Salesperson icon and enter
the source code below:
/**
* Salesperson describes an employee that sells
* the company's products. This employee receives
* a salary based on a weekly rate and a
* commission for each sold product.
*
* @author (Jeff Friesen)
* @version (1.0)
*/
public class Salesperson extends Employee
{
// salesperson weekly salary
private double weeklySalary;
// salesperson commission
private double commission;
// number of sold products
private int numProductsSold;
/**
* Construct a Salesperson.
*
* @param name salesperson's name
* @param weeklySalary salesperson's weekly
* salary
* @param com salesperson's commission for
* each sold product
* @param nsp number of sold products
*/
public Salesperson (String name,
double weeklySalary,
double com, int nsp)
{
super (name);
setWeeklySalary (weeklySalary);
setCommission (com);
setNumSoldProducts (nsp);
}
/**
* Establish the salesperson's weekly salary.
*
* @param weeklySalary payment owed to
* salesperson each week
*/
public void setWeeklySalary
(double weeklySalary)
{
this.weeklySalary = weeklySalary;
}
/**
* Establish the salesperson's commission.
*
* @param com amount of additional money
* salesperson receives for each sold
* item
*/
public void setCommission (double com)
{
commission = com;
}
/**
* Establish the number of sold products.
*
* @param nsp number of sold products
*/
public void setNumSoldProducts (int nsp)
{
numProductsSold = nsp;
}
/**
* Calculate salesperson's payment.
*
* @return payment owed to salesperson each
* week
*/
public double payment ()
{
return weeklySalary + commission *
numProductsSold;
}
}
Compile Salesperson, create an object from this
class, invoke methods, and inspect object state. This exercise will
reinforce what you've previously learned.
We have almost everything we need for our payroll application.
The final piece is a RunPayroll class whose
main() method drives the application. That class's
source code appears below.
/**
* Generate the weekly payroll for all employees.
*
* @author (Jeff Friesen)
* @version (1.0)
*/
public class RunPayroll
{
public static void main (String [] args)
{
Employee [] employees =
{
new CEO ("John Doe", 2000),
new Salesperson ("Jane Doe", 600, 50,
20)
};
for (int i = 0; i < employees.length; i++)
System.out.println (employees [i].
getName () +
" makes " +
employees [i].
payment () +
" this week.");
}
}
RunPayroll references Employee,
CEO, and Salesperson. This suggests a
"uses" relationship between RunPayroll and these
classes. After creating a RunPayroll icon, employ the dashed-arrow
button on the project tool bar to introduce three separate dashed
arrows into the class diagram, where each arrow points from
RunPayroll to each of the other class icons. Enter the above source
code into RunPayroll and compile that class. Figure 16
shows the resulting class diagram.
Figure 16. Dashed arrows identify RunPayroll's
referenced classes
Figure 16 also shows a pop-up menu resulting from a right-click
on the RunPayroll icon. From that menu, select the "void
main(String [] args)" menu item. You are greeted by Figure 17's
Method Call dialog box.

Figure 17. The Method Call dialog box lets you pass arguments to
methods
We don't have any String arguments to pass to the
main() method. If we did, we would specify those
arguments as a comma-delimited list between the brace characters.
Click the OK button instead. BlueJ's terminal window appears.
According to Figure 18, that window reveals our payroll
application's output.

Figure 18. BlueJ's terminal window displays payroll
output
|
Are you planning to teach Java? Consider using BlueJ. This
integrated Java environment has been designed to teach object
orientation with the Java language. BlueJ emphasizes classes and
objects right from the start; it doesn't confuse students by first
focusing on the procedural main() method, arrays, and
input/output.
BlueJ is easy to install and run. It requires an installed J2SE
SDK (version 1.4 or higher). If you ever need to switch from one
SDK version to another version, include bluej.exe's
/select command-line option when starting BlueJ.
BlueJ offers a simple yet capable GUI divided into menu bar, project tool bar, class diagram, object bench, and message area. We made extensive use of this GUI as we developed and tested an example payroll application.
I have some homework for you to accomplish:
FactoryWorker class that
subclasses Employee. Factory workers receive a payment
based on a fixed amount per item they create. For example, a worker
receives five dollars for each created item. If the worker creates
100 items in a week, the worker's payment is 500 dollars. Extend
RunPayroll to include FactoryWorker.Next time, "Java Tech" completes this series by investigating BlueJ's debugging, documentation generation, and JAR-packaging capabilities. You also learn how to configure BlueJ and discover a useful feature known as the code pad.
The previous "Java Tech" article presented you with some challenging homework on language lessons. Let's revisit that homework and investigate solutions.
clone() method to invoke an
overridable method?
It is not okay for the clone() method to invoke an
overridable method, because the overriding method might modify
object state while the clone() method executes, and
these changes could damage either the object being cloned, the
cloned object, or both objects. Let us see how this damage might
occur, beginning with an examination of the classes below:
class Parent implements Cloneable
{
public Parent clone ()
throws CloneNotSupportedException
{
System.out.println ("Superclass clone() " +
"method invoked");
someMethod ();
return (Parent) super.clone ();
}
void someMethod ()
{
System.out.println ("parent someMethod() " +
"invoked");
}
}
class Child extends Parent
{
ArrayList<String> al;
Child ()
{
al = new ArrayList<String> ();
al.add ("One string");
}
public Child clone ()
throws CloneNotSupportedException
{
System.out.println ("Subclass clone() " +
"method invoked");
System.out.println ("ArrayList size " +
"before " +
"super.clone() = " +
al.size ());
Child c = (Child) super.clone ();
System.out.println ("ArrayList size " +
"after " +
"super.clone() = " +
al.size ());
return c;
}
void someMethod ()
{
System.out.println ("child someMethod() " +
"invoked -- clearing " +
"array");
al.clear ();
}
}
Child's clone() method outputs the
size of an ArrayList, invokes
super.clone(), and then outputs the
ArrayList's size once more. Each output operation
symbolizes work needed to create a clone. The
super.clone() method call invokes
Parent's clone() method. In turn, that
method invokes the overridable someMethod().
Child's version of that method clears the
ArrayList. If we were to execute Child c1 = new
Child ();, followed by Child c2 = c1.clone ();,
we would see the output below. This output indicates that
Child's state has changed, as a result of the
super.clone() method call.
Subclass clone() method invoked
ArrayList size before super.clone() = 1
Superclass clone() method invoked
child someMethod() invoked -- clearing array
ArrayList size after super.clone() = 0
This example is trivial. Perhaps you might share your own
experiences with failure caused when a superclass
clone() method invokes an overridable method.
Interfaces should not be used to only export constants, because
that usage violates the purpose for interfaces--they are types
that describe auxiliary capabilities of the classes that implement
them. For example, java.util.Iterator is an interface
type whose implementing classes serve as iterators, in addition to
their main reasons for existence. Constant interfaces have nothing
to do with types; they exist to save time entering source code.
Fewer keystrokes are needed to refer to an interface-exported
constant (only the constant name needs to be entered, after
implementing the interface once) than a class-exported constant
(the class name, a period character, and the constant name need to
be entered each time the constant must be specified).
Dependence on constant interfaces can lead to maintenance problems. As time passes, a class will evolve; one or more of the interface's constants may no longer be required. However, the class still needs to implement the interface (including all of the constants), to maintain binary compatibility. This can lead to confusion. Also, we end up polluting the class's namespace and the namespaces of any subclasses with the constants. This gets really bad if we create a single interface that conveniently declares all of our constants in one place. Imagine hundreds of constant names polluting the namespace.
J2SE 5.0 provides a better alternative to constant interfaces: static imports. This language feature lets you refer to the static members of a class without having to qualify those members with the class name. Consider the following static imports:
import static java.lang.Math.*; // import all static members
// or, to import specific members only
import static java.lang.Math.PI; // import static member PI only
import static java.lang.Math.cos(); // import static member cos() only
You can now specify sin() instead of
Math.sin(), PI instead of
Math.PI, and cos() instead of
Math.cos(). Constant interfaces have gone the way of
the dinosaur.
Jeff Friesen is a freelance software developer and educator specializing in Java technology. Check out his site at javajeff.mb.ca.
|
|