Creating Packages

 

It may surprise you that we could create our own class and java could make use of it.  When we declared and/or instantiated an object of a TimeBasics type, java automatically looked in the program's directory for a TimeBasics.class.  But developers don't want to always locate everything accessing a class in the same directory.  You might have two or more user defined classes that you want to use in a given Java program.  Making sure all of these classes are compiled in the program's directory is a lot of useless work!

Fortunately, in Java, you can create packages that can be compiled to a particular directory and then accessed using an import statement in other programs.  This webpage addresses how this can be done.

All should be located further along the path

c:\j2sdk1.4.0\jre\classes

 

You are certainly likely to want to add more subdirectories to this path, but this is putting you in the direction where they should be located.  You are likely to need to create this classes directory along that path.  This is the default path for the location of user-defined classes that are being packaged. 

For this particular program you also need to create a subdirectory of this directory called javaPackages and a subdirectory of this called TimeClasses.  I make use of the directory javaPackages along this path to contain directories for each of my packages.  This is illustrated in the following image.

 

 

Now the code for TimeBasics.java should be altered slightly to include a package statement.  Notice the package statement.

package javaPackages.TimeClasses;

 

package javaPackages.TimeClasses;
import java.text.DecimalFormat;

// This class maintains the time in a 24 hour format
// and has a method to convert this to an AM/PM scale


public class TimeBasics extends Object
{

private int hour; // from 0 to 23
private int minute; // from 0 to 59
private int second; // from 0 to 59

// The TimeBasics constructor initializes each instance variable (instantiation of an object) to zero.
// It also ensures that each TimeBasics object starts in a state consistent with its specifications

public TimeBasics( )
{

setTime(0,0,0);

}

// Set a new time using military/universal representation.
// Perform validity checks on the data.
// Set invalid values to zero to ensure consistency.

public void setTime( int h, int m, int s)
{

// if hour number is outside the acceptable range set it to 0
if (h < 0 || h >= 24) hour = 0;
else hour = h;
// if minutes number is outside the acceptable range set it to 0
if (m < 0 || m >= 60) minute = 0;
else minute = m;
// if seconds number is outside the acceptable range set it to 0
if (s < 0 || s >= 60) second = 0;
else second = s;

}

// This method converts a time to a string in military/universal format
public String toUniversalString()
{

DecimalFormat twoDigits = new DecimalFormat("00");

return twoDigits.format(hour) + ":" + twoDigits.format(minute) + ":" + twoDigits.format(second);

}

// Convert string into AM/PM time format
public String toAMPMString( )
{

String AMPM;
int tempHour;
// setting up a decimal format to make certain numbers
// have two digits with no decimal places
DecimalFormat twoDigits = new DecimalFormat("00");
// checking for noon and midnight
if (hour == 12 || hour == 0)

tempHour = 12;

// if not noon or midnight then
// cast hour into correct number of hours
// since noon or midnight

else

tempHour = hour % 12;

// determine whether it is AM or PM by hour
if (hour < 12)

AMPM = "AM";

else

AMPM = "PM";

return tempHour + ":" + twoDigits.format(minute) + ":" + twoDigits.format(second) + AMPM;

}

public String echoInput( )
{

DecimalFormat twoDigits = new DecimalFormat("00");

return twoDigits.format(hour) + ":" + twoDigits.format(minute) + ":" + twoDigits.format(second);

}

}

 

This is the only change that is required to the program .

In order to compile this class and locate it appropriately along the path you need to give the command

javac -d C:\j2sdk1.4.0\jre\classes TimeBasics.java

This will cause the TimeBasics.class to be located along the path

C:\j2sdk1.4.0\jre\classes\javaPackages\TimeClasses\

because of the path specified in the compilation command and the package statement package javaPackages.TimeClasses; as you can see in the following image.

 

 

Now to get our TimeBasicsTest to compile and be able to access the TimeBasics class you need to include an additional statement.

import javaPackages.TimeClasses.TimeBasics;

This will allow you to have the TimeBasicsTest be in any other directory and still appropriately access the TimeBasics class.  The revised code for TimeBasicsTest.java follows.

 

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javaPackages.TimeClasses.TimeBasics;

