Thursday July 13, 2000
Quiz 21
1. What are two ways we can distinguish constructors from other methods in
a class definition?
2. What are the parameters listed in the signature of a method called?
3. What two classes are used when we want to get input from an external
file?
4. What two classes are used when we want to write output to an external
file?
Recall that there is a Brat cookout this afternoon in the courtyard from
4:00 to 6:00 pm.
One correction needs to be made about yesterday's lecture.
Within the class we talked about the System.out.println method. Even
though the class PrintWriter has a println method, the class variable out
in the System class is of type PrintStream. PrintStream also contains a
method called println.
There are a couple of issues related to parameter passing that we need to
discuss. Before we do that, let us go back and reexamine how we define
objects.
Consider the following code.
Binary myBinary = new Binary("1010");
What this code does is create a new object of type Binary and attach that
object to the identifier myBinary.
The new object that is created is allocated space in memory. The name
myBinary allows us to reference that memory.
It is important to keep in mind the distinction between the actual object
and the object reference.
In the following String declaration
String a = "3";
a new String object is created and is referenced by the identifier a.
We can see an example of the distinction between an object and an object
reference in the following code.
public class Test1 {
public static void main(String[] args) {
String a = new String("Hello");
String b = new String("Hello");
if (a == b)
System.out.println("a == b");
else
System.out.println("a != b");
if (a.equals(b))
System.out.println("a equals b");
else
System.out.println("a does not equal b");
}
}
The output of this program is
a != b
a equals b
a and b are references to two different objects, even though they contain
the same string.
When we use the == operator with objects we are asking do the object
references that we're testing refer to the SAME object, not whether
or not the objects they refer to contain the same value.
In the Object class, there is a method called equals. This method can be
used to by objects to define the condition under which two object
references are the same.
public class Test2 {
int a;
public Test2(int a) {
this.a = a;
}
public boolean equals(Object o) {
if (this.a == ((Test2)o).a)
return(true);
else
return(false);
}
public static void main(String[] args) {
Test2 myTest2 = new Test2(2);
Test2 myTest22 = new Test2(3);
if (myTest2 == myTest22)
System.out.println("myTest2 and myTest22 refer to the same object.");
else
System.out.println("myTest2 and myTest22 do not refer to the same object.");
if (myTest2.equals(myTest22))
System.out.println("myTest2 and myTest22 have the same value.");
else
System.out.println("myTest2 and myTest22 do not have the same value.");
}
}
The output of this program is
myTest2 and myTest22 do not refer to the same object.
myTest2 and myTest22 do not have the same value.
Now if we change the program to the following we get different output.
public class Test2 {
int a;
public Test2(int a) {
this.a = a;
}
public boolean equals(Object o) {
if (this.a == ((Test2)o).a)
return(true);
else
return(false);
}
public static void main(String[] args) {
Test2 myTest2 = new Test2(2);
Test2 myTest22 = new Test2(2);
if (myTest2 == myTest22)
System.out.println("myTest2 and myTest22 refer to the same object.");
else
System.out.println("myTest2 and myTest22 do not refer to the same object.");
if (myTest2.equals(myTest22))
System.out.println("myTest2 and myTest22 have the same value.");
else
System.out.println("myTest2 and myTest22 do not have the same value.");
}
}
The output is
myTest2 and myTest22 do not refer to the same object.
myTest2 and myTest22 do not have the same value.
Note one important thing in this program.
Because the instance method equals is inherited from the class Object, we
cannot change its signature (unless we change its parameter list). So we
must accept something of type Object. Since every class extends the Object
class, every object is of type Object. But Object does not contain the
methods specific to every class. Therefore, when we receive an object as a
parameter we must cast it to is appropriate type.
In passing parameters to methods there are two distinct ways of doing it.
Pass by value
When we pass a parameter by value, within the method a copy of the value
of the parameter sent is used, and the actual parameter is not affected.
For example, in the code
public int toDecimal(int n)
when we make a call to this method, we can send a reference to an int
variable.
int a = 3;
int b = toDecimal(a);
Within the method toDecimal, the value of the value of the actual
parameter, 3, is copied into the corresponding formal parameter. So that
within the method toDecimal, the formal parameter n has the initial value
of 3. However, if we change the value of n within the method toDecimal
this will not affect the value of the variable a.
This method of parameter passing is limited to the primitive data types.
That is, we can only pass primitive data types by value.
Pass by reference
The other way of passing parameters is to pass by reference. This is
limited to Object references.
When an object reference is sent as a parameter to a method, then the
method may change the object that the object reference is referring to,
but it cannot make the object reference refer to something else.
Consider the following code.
public class Test {
int a;
public Test(int a) {
this.a = a;
}
public void change(Test myTest) {
myTest.a = 3;
}
public String toString() {
return(String.valueOf(a));
}
public static void main(String[] args) {
Test myTest = new Test(2);
System.out.println(myTest);
myTest.change(myTest);
System.out.println(myTest);
}
}
This produces the following output.
2
3
Now let's change the code so that within the body of the method change we
assign myTest to a new object of type Test.
public class Test {
int a;
public Test(int a) {
this.a = a;
}
public void change(Test myTest) {
myTest.a = 3;
myTest = new Test(4);
}
public String toString() {
return(String.valueOf(a));
}
public static void main(String[] args) {
Test myTest = new Test(2);
System.out.println(myTest);
myTest.change(myTest);
System.out.println(myTest);
}
}
This produces the following output.
2
3
Notice that even though we changed the parameter myTest to point to
another object that did not affect what the actual parameter, myTest,
pointed to.
StringTokenizer
In your assignment you will be using the StringTokenizer class. So let's
examine some of the methods available.
Recall that the StringTokenizer class is found in the java.util package.
The following are the signatures of the methods in the class definition.
public class StringTokenizer implements Enumeration {
public StringTokenizer(String str,String delim,boolean returnTokens);
public StringTokenizer(String str,String delim);
public StringTokenizer(String str);
public boolean hasMoreTokens();
public String nextToken();
public String nextToken(String delim);
public boolean hasMoreElements();
public Object nextElement();
public int countTokens();
}
Notice that in the second constructor for the class (how do we know it is
a constructor?) the second input parameter is of type String. So that
means even though we are going to delimit out text with a semicolon, we
must send it as a String and not a character.
Consider the following example.
import java.util.*;
public class Test3 {
public static void main(String[] args) {
String a = "CIS;120;Problem Solving and Programming Concepts I;3";
StringTokenizer myStringTokenizer = new StringTokenizer(a,";");
System.out.println(myStringTokenizer.countTokens());
String program = myStringTokenizer.nextToken();
System.out.println(program);
System.out.println(myStringTokenizer.countTokens());
}
}
This program produces the following output.
4
CIS
3
Notice one important thing. After we read one token out of the string, the
value returned by countTokens() is reduced by 1.
Now let's consider the following problem.
Suppose you are asked to write a program which will take a line of numbers
seperated by semicolons, find the sum, the average, the maximum, and the
minimum of those numbers and report the results.