6.2 Instance Methods
Objects are more than just collections of data; they can also have functionality, implemented through methods. The methods associated with objects can be grouped into two primary categories. In this section, we examine the more commonly used type - instance methods. We have already encountered instance methods in the String class where the methods equals and compareTo are of this type. Here we will examine the structure of such methods and learn how to create our own.
As an example of an instance
method, suppose that we want to extend our Fraction
class with a method that returns, as a double
value, the magnitude or size of a fraction. We define the size of a fraction as
·
To implement such a method, we could add the method
shown in the next example to our Fraction
class.
Example 1 The following instance method will return the magnitude
of a Fraction object. If, in our main method, we had created and defined a Fraction object f, then we could determine its size, s, by writing double
s = f.size(); In line with our suggestion in Section 6.1, it may be
helpful if you read this statement as s = f’s
size There are many things to note here. 1. The method does not have the modifier static that has appeared in every
method that we have created up to now. Any method without the static modifier is an instance method; any method having
the static modifier is a class method. We will examine the
use of class methods with objects later in the chapter. 2. The general form of a call to an instance method that
returns a value is <object
identifier>.<method identifier>(<parameter list>); In our example, the call has the form f.size 0 ; 3. In the method, we compute the size of the fraction
using the identifiers num and den, not f.num and f.den. No
object is mentioned explicitly in the method. Instead, it is implicit here that the num and den that we are referring to are those of the object that is
currently associated with the method. The call to the method associates the
object f as an implicit parameter of the method. If
we were to call the method with a statement like t = g.size(); then g would be the implicit parameter and Java would use the num and den fields of g in
its calculations. 4. The current implicit object in an instance method can
be referred to in Java as this. It would have been correct to write the
statement in the body of the method as return
Math.abs«double)this.num/this.den); if we wanted to make explicit
the fact that we are taking the quotient of the current object's num and den fields but there is, in this example, no need to do so.
(The next example will illustrate a practical use of this in an instance method.) Although the parameter list of
the method in the previous example was empty, it is possible (and common)
for instance methods to have nonempty parameter lists. We have already
encountered this in the methods of the String class. There, the header of
the equals
method has the form public
boolean equals (String s) while that of the compareTo
method has the form public
int compareTo (String
s) To show how we can create an instance method with a
non-empty parameter list, suppose that we wanted a method to compare the
sizes of two Fraction objects.
public double size ()
{
return Math.abs((double)num/den);
}
Example 2 The following method uses the size method to compare two objects of type Fraction. It returns a reference to a Fraction object, the larger of the two (or the first if they have
the same size). If f, g, and h are all of type Fraction,
then we could use the larger
method by writing a statement such as h = f.larger(g); This would assign to h a reference to the larger when we compare f to g (or to f if f and g are the same size). Suppose that, before this call, we had the following
situation: Then, after the call, h would also refer to g,
because Note the use of the reserved
word this in the example. As we
have said previously, this
refers to the implicit object associated with an instance method. In the
call f.larger (g), this would refer to f while the explicit parameter,
other, would refer to g. In the
definition of the larger method, the first line of the if statement could
have been written more simply as if
(size() >= other.size()) Normally a call to an instance method such as size requires an object but, if we
omit an object reference, Java assumes that we intended to use this, the current implicit object
reference. As with any other methods,
instance methods can take the form of commands that do not return values.
The next example illustrates this.
public Fraction larger (Fraction other)
{
if (this.size() >= other.size())
return this
else
return other;
}
>
.
Pictorially, we would have:
Example 3 The method timesEquals has the same effect (for Fraction objects)
that the *= operator has for primitive numeric types. It assigns to its
implicit Fraction parameter the product
of itself with its explicit Fraction
parameter. If f and g are objects of type Fraction,
then the statement f.timesEquals(g); would make f represent the product
of the values represented by f
and g (while leaving g unchanged). Example 3 also illustrates an
important difference between object (reference type) parameters and
primitive type parameters. As we have said before, all parameters in Java
are passed by value. This means that, at the time of a call to a method,
the parameter is assigned the value of the argument. Any subsequent changes
to a parameter in a method cannot change the value of the argument in the
calling block. For primitive types, the value that is passed to the
parameter is the value of the item; for objects, the value that is passed
is the value of the reference to
the object. Thus, for primitive types, the parameter contains an item that
has the same value as the corresponding argument; for objects, the
parameter refers to the same object as the corresponding argument. This is
illustrated in the next diagram. A consequence of this is that,
if a field of an object parameter is altered in a method, then this
actually alters the field in the argument's object. In Example 3, the
fields of the implicit object parameter were altered but the same principle
applies to explicit object parameters. In either case, fields of object
parameters can be altered in methods. Our final example illustrates the use
of a method that creates an object and returns a reference to that object.
public void timesEquals(Fraction p)
{
num *= p.num;
den *= p.den;
}
Example 4 The method times, when called by the statement Fraction f = g.times(h); where g and h are both Fraction objects, returns a new Fraction object equal to the
product of g and h while leaving both g and h unchanged. In the example, the variable result is local to the
method but this does not mean that the Fraction
object to which result refers is lost when execution of the method
terminates. The statement Fraction f = g.times(h); returns a reference to the
newly created object. This reference is then assigned to f so that f now refers to the new object, as required. Once again, we can
illustrate the effect of this method with diagrams. Suppose that, before the
call to times, we had the following: Then, after execution of the statement Fraction f would
have:
public Fraction times (Fraction other)
{
Fraction result = new Fraction();
result.num = num * other.num;
result.den = den * other.den;
return result;
}
Exercises 6.2 1. Suppose that p,
q, and r are all objects of type Fraction. What fraction would r represent
after the statement r = p.larger(q); is executed given that larger is the method in Example 2
and (a) p represents (b) p represents (c) p represents (d) p represents (e) p represents 2. Complete the definitions of the following instance
methods for the Fraction class. The method should have the
effect (for Fraction objects) that the += operator for primitive numeric types. Thus,
if called by the statement p.plusEquals(q); (where
p and q are objects of type Fraction), the method would make p represent
the sum of the fractions currently represented by p and q while the value
of q would be left unchanged. The method should return a Fraction object whose value is the
sum of the implicit object parameter and the explicit parameter, f. The method should leave both its
explicit and implicit parameters unchanged. The method should reduce its
implicit Fraction parameter to
lowest terms. For example, if f represents the fraction f .reduceO; should change
f so that it represents the
fraction 3. Suppose that a class Complex has been defined as
follows: (a) Write an instance method
modulus for this class that could be called by a statement like where
z is of type Complex. If z represented the value (b) Write an instance method
called scale for the class
Complex that could be called by a statement like z.scale(x); where
z is of type Complex and x is a double value. If, before the
call, z represented the value 4. Assuming that z1,
z2, and z3 are of the type Complex described in the previous question, (a) write
an instance method plus that, if
called by the statement z1 = z2.plus(z3); would set z1 to the sum of z2 and z3, (b) write
an instance method times that,
if called by the statement zl = z2.times(z3); would set z1 to the product of z2 and z3. 5. Consider again the class Circle. (a) Write an instance method
area that returns, as a double value, the area of its implicit Circle object. (b) Write a method smaller that could be called by a
statement like c3 = cl.smaller(c2); where
c1, c2, and c3 are
objects of type Circle. The
method should make c3 refer to
the smaller of the circles represented by c1 and c2 (or c1 if c1 and c2 are the
same size). (c) Write a boolean-valued instance method islnside that could be
called by a statement like boolean contained = c1.islnside(c2); The method
should return true if cl is
entirely inside c2 and return false otherwise. 6. Write a main
method that uses the Circle
class developed in the previous question. The main method should perform the following actions. (a)
Create two Circle objects c1, representing the circle with
centre (4, -1) and radius 3,
and c2, representing the circle
with centre (3, -2) and radius 5. (b) Find and print the area
of c1. (c) Determine the smaller of
c1 and c2 and then print its centre and radius. (d) Determine whether or not
c2 lies entirely within c1 and print an appropriate statement.
and
q represents
and
q represents
and
q represents =
and
q represents
and
q represents
public void plusEquals (Fraction other)
public Fraction plus (Fraction f)
public void reduce ()
,
the statement
.
class Complex
{
double re:
double im;
}
double size = z.modulus();
,
then the call would set
the variable size to the
value of
,
then, after the call, it should represent the value
.
class Circle
{
double x; // x-coordinate of centre
double y; // y-coordinate of centre
double r; // radius
}