CSE131: Compound Data (Continued)
Copyright © 1996-2005
Kenneth J. Goldman
Objects as Containers
Let's see some more examples of objects used as data containers.
Methods that Update Instance
Variables
So far, we've seen objects where instance variables do not
change after they are initialized, but we often want objects to
contain values that change over time.
Example: Account
Let's consider an Account
object that keeps track
of a bank balance.
Method |
Parameters |
Mutates |
Returns |
constructor |
int openingBalance |
sets initial balance |
object reference |
deposit |
int dollars |
increases balance by given amount |
void |
withdraw |
int dollars |
if enough money, decreases balance by requested
amount |
true iff sufficient funds |
transfer |
int dollars
Account destination |
if enough money, transfers dollars from
this account to destination account |
true iff sufficient funds |
toString |
|
|
String "$x.00" |
public class Account {
int balance;
Account(int openingBalance) {
balance = openingBalance;
}
public void deposit(int dollars) {
balance = balance + dollars;
}
public boolean withdraw(int dollars) {
if (balance < dollars)
return false;
else {
balance = balance - dollars;
return true;
}
}
public boolean transfer (int dollars, Account destination) {
if (withdraw(dollars)) {
destination.deposit(dollars);
return true;
}
else
return false;
}
public String toString() {
return ("$" + balance + ".00");
}
}
Objects that Invoke Methods on Other
Objects
- Notice that the transfer method takes another
Account
object as a parameter and calls
the deposit
method on that object.
- This is important. The idea is that the balance is
encapsulated inside the
Account
object
and is only accessible through the methods of that
object.
- Each object has a life of its own.
Here is an example use of the Account
class:
Account myAcct = new Account(100);
myAcct.deposit(25);
System.out.println("My balance is " + myAcct); // myAcct.toString()
// called implicitly
System.out.println("Withdraw $50? " + myAcct.withdraw(50));
System.out.println("My balance is " + myAcct);
System.out.println("Withdraw $100? " + myAcct.withdraw(100));
Account yourAcct = new Account(50);
myAcct.transfer(60, yourAcct); // The boolean return value is ignored
System.out.println("Mine has " + myAcct + ", yours has " + yourAcct);
The output from this code would be
My balance is $125.00
Withdraw $50? true
My balance is $75.00
Withdraw $100? false
Mine has $15.00, yours has $110.00
Example: Temperature
Suppose we want to keep track of the current temperature, the
high temperature, the low temperature, and be able to read the
temperature in Fahrenheit or Celcius.
Method |
Parameters |
Mutates |
Returns |
constructor |
initial tempature (°F) |
sets current temp., low, high |
object reference |
getTemp |
|
|
current temperature (°F) |
setTemp |
temp (°F) |
updates current temp, and high or low if needed |
|
getHigh |
|
|
high temp (°F) |
getLow |
|
|
low temp (°F) |
reset |
|
sets high and low to current temp |
|
toCelcius |
temp in °F |
|
temp in °C |
toString |
|
|
"X degrees Fahrenheit" |
public class Temperature {
int temp;
int high;
int low;
Temperature(int initialTemp) {
temp = high = low = initialTemp;
}
public int getTemp() {
return temp;
}
public int setTemp(int temp) {
We have a problem here. The parameter temp
masks the instance variable temp
. How can
we access the instance variable instead? The solution is to use
this
, which refers to the current object.
this.temp = temp;
if (temp > high)
high = temp;
if (temp < low)
temp = low;
}
public int getHigh() {
return high;
}
public int getLow() {
return low;
}
public void reset() {
high = low = temp;
}
public int toCelcius(int f) {
return (f - 32) * (5.0 / 9.0);
}
public String toString() {
return ("" + temp + "degrees Fahrenheit");
}
}
As an alternative to the above, we can define
toCelcius
to be a static method of the
class; a static method does not require an instance of the
class.
public static int toCelcius(int f) { // doesn't use instance variables
return (f - 32) * (5.0 / 9.0);
}
An example use of this class:
Temperature stl = new Temperature(40);
// high 40, low 40, temp 40
stl.setTemp(60);
// high 60, low 40, temp 60
System.out.println("High of " + stl.getHigh() + ", low of " + stl.getLow() +
", currently " + stl);
stl.reset();
// high 60, low 60, temp 60
stl.setTemp(75);
// high 75, low 60, temp 75
System.out.println("Low is " + stl.getLow() + "F, " +
stl.toCelcius(stl.getLow()) + "C");
// If a static method was used instead, this would be called as
// Temperature.toCelcius(stl.getLow())
The output from this code would be
High of 60, low of 40, currently 60 degrees Fahrenheit
Low is 60F, 16C
Calling Methods from Within an
Object
Example: Sphere
Object
Method |
Parameters |
Mutates |
Returns |
constructor |
x, y, z, r |
sets center position and size of sphere |
object reference |
moveTo |
x, y, z |
sets center position |
|
resize |
r |
sets radius |
|
volume |
|
|
volume of sphere |
inside |
x, y, z |
|
true iff (x,y,z) is within the sphere |
toString |
|
|
"sphere at X,Y,Z with radius R" |
public class Sphere {
double x,y,z,r; // center and radius
Sphere(double x, double y, double z, radius r) {
moveTo(x,y,z);
resize(r);
}
public void moveTo(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public void resize(double r) {
if (r > 0)
this.r = r;
else
r = 0;
}
public double volume() {
return (4 * Math.PI * Math.pow(r,3))/3
}
public boolean inside(double x, double y, double z) {
return (distanceToCenter(x,y,z) < r);
}
double distanceToCenter(double x, double y, double z) {
return Math.sqrt(Math.pow(x - this.x, 2) +
Math.pow(y - this.y, 2) +
Math.pow(z - this.z, 2));
}
public String toString() {
return ("sphere at (" + x + "," + y + "," + z + ") with radius " + r);
}
}
Some notes:
- Again,
this
is used to reach masked instance
variables.
- Methods may be called within an object without
this
. (For example, the constructor calls
moveTo
and resize
, and
inside
calls distanceToCenter
.)
- Not all methods are necessarily public; here we chose to
leave
distanceToCenter
out of the public
interface. Therefore, it becomes a private method
and cannot be called from outside. For example, if you
attempted to write this code:
Sphere mySphere = new Sphere(3, 4, 6, 5);
double dist = mySphere.distanceToCenter(2, 3, 4); // ERROR
the Java compiler would complain that there is no such
(public) method.
Data Abstraction
Let's look back at what we've been doing lately.
- We've seen classes as a way to define new types of
objects.
- We've seen objects as containers, encapsulating data
inside themselves.
- Our objects did not contain random collections of data,
but data that have meaning as a whole (for example, the center
and radius of a single sphere).
- Our objects had meaningful operations on them that modeled
operations on the corresponding real-world objects (for
example,
deposit
and withdraw
).
- Some data and methods can be hidden, used only inside the
object as part of the internal representation or
implementation.
So objects really provide something much more powerful than
just a container. They give us a means to think about
collections of data as abstract entities. This form of
abstraction is called data abstraction and will be the
subject of the next few lectures.
Kenneth J. Goldman
Last modified: Thu Jan 30 16:22:11 CST