Thursday June 29, 2000
More about classes.
We have talked about classes and their primary components. Let us talk more about the constructor of a class.
Recall that the job of the constructor is to create a new instance of a class and initialize its instance variables. However, it is
not necessary that all of the instance variables be initialized by the constructor. That is, it will not generate a compile-time
error. However, we do want to initialize as many of the essential variables as necessary.
We have talked about the access control keyword, but so far we have only used the keyword public. Let's discuss the opposite
keyword.
private
The keyword private indicates that only methods within the class in which the variable or method are defined may access that method
or variable.
For example, consider the following class definitions.
public class Test {
private int test;
public Test(int a) {
test = a;
}
public int return_test() {
return(test);
}
}
public class Test1 {
public static void main(String[] args) {
Test myTest = new Test(3);
int a = myTest.return_test();
System.out.println("The value of a is " + a + ".");
}
}
This program will run and produce the output.
Note however what happens if we try to use the following.
public class Test1 {
public static void main(String[] args) {
Test myTest = new Test(3);
System.out.println("The value of myTest.test is " + myTest.test + ".");
}
}
We get a compile-time error because the instance variable test is private and cannot be accessed from another class.
A variable which is declared public may be accessed from anywhere. A variable which is declared private may only be accessed within
the class in which it is defined.
Yesterday we talked about the use of the toString method in a class. Recall that the toString method is inherited from the Object
class and has the following signature.
public String toString()
The purpose of this method is to create a String equivalent of our object so that this object may be sent to the System.out.println
statement.
Let us look at an example of this.
public class Test2 {
public int a;
public Test2(int a) {
this.a = a;
}
public String toString() {
return("The value of my instance variable, a, is " + a + ".");
}
public static void main(String[] args) {
Test2 myTest2 = new Test2(0);
System.out.println(myTest2);
}
}
When the object is used as a parameter to System.out.println, the String returned by the toString method is printed.
One important rule you need to observe when using the toString method is that you cannot change the signature of this method with
its current parameter list.
Recall that the signature of a method consists of four primary components.
Access Control Keyword
Return type
Name
Formal parameter list
We can overload a method, that is create two methods with the same name, if we change the formal parameter list.
So when we inherit a method from another class, we may use the method that's inherited with its formal parameter list if we don't
change the rest of the signature. That is, we can still create a method with the same name as a method we inherit if we change the
formal parameter list. But since we normally want to use the method which is inherited with its formal parameter list so we cannot
change the signature.
Note one thing that's peculiar about one of our previous examples. When we looked at the class Test and the class Test1, in class
Test1 I made reference to Test as a data type even though there is no import statement to load the class Test into class Test1.
So how does the compiler know where to look? The answer is that when the environment variable CLASSPATH is not set by default the
current directory is searched. This is known as the default package.
Calling the Constructor
Recall that the Java keyword new is used to call the constructor for a class. Let's examine more closely the call to the
constructor used in class Test1.
Test myTest = new Test(3);
The first part of this line is the word Test. Any class that we create is a valid data type. So we are telling the compiler that we
are going to create a new variable of type class called myTest.
Recall that the right-hand side of an assignment statement is calculated first. On the right-hand side we have the keyword new
which signals we are going to call a constructor. It is followed by the name of the class. Recall that the name of the constructor
is the name of the class. So the constructor for the class Test which accepts one integer parameter is called. The constructor is
executed and the result is an object of type class. This object is assigned into the variable myTest.
Be careful when using an assignment statement. An assignment cannot usually have its operands swapped. One certain things in Java
can be on the left-hand side of an assignment statement. In other programming languages the expressions which are valid on the
left-hand side of an assignment statement are called L-values.
Examples of L-values would be variables. We most often use variables on the left-hand side of an assignment statement. Examples of
things that are not L-values would be constants (after their declaration) and the result of mathematical expressions such as a/3.
We have not talked much about the switch statement, but you may find it useful in your programming assignment.
Recall the syntax of a switch statement is
switch (variable) {
case value1 : statement1; break;
case value2 : statement2; break;
...
default : defaultstatement;
}
Like the for loop is a specialized form of the while loop, a switch statement is a specialized form of a nested if-then-else. There
is a restriction on the variable that can be used. It must be an ordinal type, that is something that can be put into order like
integers.
int a;
...
switch (a) {
case 1 : System.out.println("a is 1"); break;
case 2 : System.out.println("a is 2"); break;
default : System.out.println("a is neither 1 nor 2");
}
An Example
To give you more understanding of how to go about your programming assignment, let's look at the following example.
Carolyn is given the task of keeping track of student records. She decides to take an object oriented approach.
She decides that there are certain necessary properties she needs to keep track of for each student.
Name
Address
Phone Number
Age
Year
Major
GPA
Student Number
She decides that in order to assign student numbers she will examine the current list of students numbers that have been assigned.
If a student has already graduated then their student number will be released so that another student can use it. (We will not
actually write the code to do this. We can assume that there is already a method written for this call getnextnumber.);
Since most of the information related to a student is subject to change she decides she must set up a way to change those
properties.
She also would like to have a way of retrieving information for a particular student and displaying the output in a nice easy to
read form such as
Name xxxxxxxxx
Address xxxxxxxxx
Phone Number xxxxxxxxx
Age xxxxxxxxx
Year xxxxxxxxx
Major xxxxxxxxx
GPA xxxxxxxxx
Student Number xxxxxxxxx
So how will Caroline write a class which will perform these tasks?
Your programming assignment
Evariste decides that in order to gain more understanding of Object Oriented Programming he is going to write a small
class called Binary. He will have five instance variables in his class.
| original |
of type String |
| quadra |
of type String |
| octal |
of type String |
| hexadecimal |
of type String |
| decimal |
of type int |
He will have four instance methods in his class.
| toQuadra |
accepts no parameters and returns type String |
| toOctal |
accepts no parameters and returns type String |
| toDecimal |
accepts no parameters and returns type int |
| toHexadecimal |
accepts no parameters and returns type String |
| toString |
returns the String equivalent of this class (we will discuss this topic Tuesday and
Wednesday) |
He will have one class method called equiv that is overloaded.
The method will accept two, three or four parameters. It will return type String.
The constructor for Evariste's class will accept one parameter of type String.
The purpose of Evariste's class is to accept a binary number written as a string. Each of the instance methods will be
used to convert that binary number into the appropriate number system. When the constructor is called, its job will be to
give a value to original, and then call each of the four conversion instance methods to give values to the instance
variables, quadra, octal, decimal, and hexadecimal.
The method equiv will be used to accept two, three, or four bits (characters) and convert that group of bits to the
appropriate equivalent. For example, if the bits we send to one implementation of the method are ``1'',``1'', and ``1'',
the
method would recognize that since we are sending it three bits, we want the octal equivalent, so it would return the
String ``7''.
The method toString will be used to prepare a formatted result. The output this method will produce will be
| Binary |
QuadraDecimal |
Octal |
Decimal |
Hexadecimal |
| 1010 |
22 |
12 |
10 |
A |
Evariste has created a new number system called the quadradecimal number system which has only the digits 0, 1, 2, and 3.
He has decided that the easiest way in which to convert a binary number to other systems is to use the methods available
in the String class.
He decides the easiest way to proceed with converting a binary number to a quadradecimal is with the following algorithm.
Assume that there is a binary number stored in the String original.
1. Let l = the length of the string original.
2. Let n = the integer part of the quotient l/2.
(He decides on this because like the conversion
from binary to octal and hexadecimal he must
take groups of bits. Since the base of the
quadradecimal system, 4, is 22, he must take
groups of two binary digits and convert them to
their quadradecimal equivalent).
He knows now that there are n groups of 2 bits
in original. Now he must determine is there are
any bits left over.
3. Let r = the remainder in the division l/2.
If r is 0 he knows that there are exactly n
groups of 2 bits in original and no more. If r
is 1 he knows that there are n groups of 2 bits
in original and 1 left over. If there is one left
over he must accomodate for this.
4. if (r == 1)
get quadradecimal equivalent of ``0" and
the first character in original and store the
equivalent in an output string.
Now that he has accounted for the first character
if there is one left over, he can now go through
the rest of the string taking groups of two bits
and converting them to their quadradecimal equivalent.
If r was 1, then he will start breaking up the
string into groups of 2 beginning with position 1.
If r was 0, then he will start breaking up the
string into groups of 2 beginning with position 0.
5. for (initialize counter to 1; as long as counter
is less than or equal to n; increment counter by 2) {
get quadradecimal equivalent of two characters
of original beginning at position counter.
concatenate the equivalent into the output string.
}
6. Return the output string.
Evariste decides he can carry out the conversion from binary to octal and hexadecimal in the same way.
He decides the conversion from binary to decimal is even easier.
Your task is to write the class Binary and have it carry out the proposed tasks. The class you write should contain a
main method in which you instantiate the class, and make a call to its toString method to produce the formatted output.