IntObj
class we gave
in the "IntObj" examples: Part 1 notes.
For example, we could add a method which subtracts a number from the
value held in an IntObj
:
public void sub(int m) { val=val-m; }This could be added anywhere (though obviously not inside one of the other methods) in the file for the class
IntObj
. One of the
advantages of the object-oriented approach is that you can make
additions like this to the code for a class without having to change any
other code, or even recompile it. Only the file for the class that has been
changed has to be recompiled.
Suppose you wanted to add two IntObj
s. If we had, say
IntObj a = new Intobj(3), b = new IntObj(4);you might think that
a.add(b);would cause the value inside
b
to be changed from 3 to 7.
However, it would not work because the definition of add
in
IntObj
is:
public void add(int m) { val=val+m; }The argument it takes is an
int
, not an IntObj
.
While to us it is obvious what ought to be done, computers can only follow
their own rules strictly, and there is no rule which enables a computer
running Java to convert an IntObj
into an int
- we have to instruct it to do that ourselves. That is easy:
a.add(b.value());will do what we want, as we have already seen. However, this looks a bit complex, and our program which uses
IntObj
s might look a bit
messy if there was a lot of this. It would be nice if we actually could
use the nicer looking a.add(b)
. In fact, we can, we just
need to instruct the computer how to add one IntObj
to another
by adding the appropriate method to the class IntObj
. Here
it is:
public void add(IntObj a) { val=val+a.val; }This can be added to the file for class
IntObj
. It can be
added without taking away the existing add
method. The
reason for this is that Java allows two methods to have the same name
so long as the types of their arguments are different. This is known as
overloading. If we have a variable a
of type
IntObj
, and a call a.add(p)
, the call will
use the method for adding int
s to an IntObj
if
p
is of type int
, and the method for adding
IntObj
s to an IntObj
if p
is of
type IntObj
. Here is a simple program that demonstrates the
use of both:
1 class Ints3 2 { 3 4 public static void main(String[] args) 5 { 6 IntObj a = new IntObj(3), b = new IntObj(7); 7 System.out.println("Starting with: "); 8 System.out.println(" a's value: "+a.value()); 9 System.out.println(" b's value: "+b.value()); 10 System.out.println(); 11 System.out.println("Executing a.add(b)"); 12 a.add(b); 13 System.out.println(" a's value: "+a.value()); 14 System.out.println(" b's value: "+b.value()); 15 System.out.println(); 16 System.out.println("Executing b.add(5)"); 17 b.add(5); 18 System.out.println(" a's value: "+a.value()); 19 System.out.println(" b's value: "+b.value()); 20 System.out.println(); 21 } 22 }On line 12 is the use of
add
with an IntObj
as the argument, on line 17 the use of add
with an
int
as an argument.
Note that the code for the version of add
that has
an IntObj
as its argument has the line val=val+a.val
.
Here a.val
refers to the val
field of the
IntObj
object which is the argument. So when we make the call
a.add(b)
, inside the add
method, a.val
refers to the val
field of b
and val
on its own refers to the val
field of a
. This can
be done because even though val
is a private
field, which we said means only the object it is in can access it, in
fact another IntObj
object can access it if it has the
object passed in as a method argument. If you want to make your code
a little clearer as to which val
belongs to which object,
an alternative way of writing the add
method is:
public void add(IntObj a) { this.val=this.val+a.val; }The keyword
this
in Java means "the object to which this method
is attached". So in any call obj.meth(args)
, in the code
for method meth
, this
refers to obj
.
You can think of val
on its own in an IntObj
method
as a shorthand for this.val
, and similar for any field name
used without being attached to an object name in any method.
a.add(b)
, we change the value stored in
a
. The old value is destroyed - even if another name
had been given to a
through assignment, say c=a
,
aliasing means the old value in c
is destroyed since it is
actually the same thing (not just a copy) of the old value in a
.
A method which changes any values in fields of the object it's applied to is
known as destructive because of this. Note that it is possible,
but not advisable, to have a method which changes fields of its arguments,
for example:
public void badd(IntObj a) { a.val=this.val+a.val; }has the effect that a call
c.badd(d)
changes the val
field of IntObj
object d
rather than
IntObj
object c
.
A method which does its work not by changing any fields but by creating a
new object with the new field of the required value is known as a
constructive method. A constructive method for adding one
IntObj
to another is easily defined:
public IntObj cadd(IntObj a) { return new IntObj(this.val+a.val); }Now, if
e
, d
and f
are all
IntObj
variables
d = e.cadd(f);causes
d
to refer to a new IntObj
object
whose val
field is the sum of the val
fields of
e
and f
. It does not change the val
field of e
or f
. Obviously, however, if
d
referred to any other IntObj
object before, it
no longer refers to it, though it is not destroyed if any other
IntObj
variable also refers to it.
It is necessary to give this constructive version of add
a
different name because although its return type is different -
IntObj
rather than void
, meaning it returns
an IntObj
value - its arguments are exactly the same as the
previous add
method. It is not possible to have two methods
with the same name and same arguments, differing only in return type.
Here is some code which demonstrates this constructive add:
1 class Ints4 2 { 3 4 public static void main(String[] args) 5 { 6 IntObj a = new IntObj(3), b = new IntObj(7), c; 7 System.out.println("Starting with: "); 8 System.out.println(" a's value: "+a.value()); 9 System.out.println(" b's value: "+b.value()); 10 System.out.println(); 11 System.out.println("Executing c = a.cadd(b)"); 12 c = a.cadd(b); 13 System.out.println(" a's value: "+a.value()); 14 System.out.println(" b's value: "+b.value()); 15 System.out.println(" c's value: "+c.value()); 16 System.out.println(); 17 } 18 }
a
and b
are added together to make c
. There is no
difference between the roles a
and b
take, but
a.cadd(b)
might suggest there is. An alternative form of
constructive add makes both arguments to the addition arguments to the
method. Here is the alternative form:
public static IntObj add(IntObj a, IntObj b) { return new IntObj(a.val+b.val); }To use this alternative form, add it to class
IntObj
and then just
replace line 12 in class Ints4
above (and also change line 11
appropriately) by:
c = IntObj.add(a,b);Note that this method call is not attached to any particular object. Instead it is attached to the class name
IntObj
. The reason for this is
that this version of add
isn't associated with any object in
particular when it is called. Both the objects it refers to in its code
are passed to it as arguments. A method in a class which refers only to
fields of that class attached to objects of that class passed as arguments
should be declared as static
, as this new add
method is (the word static
appears before its return type).
When a method is static
, it has no this
. When it
is called in another class, the call should be attached to the name of the
class the method comes from rather than to an object of that class.
Static methods are very much like procedures or functions in non-object-oriented
languages.
Note also this method can also be called add
because
it has different arguments to any other method called add
in
class IntObj
- no other method of that name has two
IntObj
arguments. For complete flexibility, it would be
possible to have three further static add
methods
public static IntObj add(IntObj a, int b) { return new IntObj(a.val+b); } public static IntObj add(int a, IntObj b) { return new IntObj(a+b.val); } public static IntObj add(int a, int b) { return new IntObj(a+b); }This means that all possible combinations of
int
and
IntObj
arguments are covered by an appropriate method.
toString()
methodIntObj
object, we have
used the value()
method to obtain the integer value it stores,
and then printed that. Suppose we attempted to print the object directly,
for example we had an IntObj
object referenced by variable
a
and the statement:
System.out.println(" a's value: "+a);in our
main
method, for example as line 13 of
Ints4.java
. This will compile without error, but
with the code for class IntObj
as described to this point,
when it is run it will result in something like the following being
printed:
a's value: IntObj@1197c6cWhen an object value is joined to a string using
+
, a string
value representing the object is created and joined to the string to create
the new string, just as a string value representing an integer is created
when an integer is joined to a string using +
. However,
unless there is a method giving the string representation of an object,
it will just be converted to a string consisting of the object's type plus
a jumble of numbers and letters as above.
In Java there is a special name used for a method which gives the string representation of an object. If you add a method with the signature:
public String toString()to a class, the code in the method will be used to give the string representation whenever an attempt is made to print the object or to combine it with a string using
+
. Here is an appropriate
toString
method for public String toString() { return ""+this.val; }The
""
represents the empty string (string of length 0).
Joining any integer to any string using +
converts it to
the string representation then joins that to the string, so joining
this.val
to the empty string gives the string representation
of this.val
, which is also an appropriate string representation
for the whole object.
If all these extra methods have been added to our original code for
IntObj
, we will now have:
class IntObj { private int val; public IntObj(int n) { val=n; } public int value() { return val; } public void add(int m) { val=val+m; } public void add(IntObj a) { val=val+a.val; } public static IntObj add(IntObj a, IntObj b) { int c = a.val+b.val; return new IntObj(c); } public static IntObj add(int a, IntObj b) { int c = a+b.val; return new IntObj(c); } public static IntObj add(IntObj a, int b) { int c = a.val+b; return new IntObj(c); } public String toString() { return ""+this.val; } }perhaps with additional methods for the other arithmetic operations.
Last modified: 7 Oct 1999