public class TimeBasicsTest extends JApplet implements ActionListener
{

// declare GUI components
JLabel lblHoursInput;
JTextField txtHoursInput;
JLabel lblMinutesInput;
JTextField txtMinutesInput;
JLabel lblSecondsInput;
JTextField txtSecondsInput;
JLabel lblEchoInput;
JTextField txtEchoInput;
JLabel lblUniversalTime;
JTextField txtUniversalTime;
JLabel lblAMPMTime;
JTextField txtAMPMTime;
JLabel lblClickToCompute;
JButton compute;
JPanel panInterface;
// declare four global variables related to inputs
boolean validInput;
int hoursInput = 0;
int minutesInput = 0;
int secondsInput = 0;

public void init( )
{

JPanel panInterface = new JPanel();
panInterface = createGUI();

setContentPane(panInterface);

}

public void actionPerformed(ActionEvent userClick)
{

if (userClick.getSource( ) == compute)
{

// call method to obtain and validate input
validInput = validateInput( );
// perform computations only if method returns true
if (validInput)
{

// instantiate an object of type Circle
// with the valid time inputted by the user

TimeBasics thisTime = new TimeBasics( );
thisTime.setTime(hoursInput, minutesInput, secondsInput);
// echo back the input to the user
txtEchoInput.setText(thisTime.echoInput( ));
// call the method to convert the inputs
// to universal time
// set the text in the appropriate JTextField

txtUniversalTime.setText(thisTime.toUniversalString( ));
// call the method to compute the circumference
// convert the numeric answer to a string
// set the text in the appropriate JTextField

txtAMPMTime.setText(thisTime.toAMPMString( ));
// a finalizer to free up memory allocation on TimeBasics thisTime
thisTime = null;

}

}

}

public JPanel createGUI( )
{

JPanel panGUI = new JPanel();
panGUI.setLayout( new GridLayout(7, 2, 5, 5) );

// developing input row for hours
lblHoursInput = new JLabel("Please input the hours: ", SwingConstants.RIGHT);
panGUI.add(lblHoursInput);

txtHoursInput = new JTextField(3);
panGUI.add(txtHoursInput);

// developing input row for minutes
lblMinutesInput = new JLabel("Please input the minutes: ", SwingConstants.RIGHT);
panGUI.add(lblMinutesInput);

txtMinutesInput = new JTextField(3);
panGUI.add(txtMinutesInput);

// developing input row for seconds
lblSecondsInput = new JLabel("Please input the seconds: ", SwingConstants.RIGHT);
panGUI.add(lblSecondsInput);

txtSecondsInput = new JTextField(3);
panGUI.add(txtSecondsInput);

// developing command button row for program execution
lblClickToCompute = new JLabel("Click button to solve: ", SwingConstants.RIGHT);
panGUI.add(lblClickToCompute);

compute = new JButton("Compute");
compute.addActionListener(this);
panGUI.add(compute);

// developing output row for echo of the input
lblEchoInput = new JLabel("Echoing your input: ", SwingConstants.RIGHT);
panGUI.add(lblEchoInput);

txtEchoInput = new JTextField(10);
txtEchoInput.setEditable(false);
panGUI.add(txtEchoInput);

// developing output row for universal time
lblUniversalTime = new JLabel("In universal time: ", SwingConstants.RIGHT);
panGUI.add(lblUniversalTime);

txtUniversalTime = new JTextField(10);
txtUniversalTime.setEditable(false);
panGUI.add(txtUniversalTime);

// developing output row for AM/PM time
lblAMPMTime = new JLabel("In AM/PM time: ", SwingConstants.RIGHT);
panGUI.add(lblAMPMTime);

txtAMPMTime = new JTextField(10);
txtAMPMTime.setEditable(false);
panGUI.add(txtAMPMTime);

return panGUI;

}

public boolean validateInput( )
{

String errorMessage = "";
validInput = true;

try
{

hoursInput = Integer.parseInt(txtHoursInput.getText());

}

catch (NumberFormatException nfeInteger)
{

// give error message when input can't be parsed to integer
errorMessage = errorMessage + "You need to enter an integer for the hour\n";
// set boolean variable to false when
// received an invalid input

validInput = false;
// blanking out inputs and any previous outputs
// when input is invalid

txtHoursInput.setText("");

}

try
{

minutesInput = Integer.parseInt(txtMinutesInput.getText());

}

catch (NumberFormatException nfeInteger)
{

// give error message when input can't be parsed to integer
errorMessage = errorMessage + "You need to enter an integer for the minutes\n";
// set boolean variable to false when
// received an invalid input

validInput = false;
// blanking out inputs and any previous outputs
// when input is invalid

txtMinutesInput.setText("");

}

try
{

secondsInput = Integer.parseInt(txtSecondsInput.getText());

}

catch (NumberFormatException nfeInteger)
{

// give error message when input can't be parsed to integer
errorMessage = errorMessage + "You need to enter an integer for the seconds\n";
// set boolean variable to false when
// received an invalid input

validInput = false;
// blanking out inputs and any previous outputs
// when input is invalid

txtSecondsInput.setText("");

}

if (!validInput)
{

JOptionPane.showMessageDialog(null, errorMessage, "Input Error", JOptionPane.ERROR_MESSAGE);
txtEchoInput.setText("");
txtUniversalTime.setText("");
txtAMPMTime.setText("");

}

return validInput;

}

}

 

Now the code will run wherever you want it to on the same machine.  You do not need to specify any special path in the compilation command.

javac TimeBasicsTest.java

and

appletviewer TimeBasicsTest.html

 

will still work.