Note Sun, which developed Java, has online documentation and tutorial at http://java.sun.com/doc.html


Two Kinds of Programs

Java is very similar to C++, particularly in the syntax of its statements. However, Java is a true object-oriented (OO) language, whereas C++ is a hybrid between an OO and a procedural language, such as C. For example, in Java, every function is a method in a class.
    

There are two forms of a Java program, an application, which is a stand-alone Java program, and an applet, which is a program that can run within a Java-compatible browser. A Java compiler translates source code into device-independent bytecode, or platform-independent code that a Java runtime system can interpret. We say that the program is compiled to a Java virtual machine. The bytecode is comparable to a machine language code for this imaginary machine. The Java runtime system on a real computer translates these bytecodes into the real machine code for that computer, which executes the program.


Basic Programs

The following is the Java application program HelloWorldAppl.java that displays "Hello World!":

//
// HelloWorldAppl.java
// Application to display "Hello World"
//
public class HelloWorldAppl 
{
   public static void main(String args[])  
   {
      System.out.println("Hello World!");
   }
}

An application always has a class with a main method whose first line reads as follows:

public static void main(String args[]) 

To display "Hello World" and advance to a new line, we call the method System.out.println().

The name of the source code file that contains main must be the class name with the extension .java. On a UNIX system, we compile this program with the javac compiler as follows:

javac HelloWorldAppl.java
Compilation produces a bytecode file whose name is the class name with the extension .class, such as HelloWorldAppl.class. In UNIX, to execute this file we type
java HelloWorldAppl
The method main has a parameter args that is an array with each element being a String object. As with C++, we refer to element 0 as args[0]. The public instance variable args.length stores length of the array args or number of elements it contains. Consequently, we can write a program to display the command-line arguments as follows:

