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.

public double size ()
{
   return Math.abs((double)num/den);
} 

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.

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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).

 

   public Fraction larger (Fraction other)
   {
      if (this.size() >= other.size())
         return this
      else
         return other;
   } 

 

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 > . Pictorially, we would have:

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.

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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.

 

   public void timesEquals(Fraction p)
   {
      num *= p.num;
      den *= p.den;
   } 

 

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.

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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.

 

   public Fraction times (Fraction other)
   {
      Fraction result = new Fraction();
      result.num = num * other.num;
      result.den = den * other.den;
      return result;
   } 

 

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:

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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 and q represents

(b) p represents and q represents

(c) p represents and q represents =

(d) p represents and q represents

(e) p represents and q represents

 

2. Complete the definitions of the following instance methods for the Fraction class.

public void plusEquals (Fraction other) 

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.

public Fraction plus (Fraction f) 

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.

public void reduce () 

The method should reduce its implicit Fraction parameter to lowest terms. For example, if f represents the fraction , the statement

f .reduceO;

     should change f so that it represents the fraction .

3. Suppose that a class Complex has been defined as follows:

class Complex
{
   double re:
   double im;
} 

(a) Write an instance method modulus for this class that could be called by a  statement like

double size = z.modulus(); 

where z is of type Complex. If z represented the value, then the call would set               the variable size to the value of

(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, then, after the call, it should represent 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.

class Circle
{
   double x; // x-coordinate of centre
   double y; // y-coordinate of centre
   double r; // radius
} 

(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.