As an example of these classes and objects, let us look at how we might introduce the concept of a fraction into Java. Ignoring, for the moment, the operations that can be performed on fractions, we can consider a fraction to be composed of two parts: a numerator and a denominator. If we want the numerator and denominator of our fractions to both be of type int, we can define the class of fractions as follows:
class Fraction
{
int num;
int den;
}
This class is very different from the ones that we have seen up to this point in our study of Java. It does not have a main method; in fact, it has no methods at all! It simply defines what something called a Fraction should look like: something that has two int parts that we have called a num and a den. We call these parts fields of the class. A field is declared outside a method while a local variable is declared inside a method.' We can illustrate the structure of the class with a diagram, as follows:
We should warn you that, although we think that this distinction between fields and local variables is a useful one, not everybody uses these terms. We can think of the Fraction class as a model, blueprint, or template of what a fraction should look like. All fractions have both a numerator and a denominator. The class definition makes this idea explicit; it defines a new type called Fraction that we can use in our programs. The definition does not actually create any fractions; it simply shows us what any fractions that we eventually create will look like. When we do create any fractions, each one of them will have its own num and den fields. Since each instance of a fraction will have these fields, they are, reasonably enough, called instance fields. In a program that uses fractions, this class can appear separately from the class that contains the main method. Once we have defined what we mean by a fraction, we can then create actual fractions, using our template. To begin to do this, we can, in the main method of our program, say, make the declaration:
Fraction f;
This creates a variable f that can act as a reference to a fraction. Since we have not assigned f a value, it does not at this point actually refer to a fraction. To achieve this, we can now write:
f = new Fraction();
This causes Java to create an object, an instance of the type Fraction. In addition a reference to the location in memory of the newly created object is stored in the variable f. Pictorially, we can illustrate what we have created as follows:
Notice in the preceding diagram that the num and den fields are both shown with the value zero. Although Java does not initialize local variables when we declare them, it does initialize all numeric fields to the value zero when we create an object containing those fields. We can (and usually will) combine the process of declaring and creating a new Fraction object f by writing
Fraction f = new Fraction();
If we wanted our object to represent the fraction
rather than
, we could now make the following assignment statements:
f.num = 2;
f.den = 3;
You might find it useful to read these assignment statements as
f's num = 2;
f’s den = 3;
Pictorially, the result of the assignments is:
Using the same template, we can create as many objects of that type as we wish.
|
Once we have created objects, we can manipulate their fields in the same ways that we do with local variables.
|
As we have already noted, if we simply declare a reference variable, that variable does not yet actually refer to an object. For example, if we were to write Fraction £1; the result is an uninitialized Fraction variable. An attempt to use £1 in this state will result in an error during compilation of the program. To avoid such compilation errors, we can initialize a reference variable so that it does not refer to an object (but is still defined) by assigning it the value null. If we write Fraction f2 = null; then we can print f2 (producing the output "null") or compare f2 to other objects (an idea that we will explore in more detail later). The variables £1 and f2 are illustrated in the next diagram. The dot inside f1 indicates that it has no value. We show the null reference of f2 with the symbol used to indicate a ground in a diagram of an electrical circuit.
As we have already seen with strings, objects are very different from primitive types so, when we attempt to apply operations to objects, we must be very careful of what we are doing. Otherwise, the results can be something quite different from what we want. The next example examines the meaning of assignment with objects.
|
|