//
// echo.java
// Application to display its command-line arguments.
//
public class echo{
   public static void main(String[] args
   {
      for (int i = 0; i < args.length; i++)    
         System.out.println(args[i]);
   }
}

After compilation, to run the program with command-line arguments "Here", "we", "go!" on a UNIX system, we type
java echo Here we go!
The resulting output is as follows:
Here
we
go!
Java requires that we declare as int the index i in the for loop.
Quick Review Question
Quick Review Question 1  Write a Java statement to display the number of elements in array a. Do not use any blanks.


Types

Besides the C++ primitive types int, float, double, short, long, and char, Java has type boolean, which has values true and false.

Java does not have pointer, enum, or struct types. To group data items, we use a class instead of a structure.

We can establish a constant during variable declaration by using the modifier final and assigning the constant a value. For example, Avogadro's number, which is the number of particles (atoms, molecules, or formula units, depending on the substance) in a mole, is a constant. With the following declaration, the value of AVOGADRO cannot change in the program:

final double AVOGADRO = 6.023e23;

A common convention is to have all uppercase letters for a constant identifier. Use of final in Java is comparable to that of const in C++.


Class Definition and Object Creation

Frequently, each class is in its own file, which has the name of the class and the extension .java. If several classes are in one file, only the class that shares the name of the file is publicly accessible. Below is a file point.java for a point class that encapsulates the data and methods for a point in two dimension. Unlike C++, we do not have a header file with the class prototype. The x and y coordinates, x and y, respectively, are private double variables, while the methods are public. Constructors initialize the point to the origin or with parameter arguments. A constructor has no return type, not even void; and the default constructor has no parameters. Methods return the distance of the point to the origin or to a parameter point. Recall that the distance of (x, y) to the origin is , while the distance between (x, y) and point (a, b) is . To compute the square root, we use the sqrt method in the Math class, such as Math.sqrt(x * x + y * y). (See the "Math Class" section below for other methods and constants.) To instantiate the origin, we have new point(0.0, 0.0). The method DistanceToOrigin calls method DistanceToPoint with the origin as the argument. The file point.java follows:

// point.java 
// Implementation of point class
class point 
{
   private double x;
   private double y;
   // Default constructor to create origin
   // Pre:  none
   // Post: This object represents origin (0.0, 0.0).
   public point() 
   {
      x = 0.0;
      y = 0.0;
   }
   // Constructor to create point from parameter coordinates
   // Pre:  xCoord and yCoord are double coordinates
   // Post: The object represents the point (xCoord, yCoord).
   public point(double xCoord, double yCoord) 
   {
      x = xCoord;
      y = yCoord;
   }
   // Method to return distance of this point to origin
   // Pre:  The point exists.
   // Post: The function returned the distance of the point to origin.
   public double DistanceToOrigin() 
   {
     return DistanceToPoint(new point(0.0, 0.0));
   }
   // Method to return distance of this point to a parameter point
   // Pre:  p is a point.
   // Post: The function returned the distance of the point to p.
   public double DistanceToPoint(point p
   {
     return Math.sqrt(((x - p.x) * (x - p.x)) + 
                      ((y - p.y) * (y - p.y)));
   }
}
Below is a TestPoint class that contains main. To declare and create an instance of a point object pt that represents the point (5.1, 2.73), we use a declaration and new, as follows:

point pt = new point(5.1, 2.73);

The code for TestPoint.java follows:

// 
// TestPoint.java - implementation of TestPoint class to
// test point class
//
class TestPoint {
   public static void main(String[] args) 
   {
      point pt = new point(5.1, 2.73);
      System.out.println("The distance to origin is " + 
            pt.DistanceToOrigin() + ".");
      point pt1 = new point(4.4, 8.4);
      System.out.println("The distance between the points is " + 
            pt.DistanceToPoint(pt1) + ".");
    }
  }

Output from execution of this test program is as follows:

The distance to origin is 5.784712611703368.
The distance between the points is 5.713046472767397.
Quick Review Question
Quick Review Question 2  Complete the statement to assign to dist the distance from point pt to a new point representing (3, 5). Do not put any blanks in your answers.

dist =  (a) DistanceToPoint( (b)    (c)  (3, 5));


Inheritance, Abstract Classes, and Interfaces

To indicate that class chemistry is a subclass of class science, we start chemistry's definition using extends, as follows:
class chemistry extends science {...
Within chemistry, we can refer to its parent as super. Thus, super() invokes the default constructor of science.

We use an abstract class only to create subclasses; we cannot generate an instance of an abstract class. We declare a class as abstract in the first line of its definition, such as follows:

public abstract class experiment {...
A method in an abstract class can also be abstract. In such a case, we declare the method as abstract and do not include a definition, as the following shows:
public abstract String ExperimentName();
Any class inheriting from experiment must include a definition for ExperimentName and all other abstract methods.

In Java, a class can only inherit directly from one other class; there is no multiple inheritance. However, we can use an interface to describe a behavior and provide many of the benefits of multiple inheritance. An abstract class can have some methods that are not abstract, but all methods in an interface must be abstract. An interface is also different from an abstract class in that several interfaces can impose their requirements on a class. To define an interface, LifeStudy, we use the keyword interface, such as follows:

public interface LifeStudy {
   public abstract boolean animal();
   ...
}

We might say that the class biology inherits from class science and implements the LifeStudy interface, as follows:

class biology extends science implements LifeStudy {
   public abstract boolean animal() {
     //definition of method goes here
     ...
   }
   ...
}  

In this case, the biology class must define the abstract methods, such as animal, from the interface LifeStudy.

Every Java applet extends the Applet class. We indicate that an addition class is an applet by starting its declaration, as follows:

public class addition extends Applet {...
The declaration that follows indicates that class clock is an applet and implements the Runnable interface:
public class clock extends Applet implements Runnable {...
The class clock only inherits from one super class, Applet, but clock also has the behavior of the interface Runnable and must implement all the methods of Runnable. We consider applets in more detail in another module.
Quick Review Question
Quick Review Question 3

a. In indicating that one class inherits from another, what keyword do we use in the first line of the class declaration?
abstract applet extends
implements interface super

 

b. Which of the following do(es) not include a definition?

abstract method applet method subclass method
super class method interface method none of the above

 

c.True or False: A class can inherit from two or more super classes.

True False



Packages

A Java package is a class library of related classes and interfaces. For example, the System class is a member of the I/O streams package java.io. To include all classes in this package, we have the following import statement at the beginning of the file:
import java.io.*;
To include the System class only, we replace the wildcard * with the class name, as follows:
import java.io.System;

To define our own package, we place all files in the package in the same directory and start each file with a package statement. This statement contains the full path name of the directory with dots as separators instead of forward slashes (as in UNIX), colons (as in MacOS), or backwards slashes (as in Windows). If the UNIX directory /usr/username/sciences contains files for classes science, biology, chemistry, physics, and psychology of the package sciences, we begin each class file with a package statement, as follows:

package usr.username.sciences;
class physics extends science {
  ...
}

To load all public classes in the package, we employ the following import statement:
import usr.username.sciences.*;

If we have already alerted the operating system to look in directory /usr/username, we can omit usr.username, as follows:

import sciences.*;

By setting the operating system environment variable, CLASSPATH, to include directories, such as /usr/username, we are indicating paths to search for imported packages.

To set the class path in UNIX to include directories /usr/username and /usr/username/classes, at the UNIX prompt we type

set CLASSPATH = /usr/username;/usr/username/classes

Wrappers

Every class inherits from class Object, although the former might not be a direct subclass. An element of every composite data structure, except an array, is of type Object. Thus, we cannot place an element of a simple type, such as int, in such a data structure. However, we can use a wrapper class to hold a primitive value. Integer is a class for which an instance stores an int value. For example, we can create an Integer object QuantityObj as a wrapper for the int 5, as follows:

Integer QuantityObj = new Integer(5);

To recover the int value, we call the Integer method intValue, such as follows:

int quantity = QuantityObj.intValue();

If a string contains an integer value, we can also wrap the corresponding integer value into an Integer object, and, if we wish, obtain the corresponding int value as shown:

String  IntString  = "3572";
Integer IntWrapper = new Integer(IntString);
int     IntValue   = IntWrapper.intValue();

To go in the opposite direction, obtaining a String from an Integer, we can use the Integer method toString, such as follows:

Integer QuantityObj    = new Integer(5);
String  StringQuantity = QuantityObj.toString();

Other numeric classes are Float, Double, and Long, with corresponding methods floatValue, doubleValue, and longValue, respectively. Similarly, Character and Boolean provide wrapper classes for char and boolean, respectively. Character also has boolean methods isLetter that returns true if the character is a letter and isDigit if the character is a digit. Table 1 summarizes the wrapper classes and some of their methods.

Table 1. Wrapper classes with some of their methods

Class Method Meaning
Boolean    
  new Boolean(booleanValue) Instantiate from boolean value
  booleanValue() Return boolean value
Character    
  new Character(charValue) Instantiate from char value
  charValue() Return char value
  isLetter() Return true if character is letter, false otherwise
  isDigit() Return true if character is digit, false otherwise
Integer    
  new Integer(value) Instantiate from int or String value
  intValue() Return int value
  toString() Return String representation
Double    
  new Double(value) Instantiate from double value
  doubleValue() Return double value
Float    
  new Float(value) Instantiate from float value
  floatValue() Return float value

Quick Review Question
Quick Review Question 4  For the following answers, use only one blank between words and on each side of the equal sign. (When answering, be sure not to put any blanks in your answer)
a. Suppose char variable ch has a value. Write a statement to declare ChObj as a Character object and make it a wrapper for ch’s value.

b. Complete the test to determine if ChObj represents a letter of the alphabet.
if(__________)...;

c. Complete the statement to assign to char variable c the character of ChObj.
char c = __________;


Arrays and Vectors

Java has an Array class. We declare an array readings of double elements using brackets, as follows:
double[] readings;
To create an Array instance and allocate space for 100 readings, we once more employ new:
readings = new double[100];
We can declare and set aside room for 100 elements in one statement:
double[] readings = new double[100];
To declare and initialize MonthDays as a 12-element array with each element storing the number of days in the corresponding month, we use braces around the sequence of values, as follows:
int[] monthDays = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
Quick Review Question
Quick Review Question 5  Complete the declaration of a 30-element int array, NumTrials. Do not use any blanks in your answer.
  (a)   NumTrials =  (b)     (c)  ;

A more reliable way to manipulate an array-like data structure is with the Vector class, which is part of the Java library. Unlike an array, a Vector is expandable; a vector can grow as necessary. To have access to Vector, we import the java.util.Vector, as follows:
import java.util.Vector;
or we import the entire java.util package with
import java.util.*;
The type of a Vector element must be a subclass of Object. Because an element cannot be of a primitive type, such as int or double, we use wrapper classes, such as Integer or Double. We declare and instantiate a vector, as follows:
Vector readings = new Vector();
We establish the vector's size as 100 with the Vector method setSize, as follows
readings.setSize(100);
Elements are initialized with the value null. One advantage of vectors is that we can call setSize to change the size by expanding or truncating. To obtain the number of elements, we employ the size method.
System.out.println("Number of elements = " + readings.size() );
To change the value of the element at position 3 to be 57.3, we call the setElementAt method with 57.3 wrapped in Double, as follows:
readings.setElementAt(new Double(57.3), 3);
Notice that the inserted value occurs before the index in the list of arguments. We use the elementAt method to display element with index 3 or to assign its value to x, as the following shows:
System.out.println("Element with index 3 = " + readings.elementAt(3) );
Double x = (Double)readings.elementAt(3);
To expand the vector at the end to include another element with value 25.44, which is in the Double wrapper class, we call addElement, as the following shows:
readings.addElement(new Double(25.44));
After execution of this statement, the element with index 100 contains a Double object with value 25.44, and the vector has 101 elements. Table 2 contains a summary of some of the Vector methods.

Table 2. Some methods in the Vector class
Method Meaning
addElement(value) Add value to the end of vector, expanding vector's size
elementAt(index) Returns element at position index
setElementAt(value, index) Assign value to element at position index
setSize(n) Set size of vector to n, expanding or truncating
size() Returns number of elements in vector

Quick Review Question
Quick Review Question 6  When answering, be sure not to include any blanks in your answers.

a. Complete the declaration of a vector, NumTrials.

 (a)   NumTrials =  (b)     (c  );

b. Establish the size of NumTrials as having 30 elements.

c. What is the value of the first vector element?

d. Complete the statement to assign the integer 82 to the first vector element.

NumTrials. (a) (  (b)     (c)  ,  (d) );

e. Complete the loop to display all the elements in the vector NumTrials, regardless of the number of elements.

for (int i = 0; i < NumTrials.        (a)        ; i++)
    System.out.println(NumTrials.     (b)     );


Strings

We have already employed strings in several situations. This important data structure is used in many scientific applications, such as storing human genomic data (see modules "Genomic Data," "Genomic Sequence Comparison," and "Searching Genomic Databases"). In this section, we consider strings in more detail. In the java.lang package, Java provides the String class for constant strings and the StringBuffer class for strings that can change.

We can instantiate a string object chemical as "sodium chloride" in any of the following ways:

String chemical = "sodium chloride";
String chemical = new String("sodium chloride");
As with arrays and vectors, numbering of character positions starts at 0 (see Figure 1). Thus, the statement
char ch = chemical.charAt(2);
employs String method charAt in assigning the character at index 2, d, to ch. To display the length of this string, 15, we use the length method, as follows:
System.out.println(chemical.length());
Figure 1. String chemical with value "sodium chloride"
s
o
d
i
u
m
 
c
h
l
o
r
i
d
e
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


We can also perform the reverse process to CharAt, indexOf, which returns the first index of a character of string. For example,

System.out.println(chemical.indexOf('i'));

and

System.out.println(chemical.indexOf("ium"));

each display "3." To discover the location of a character or string from a particular index on, we include a second argument. The following statement displays "12," the index of the second occurrence of 'i'.

System.out.println(chemical.indexOf('i', 4));

The method substring returns the substring from one index up to but not including a second index. Thus, to obtain the substring "chlo," which occurs at indices 7 through 10 in chemical, substring has arguments of 7 and 11, as follows:

String str = chemical.substring(7, 11);

To obtain rest of a string, such the word "chloride" from index 7 to the end of the string, we request the substring from starting index up to the length of the string

String AnotherChemical = chemical.substring(7, chemical.length());

We cannot use the relational operators, such as == and <, to compare strings. The expression (str1 == str2) returns true only if str1 and str2 occupy the same location in memory, not just if they have the same value. We use the String method equals to test if an argument string has the same value as the present string, such as follows:

if (chemical.equals(chemical2))...

If chemical2 also stores "sodium chloride," the boolean expression is true and the body of the if clause executes. Instead of a string variable (such as chemical2), we can also use a string constant argument (such as "sodium chloride"), as follows:

if (chemical.equals("sodium chloride"))...

To determine which string occurs before the other lexicographically, we employ method compareTo. The method returns a negative integer if this string occurs before the argument string lexically (alphabetically) according to the ASCII encoding scheme. In addition, the method returns a positive integer if this string occurs after and returns 0 in the case of equality. Consider the following segment:

String element1  = "copper";
String element2 = "zinc";

if (element1.compareTo(element2) < 0)
System.out.println(element1 + " occurs before " + element2);
else
System.out.println(element1 + " occurs after " + element2);

The output verifies that the value of element1 ("copper") occurs before the value of element2 ("zinc"):

copper occurs before zinc

Comparison is made according to the computer's encoding scheme, which is usually ASCII. In ASCII, uppercase letters have a smaller numeric representation than the lowercase letters. Thus, if element2 stores "ZINC," the output indicates that

copper occurs after ZINC

Some gene-sequence algorithms require that we determine if a sequence string has a certain prefix. The boolean method startsWith returns true if the current String object starts with a particular string. Thus, for chemical having the value "sodium chloride," the expression chemical.startsWith("sodium") returns true. Similarly, we use endsWith to determine if the string has a particular suffix. For example, the expression chemical.endsWith("ide") is true. Table 3 summarizes some of the String class methods.

Table 3.    Some methods in the String class
Method Meaning
charAt(index) Returns character at position index
compareTo(str) Returns negative if this string occurs before string str lexicographically; 0 if equal; positive if this string occurs after str lexicographically
endsWith(str) Returns true if string ends with str
equals(str) Returns true if this string is not null and equals string str
indexOf(s) Returns index of first occurrence of string or character s
indexOf(s, from) Returns index of first occurrence of string or character s after index from
length() Returns length of string
startsWith(str) Returns true if string starts with str
substring(i1, i2) Returns substring from index i1 through index i2 - 1; throws StringIndexOutOfBoundsException if out of bounds

Quick Review Question
Quick Review Question 7  Suppose String variables f and a have the values "force" and "acceleration", respectively.

a. Give the value of f.charAt(3).

'f' 'o' 'r'
'c' 'e' null


b. Give the value of f.length().


c. Give the value of a.substring(2, 5). Do not type quotation marks.

d. What is the value of f.equals("Force")?

True False


e. Complete the expression to return true if String x occurs before String y lexically. Be sure not to enter any blanks when answering.

if (x.___(a)___(___(b)___) __(c)__ __(d)__)
 

f. What is the value of f.compareTo(a)?

zero negative integer positive integer


g. Give the value of a.startsWith(f)

True False


We have already used the concatenation operator, +. For example, the following statement displays "solution of sodium chloride":

System.out.println("solution of " + chemical);

Similarly, after execution of the following segment, c and b have the value "barium hydroxide."

String b = "barium";
String h = " hydroxide";
String c = b + h;
b += h;

However, the time for such concatenation is not constant but is proportional to the length of the string. When we must perform a number of such updating concatenations, it is best to use the StringBuffer class instead of the String class.

To instantiate a StringBuffer object s with the sequence "ATGAC" of DNA bases, or nucleic acids, we use the following statement:

	StringBuffer s = new StringBuffer("ATGAC");
    We cannot omit new as we could with a String object.
    As with String, a StringBuffer object has methods length and charAt. Another method, setCharAt changes the value at a particular index to a char argument. Thus, we can change T at index 1 in s to A making s equal "AAGAC" with the following statement:
	s.setCharAt(1, 'A');
    The append method converts an Object argument to a String and appends that string onto the end of the current string. For example, s.append('G') changes the value of s to have an additional G on the end as "AAGACG". The statement s.append("AAA") attaches a string of three A's onto s to give "AAGACGAAA". The integer 23 in s.append(23) is converted to a string before appending to s to form "AAGACGAAA23". Besides changing s, the method returns the new value. Thus, the following statement changes s and assigns a value to t:

StringBuffer t = s.append('G');

Similarly, the insert method inserts the String equivalent of an Object argument at a particular index, changing the current StringBuffer object and returning the value. Suppose s has the value "ATGAC". After the following statement with insertion of "CC" starting at index 2, s has the value "ATCCGAC":

s.insert(2, "CC");

The method reverse alters the current string to be its reverse. In one of the genomic algorithms, we perform a process called reverse complementation in which we reverse the sequence of bases. To perform this operation on s, we use the following statement:

s.reverse();

As with Integer, Float, and Double, StringBuffer has a method toString to return the String object equivalent to the string buffer argument. Also, we can test if two StringBuffer objects are equal with equals. However, the StringBuffer class does not have methods compareTo, endsWith, startsWith, and substring. Table 4 lists some of the StringBuffer methods.

Table 4. Some methods in the StringBuffer class
Method Meaning
append(obj) Appends Object obj, converted to String, onto end of this string and returns result
charAt(index) Returns character at position index
equals(obj) Returns true if this string is not null and equals Object obj, converted to String
insert(index, obj) Inserts Object obj, converted to String, at index index and returns result
length() Returns length of string
reverse() Reverses current string and returns result
setCharAt(index, ch) Changes character at index index to ch
toString() Returns String equivalent of this string buffer

Quick Review Question
Quick Review Question 8  Suppose m is a StringBuffer object. For each question, assume m has the value "mass". Do not use quotation marks in your answers. What is the value of m after execution of each of the following statements?
a. m.append("es");

b. m.insert(3, '\'');

c. m.reverse();

d. m.setCharAt(1, 'o');


Parameters

Java uses pass by value for its arguments, where the value of an argument is copied into the corresponding parameter. If the type of the argument is primitive, such as int or char, the method's actions on the parameter cannot change the value of the argument.

Example 1   Suppose main contains the declaration of an int variable quantity that has the value 100. In main, we instantiate an object t in the class change. Then, we call t's method inflation with the argument quantity. The following code segment from main displays the value of quantity before and after the call:

public static void main(String[] args)
{
   int quantity = 100;

    System.out.println("Before calling change50, quantity = "
   + quantity);

   change t = new change();
   t.change50(quantity);

   System.out.println("After calling change50, quantity = " +
  quantity);
}

Suppose the method change50 in a class change has a parameter q that corresponds to quantity. The definition of change50 is as follows:

class change {
...
  public void change50(int q)
  {
     q = 50;
     System.out.println("In change50, q = " + q);
  }
...
}

The value of quantity (100) is passed by value and, thus, is copied into q. When q is assigned the value 50 inside the method, the value of quantity is not altered. As Figure 2 illustrates and the output verifies, the call to change50 does not change the value of quantity in the calling method:

Before calling change50, quantity = 100
In change50, q = 50
After calling change50, quantity = 100


Figure 2. Action of the pass by value call to change50 of Example 1
Call change50 Assignment
quantity of main: 100
100
q of change50:
100
50

When we pass an object to a method, we are actually passing by value the reference to the object. In effect, Java uses a technique called pass by reference for object argument-parameter pairs. The reference is copied into the corresponding parameter. If the method changes a data value of the object, the method is altering the contents of the argument object. Although the argument still references the original object, the value that object stores is now different.
Example 2   Suppose the class obj has a private int data member x that a constructor initializes to 100. The method PutObj changes x to the value of a parameter, and another method GetObj returns x. The definition of obj follows:
public class obj {

	private int x;

	// construct an object containing 100
	public obj()
	{
		x = 100;
	}

	// change the stored data
	public void PutObj(int xint)
	{
		x = xint;
	}

	// return the stored data
	public int GetObj()
	{
		return x;
	}
}
Suppose in main we instantiate object QuantityObj in the class obj and an object t in the class change. We pass QuantityObj to the parameter qObj in the t method ChangeObj50. ChangeObj50 calls the qObj method PutObj to change the data member of qObj to 50. Code segments for main and ChangeObj50 follow:
public static void main(String[] args)
{
	obj QuantityObj = new obj();

	System.out.println("Before calling ChangeObj50, QuantityObj:
		" + QuantityObj.GetObj());

	change t = new change();
	t.ChangeObj50(QuantityObj);

	System.out.println("After calling ChangeObj50, QuantityObj: "
		+ QuantityObj.GetObj());
}


class change {
	...
	public void ChangeObj50(obj qObj)
	{
		qObj.PutObj(50);
		System.out.println("In ChangeObj50, qObj stores " +
			qObj.GetObj());
	}
	...
}
Because we are changing the data that qObj stores and not the object reference, Figure 3 and the following output illustrate that the assignment in ChangeObj50 alters the data that the argument object QuantityObj contains:
Before calling ChangeObj50, QuantityObj: 100
In ChangeObj50, qObj: 50
After calling ChangeObj50, QuantityObj: 50

Figure 3. Action of the call to ChangeObj50 of Example 2
Call ChangeObj50   Assignment
QuantityObj of main:
100
50
qObj of ChangeObj50:    

Java passes an object reference to a called method. Within the method, assignment of an object to the parameter changes that reference. Consequently, the object in the calling function does not change.

To summarize, if we change a data member of an object parameter, the value of the argument object changes. If we assign another object to an object parameter, the value of the argument object does not change.

Example 3    Suppose in main we instantiate an Integer object QuantityInteger to contain the value 100. After instantiating a change object t, main calls t's ChangeInteger50 method using the argument QuantityInteger, as follows:
Integer QuantityInteger = new Integer(100);

System.out.println("Before calling ChangeInteger50,
	QuantityInteger = " + QuantityInteger.intValue());

change t = new change();
t.ChangeInteger50(QuantityInteger);

System.out.println("After calling ChangeInteger50,
	QuantityInteger = " + QuantityInteger.intValue());
Suppose that the parameter qInteger corresponds to QuantityInteger and that we assign a new Integer object to qInteger within ChangeInteger50, as follows:
class change {
	...
	public void ChangeInteger50(Integer qInteger)
	{
		qInteger = new Integer(50);
		System.out.println("In ChangeInteger50, qInteger = " +
			qInteger.intValue());
	}
	...
}	
Because a change of a parameter's object reference inside ChangeInteger50 does not affect the argument's object, the following output shows that QuantityInteger continues to store 100 (see Figure 4):
Before calling ChangeInteger50, QuantityInteger = 100
In ChangeInteger50, qInteger = 50
After calling ChangeInteger50, QuantityInteger = 100

Figure 4. Action of the call to ChangeInteger50 of Example 3
Call ChangeInteger50 Assignment
QuantityInteger of main: 100
100
qInteger of ChangeInteger50:  
50


Standard Streams
The three standard streams are as follows:
  • System.in for reading from standard input, such as the keyboard
  • System.out for writing to standard output, such as the screen
  • System.err for writing to error messages
System.out and System.err each have a method println for displaying the output and then advancing to a new line. The method print displays the output but does not advance to a new line. Consider the following segment:
System.out.print("1");
System.out.println("2");
System.out.println("3");
The output displays 1 and 2 on the same line, as follows:
1 2
3
To read a string interactively, we instantiate a BufferedReader object and employ its readLine method, as follows:
BufferedReader stdin = new BufferedReader 
		(new InputStreamReader(System.in));
String str;
	
System.out.println("Type a string: ");
str = stdin.readLine();


Files

To read an input file, we must create an input stream associated with the file. An instance of the class FileInputStream is a file input stream. For example, if the file on disk is FileIn.dat, we can create an associated file input stream infile, as follows:
FileInputStream infile = new FileInputStream("FileIn.dat");
We read from such a stream one byte at a time. To read entire items, such as floating point numbers or strings, we form a StreamTokenizer instance from the infile, as follows:
StreamTokenizer InfileToken = new StreamTokenizer(infile);

Alternatively, we can form InfileToken in one statement, as follows:

StreamTokenizer InfileToken = new StreamTokenizer(									
				 new FileInputStream("FileIn.dat"));
To obtain the first or next item in the file, we call the InfileToken's nextToken method:
InfileToken.nextToken();

If the file item is a number, the method returns the value of its instance variable TT_NUMBER. (TT is an acronym for token type.) In this case, nextToken reads a double value into the object's nval instance variable. Thus, if the value nextToken returns is equal to the method's TT_NUMBER, then the instance variable nval contains the input. The following segment, reads and displays an item provided that item is a number:

int token = InfileToken.nextToken();

if (token == InfileToken.TT_NUMBER)
	System.out.println(InfileToken.nval);

To interpret the value as an integer, we cast it to int, as follows:

int IntegerValue  = (int)InfileToken.nval;
The input stream can contain a string, delimited by whitespace or by quotation marks. In this case, nextToken's sval instance variable stores the item from the input stream, and we can display the value as follows:
System.out.println(InfileToken.sval);
If the input string is inside quotation marks, such as
"This is a string in quotation marks."
nextToken reads the entire string and drops the quotation marks for the value in sval. If the string is delimited by whitespace, such as a word, nextToken returns the value of the instance variable TT_WORD. In the following statement, if the input is a "word," we display that string:
if (InfileToken.nextToken() == InfileToken.TT_WORD)
	System.out.println(InfileToken.sval);
If there is an attempt to read beyond the end of the file, the method nextToken returns a value equal to the instance variable TT_EOF. Thus, we can read and process all values in the file with the following loop:
while (InfileToken.nextToken() != InfileToken.TT_EOF)
{
	...
}
To produce an output file, we first instantiate a FileOutputStream object (such as outfile) and associate it with a disk file (such as, "FileOut.dat"), as follows:
FileOutputStream outfile = new FileOutputStream("FileOut.dat");
We can write to this stream one byte at a time. To write numbers or strings to the file, we instantiate a PrintStream object from outfile, as the following illustrates:
PrintStream OutputToken = new PrintStream(outfile);
As with input files, we can consolodate these two statements into one and omit the intermediate object outfile:
PrintStream OutputToken = new PrintStream(
			    new FileOutputStream("FileOut.dat"));
The PrintStream method println writes an output stream and advances to the next line, while print writes but does not advance to a new line.

After we have finished using a file, we should close the file stream variable, whether it is a FileOutputStream or a FileInputStream object. To close, we invoke the object's close method, such as follows:

outfile.close();
infile.close();
In the next section on "Exceptions," we see how to capture errors, such as not finding the file or not having proper data.
Quick Review Question
Quick Review Question 9 

a. What is the name of the file input stream class?

b. What is the name of the file output stream class?

c. To read a number or a string from a file, we must associate the file input stream with an object from what class?

d. To write a number or a string to a file, we must associate the file output stream with an object from what class?

e. What is the input stream method that obtains the next item in a file?

f. This method returns the value of what instance variable if the item is a number?

g. This method returns the value of what instance variable if the item is a whitespace-delimited string?

h. This method returns the value of what instance variable if there is an attempt to read beyond the end of the file?

i. If this method reads a number, the method stores the value in what instance variable?

j. If this method reads a string, the method stores the value in what instance variable?

k. What output file stream method closes the file?


Exceptions

If we know that execution of a method can generate an error, or exception, Java expects that we acknowledge the situation and perhaps handle the exception. We say that the exceptional behavior throws an exception. For example, an error in opening, reading from, or writing to a file is an IOException. More specifically, if a disk file is not found in attempting to instantiate a file stream, a FileNotFoundException is thrown by the statement. IOException and FileNotFoundException are classes, and an exception is an object in such a class.

We can acknowledge that a method, such as main, has the potential of having file difficulties on the first line of the method's definition, as follows:

public static void main(String argv[]) throws IOException
{
	...
}
However, this clause does not instruct the computer about what to do in such exceptional situations. 

A better alternative is to enclose the segment that might result in an error in a try statement and to handle a problem in a catch statement. For example, we enclose the statements from opening the file streams to closing those streams in a try block. Then, after the keyword catch, in parentheses we have an argument of the type of the exception, such as FileNotFoundException, and in brackets how to handle the exception. We have a catch for each exception. The try-catch statements for file processing follow:

try {
	// statements to open, read, and write file stream(s)
	...
}
catch (FileNotFoundException e) {
	System.err.println("main: " + e);
}
catch (IOException e) {
	System.err.println("main: " + e);
}

If the file is not found, a statement with the name of the disk file similar to the following is displayed:

main: java.io.FileNotFoundException: FileIn.dat
As the above segment indicates, we can have more than one catch block, but no statements can appear between the try and the catch blocks. If one catch statement does not catch an error, the next catch attempts to do so. Thus, the order in which we list the catch statements is important. To catch the exception, the type of the argument of the catch statement must match the error. Because FileNotFoundException is a subclass of IOException, if a file is not on a disk, both types would match the exception. An IOException also includes errors in reading from or writing to a file. Table 5 lists some Java exceptions.

Table 5. Some Java exceptions
Exception Meaning
ArithmeticException Overflow or integer division by zero
ArrayIndexOutOfBoundException Array index not in declared range
FileNotFoundException Disk file not found
IndexOutOfBoundsException String or array index not in declared range
IOException Error in dealing with an input/output file stream
NullPointerException Illegal attempt to use null reference
NumberFormatException Illegal conversion of String to number


Random Numbers

Simulations, such as a simulation of molecules moving in an enclosed area or of weather, require random numbers. Because the class Random is part of the java.util package, we import the package as follows:

import java.util.*; 
or
import java.util.Random;
Table 6 contains a list of some of the methods in the Random class.

The following segment instantiates prob as a Random object and assigns to double variable d a uniformly distributed pseudorandom integer in the interval [0.0, 1.0), numbers greater than or equal to 0.0 and less than 1.0:

Random prob = new Random();
double d = prob.nextdouble(5);  
For example, d might be assigned the value 0.9557053550430712.

To obtain a nonnegative pseudorandom double that is less than 4.0, we multiply the value by 4.0, as follows:

d = prob.nextdouble() * 4.0;
If prob.nextdouble() returns, then d becomes 4.0 times this value, 3.8228214201722848.

If we need a random double greater than or equal to 8 and less than 12, we obtain a random double in the interval [0.0, 1.0). Then, we multiply the result by the length of the interval, 12 - 8 = 4 and add the lower bound (8.0), as follows:

d = prob.nextdouble() * 4.0 + 8.0;
For example, if prob.nextdouble() * 4.0 is 3.8228214201722848, adding 8.0 gives 11.8228214201722848.  

Casting the entire expression on the right to int truncates the floating point number from [8.0, 12.0) to an integer in the set {8, 9, 10, 11}:

int i = (int)(prob.nextdouble() * 4.0 + 8.0);
Because the expression in parentheses returns a floating point number less than 12.0, casting to int yields an integer less than 12. To obtain a pseudorandom integer in the 5-element set {8, 9, 10, 11, 12}, we multiply by 5 = 12 - 8 + 1, as follows:
i = (int)(prob.nextdouble() * 5.0 + 8.0);

We must be careful to place prob.nextdouble() * 5.0 + 8.0 in parentheses for casting. Because nextdouble returns a floating point number in the interval [0.0, 1.0), (int)( prob.nextdouble()) always truncates to zero.

Table 6. Some methods in the Random class. Unless otherwise specified, "random" means "pseudorandom, uniformly distributed."

Method Meaning
nextDouble() Returns next "random" double between 0.0 and 1.0
nextFloat() Returns next "random" float between 0.0 and 1.0
nextGaussian() Returns next pseudorandom, Gaussian ("normally") distributed double with mean 0.0 and standard deviation 1.0
nextInt() Returns next "random" int
nextLong() Returns next "random" long
Random() Creates random number generator with current time as seed
Random(seed) Creates random number generator with long seed as seed


Quick Review Question
Quick Review Question 10 Be sure not to include any blanks in your answers.
a. What is the name of the class for generation of pseudorandom numbers?

b. Suppose rand is an object in this class. Complete the statement to display a uniformly distributed random double between 0.0 and 50.0.
System.out.println(rand.   (a)      (b)  50.0);

c. Complete the statement to display a uniformly distributed random double between 100.0 and 150.0.
System.out.println(rand.   (a)     (b)  50.0  (c)  100.0);

d. Suppose rand is an object in this class. Complete the statement to display a uniformly distributed random int between 0 and 50, inclusively (i.e., in the set {0, 1, 2,..., 50}).
System.out.println(  (a)   (rand.nextDouble() *  (b) .0));

e. Complete the statement to display a uniformly distributed random double between 100 and 150, inclusively.
System.out.println((int) (rand.nextDouble() *   (a)  .0 +   (b) .0));


Math Class

Java's java.lang package contains the Math class. Because the compiler automatically loads this package, we do not need to import it. The class contains a number of methods and two constants. Math.PI is p (3.14159…) and Math.E is e (2.71828...) to about 19 decimal places. To invoke a Math method, we use the class name (Math), a dot, and the method name. For example, to assign the absolute value of x, |x|, to Posx, we employ the abs method, as follows:
Posx = Math.abs(x);
Table 7 lists several of the methods and constants in the Math class.

Table 7. Table of several Math class methods and constants, where x and y are of type double unless otherwise noted
Method or Constant Meaning
abs(x) Absolute value of x, where x is double, float, int, or long
acos(x) arccos(x)
asin(x) arcsin(x)
atan(x) arctan(x), which is between -p/2 and p/2
atan2(x, y) arctan(y/x), which is between -p and p
ceil(x) Ceiling of x, smallest integer greater than or equal to x
cos(x) cos(x), where x is in radians
E Constant e
exp(x) ex
floor(x) Floor of x, largest integer less than or equal to x
log(x) ln(x), natural logarithm (log to base e) of x; can throw ArithmeticException
max(x, y) Maximum of x and y, where x and y are double, float, int, or long
min(x, y) Minimum of x and y, where x and y are double, float, int, or long
PI Constant p
pow(x, y) xy; can throw ArithmeticException
random() Uniformly distributed pseudorandom double between 0.0 and 1.0
round(x) Closest long to double x or closest int to float x
sin(x) sin(x), where x is in radians
sqrt(x) Square root of x; can throw ArithmeticException
tan(x) tan(x), where x is in radians


Quick Review Question
Quick Review Question 11 Write expressions for each of the following, using only one blank after each comma and no other blanks:

a. cos5(t).

b. ln(p z)

c.


Exercises

1. Write an application program that counts from 1 to 15, printing each number on the same line with a blank between numbers. Advance the output to a new line. Then count backwards by twos to 1, again printing each number on the same line with a blank between numbers. Thus, the output is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
15 13 11 9 7 5 3 1
2. Develop a program (radius.java) that accepts an integer radius of a circle as a command-line argument and prints the corresponding circumference (2pr) and area (pr2) of the circle, where p is approximately 3.14159. Declare double variables circumference and area. Sample output:
radius of circle = 3
circumference = 18.8495
area = 28.2743
3. Develop a program (BlankBtw.java) that prints the command-line arguments with a blank between each character and two blanks between arguments. For example, if the arguments are
This is a test
The output should be the following:
T h i s  i s  a  t e s t
4. The point class, has private data members x and y. Suppose the constructor below is defined with parameters x and y that should be assigned to the corresponding private data members. How do C++ and Java avoid the ambiguous situation of x or y meaning a parameter and a private data member? Fill in the blanks in the definition of the constructor.
public point(double x, double y) 
{
	______ = x;
	______ = y;
}
5. Write a method GetLine that reads and returns a line from the current position in the input stream f.

6. Write a method to return the reverse of a String argument.

7. Write statements to pad a StringBuffer object s with asterisks to a length of 20. If the string is already of length 20 or more, do nothing.

8. Write a method DeleteAllSub(s, sub) with String parameters to return a String equal to s except omit all occurrences of the substring sub.

9. Write a method DeleteString(s, pos, lng) to return a String object equal to s except to delete from this object the substring starting at position pos for length lng or to the end of the string, whichever occurs first.

10. Write a method subst(s, old, new) with String parameters s, old, and new to return a String object. The return value is the same as s except new is substituted for the first substring old in s. If old cannot be found, a value equal to s is returned.

11. Write a function SequentialSearch with parameters v (a Vector of Strings) and str of type String that performs a sequential search of v and returns the index of the first occurrence of str in v or —1 if str is not in the vector.

12. Write a function BinarySearch with parameters v (a sorted Vector of Strings) and str of type String that performs a binary search of v and returns the index of the first occurrence of str in v or —1 if str is not in the vector.

13. Write a function sort with parameter v, a Vector of Strings, that sorts the vector.

14. Write a method ReplaceChr of an edit class to replace every occurrence of one character in a String with another. For example, if e is an edit object and the string str is "appearance", after execution of the following:
e.ReplaceChr(str, 'a', '*');
the string is "*appe*r*nce".

15. a. Suppose a node class contains data elements for an Object and another node, as follows:
// class for node in queue
class node {
   Object el;
   node next;
}

Develop a dynamic implementation of a stack class with private data member top of type node and with the following methods:

  • A default constructor that assigns null to top
  • Boolean StackIsEmpty that returns true if the stack is empty
  • Boolean StackIsFull that returns false
  • MakeNode that returns a node containing an Object parameter
  • Push that pushes an Object parameter onto the top of the stack
  • Pop that pops and returns the Object from the top of the stack
  • RetrieveStack that returns the Object from the top of the stack
  • StackError that displays a String error message and aborts the program

      b. Instantiate s to be a stack object.

       c. Suppose a stack contains an integer in the el portion. Write a statement to push 17.3 into s. Use a wrapper.

       d. Suppose val is of type double. Write a statement to pop the top element of s placing the value into val. Be sure to convert the Double to a double.

16. Develop a static implementation of the stack class from the previous exercise using the Vector class.

17. a. Using the node class from Exercise 11, develop a dynamic implementation of a queue class with private data members front and rear of type node and with the following methods:

  • A default constructor that assigns null to front
  • Boolean QueueIsEmpty that returns true if the queue is empty
  • Boolean QueueIsFull that returns false
  • MakeNode that returns a node containing an Object parameter
  • EnQueue that enqueues an Object parameter onto the rear of the queue
  • DeQueue that dequeues and returns the Object from the front of the queue
  • RetrieveQueue that returns the Object from the front of the queue
  • QueueError that displays a String error message and aborts the program
       b. Instantiate q to be a queue object.

       c. Suppose a queue contains an integer in the el portion. Write a statement to enqueue 5 into q. Use a wrapper.

       d. Suppose val is of type int. Write a statement to dequeue the front element of q placing the value into val. Be sure to convert the Integer to an int.

18. Develop a static implementation of the queue class from the previous exercise using the Vector class.


Projects


1. Develop a unit class for conversion between the English and metric systems along with a test program.

2. Develop a fall class with methods concerning a falling object in metric units. The class has private data for initial position and initial velocity, where up is positive. Have the following methods, where s0 is initial position and v0 is initial velocity:
  • A default constructor that initializes initial position and velocity to zero
  • A constructor that initializes initial position and velocity to parameters
  • SetInitPosition to establish an initial position
  • SetInitVelocity to establish an initial velocity
  • WhenMaxPosition to return the time when the object achieves its maximum height. If the object is thrown up, the time is v0/9.81. If the object is dropped (zero initial velocity) or thrown down (negative initial velocity), the object starts at its high position.
  • MaxPosition to return the object's maximum height. If the object is thrown up, the value is . If the object is dropped (zero initial velocity) or thrown down (negative initial velocity), the object starts at its maximum height.
  • WhenHitGround to return the time when the object hits the ground, .
  • VelocityHitGround to return the velocity () when the object hits the ground
3. Develop a program to simulate a rat pressing a lever. Develop a clock class with the following methods:
  • A constructor to initialize the clock to zero
  • SetClock to set the time to a parameter value
  • GetClock to return the time
  • IncrementClock to increment the clock by one unit
Interactively read the length of time for the simulation and the probability (probability) that the rat will press the lever at any one tick of the clock. At each tick, generate a random double between 0.0 and 1.0. If this number is less than probability, write the time to a file.

4. Develop the stack class as described in Exercise 11 and use it to solve the following problem. Some calculators employ a stack and use postfix notation. Design an interactive program to simulate such a calculator. For this machine, the user presses return after entering each number or operation. Numbers are pushed onto the stack. For a binary operator, the top two data items are popped, the operation performed, and the result pushed onto the stack. A unary operator pops the top item, completes the manipulation, and pushes the answer. The simulated calculator should display the top of the stack. The following is part of a sample session with a prompt of > and underlined user input:
> 5
> 7
> *
35
>
The program should accept binary operations of +, -, *, / for floating point division, and ^ for exponentiation. Moreover, it should handle several unary operations, such as sqrt:
> 1.44
> sqrt
1.2
>
Other unary operations to implement are the following: sqr, sin, cos, tan, ln, exp, chs to change the sign, inv to compute the inverse with respect to *, and clear to clear the stack. The operation display prints the stack, and off "turns off" the calculator. If an error occurs, such as an attempt to pop from an empty stack or divide by zero, the "calculator" should print "ERROR."

5. Develop and test the queue class as described in Exercise 13.

Copyright © 2002, Dr. Angela B. Shiflet
All rights reserved