Objects
and Classes
[When asked] "...why is it called a class?" ... I reply "Because that's
the place
where
we teach objects how to do things".
-Rich Pattis
A class is a blueprint
for a collection of objects. A class describes a
collection
of objects that have similar attributes and behaviors.
Example: Dog is a real-world
class
Every class has associated data, or attributes.
Attributes for Dog
class:
breed, color, height, weight, gender, name
Every class has associated actions.
Actions for Dog class: bark,
sleep,
eat
Instances of the Dog class, or objects in the Dog class:
my dog Otis,
your
dog, former president Bill Clinton's dog Buddy
If we translate the Dog class into a Java class, we get this:
class Dog
{
...
String breed;
String name;
double height;
double weight;
char gender;
// In order to be
able to create specific Dog instances,
or
objects of type Dog, we need
// a method (a
constructor) that creates an
instance:
public Dog(String
theName, char theGender)
{
name =
theName;
gender
= theGender;
}
public void bark()
{
System.out.println("Rff, rff");
}
public void sleep()
{
System.out.println("zzzz, zzzz");
}
public void eat()
{
System.out.println("slurp");
}
} // end of Dog class
Now if I'm writing a program, I can create a Dog object:
Dog otis = new Dog("Otis", 'm');
// this object is a software
representation
of my dog
// Otis
I can call the methods that were defined in the Dog class on my Dog
instance:
otis.bark(); // output to screen:
Rff, rff
To create an instance of any class:
Use the new operator and invoke the
constructor.
new ClassName(... any needed
arguments...)
to assign the address of this new
object to a reference variable of type ClassName:
ClassName myRefVar = new ClassName(arguments);
The use of the new keyword causes the creation, or construction, of a
new
object. The object is an instance of the specified class. When new is
used,
a constructor for the class is called.
Defining
Methods
A method definition contains:
1. An access specifier (like
public)
-- determines which other methods can call
your
method
-- most methods are declared public, so that
all
other methods in your program can
call them
2. The return type of the
method (like void - which means no value is
returned
- or int, String, etc)
-- some methods return a value
Ex: The method Character.isDigit() returns a boolean value
-- a return type of void means that the
method
executes some statements without
returning a value
3. The name of the method
(such as bark)
4. A list of the parameters of
the method, enclosed in parentheses (our
Dog
constructor takes the parameters theName, theGender)
-- some methods take in other information
-- the constructor for Dog takes the Dog's
name
and gender, and uses those values
in the body of
the method
5. The body of the method,
which is enclosed in curly braces - a
sequence
of statements
Syntax:
class ClassName
{
....
accessSpecifier returnType methodName (parameterType
parameterName, ... )
{
method body
}
...
}
Ex:
public class Speaker
{
...
public String sayHi()
{
String
message = "Hello Friend";
return
message; // this method
returns
to the caller a reference to the String message
}
}
Note: A method's execution ends
when a return statement is executed.
The
return value becomes the value of the method call expression.
What can we do with our Speaker class? We can compile it. But we cannot
run
it, because it does not contain a main method. So we write a test class
-
a class with a main method that allows us to try out the Speaker class.
Ex:
public class SpeakerTest
{
public static void
main(String[] args)
{
//
Create a new Speaker
Speaker friendly = new Speaker();
System.out.println(friendly.sayHi());
}
}
So your program consists of these 2 classes. To run your program, you:
1. Make a subfolder for your program.
2. Make two files, one per class.
3. Compile both files.
4. Run the test program.
Defining Instance Fields
Let's add some data to our Speaker class:
public class Speaker
{
private String
name; // the name of the person to
speak to
public String
sayHi()
{
String message = "Hi " + name;
return message;
}
}
An instance field contains:
1. Acess specifier (typically private)
2. Type of the variable (e.g., String, int, double)
3. Variable name
Syntax:
accessSpecifier Type
varName;
Constructors
We now need to change our Speaker class so that we can construct
Speaker objects with different names:
class Speaker
{
public
Speaker(String personName) // a
constructor for the Speaker class
{
name = personName;
}
... // the stuff we
included before
}
A constructor allows us to create instances of our class. The
constructor
has the same name as the class, and is typically public.
Example:
To create an instance of Speaker class:
Speaker mrFred = new Speaker("Mr. Fred");
mrFred.sayHi(); // output: Hi Mr. Fred
Example: Write a class that
represents a circle. Write another class to
test the Circle class.
Designing a Class
Think about the objects that will be created from the new class
type. Think about:
- what the object knows
- what the object does
Example:
For an Alarm class -
think about what an Alarm object knows and does
Example: For a
Car class -
think about what a Car object knows and does
Instance variables
are an object's data, i.e., the things an object knows about itself.
Things an object can do are called methods.
Note: Often our classes contain
methods that read or write the values
of the instance variables.
Designing
A Class, Start to Finish
Example: Rectangle class
Before you start coding, think about how the objects of your
class
should behave. What operations should a Rectangle be capable of, for
example?
- area
- perimeter
- get current length
- get current width
- set current length
- set current width
These operations that you chose should become methods in the class.
What data do you want to store for each Rectangle object?
Example: BankAccount - write a
class that represents a bank account
1. Decide what operations/methods you need
What operations do you want
to
carry out with a bank account?
- get balance
- deposit money
- withdraw money
If you have a BankAccount object called myChecking, you would like
to
be able to call methods like:
myChecking.deposit(2000); // add $2000 to my checking account
myChecking.withdraw(30); // get some cash
System.out.println(myChecking.getBalance()); // let me see
my
current
balance
So the BankAccount class should contain the methods:
- deposit
- withdraw
- getBalance
2. Figure out what information each method needs to receive (parameters), and what will be the return value, if any (what do they
compute?).
In our examples, the deposit
and withdraw methods took a double value, a money amount, and did not
return a value. The getBalance method did not take any parameters, but
returned a double value, the account balance. So we have these method
headers:
public void deposit(double depositAmount)
public void withdraw(double withdrawAmount)
public double getBalance()
3. What information do we need to store about each BankAccount instance?
We need to keep track of the bank
account's balance: double balance
4. Next, let's think about the constructors - how do we want to be able
to
create BankAccount objects?
- The default balance is 0.
- Some nonzero initial balance.
So we could create a
BankAccount
instance like
this:
BankAccount myChecking = new BankAccount(); // this should
create
my
account with a zero balance
or with this statement:
BankAccount myChecking = new BankAccount(500); // initial
balance
is 500
Two constructors:
- public BankAccount()
- public BankAccount(double
initialBalance)
When we use the same method
name
for multiple methods that have
different parameters, we say the method name is overloaded.
The constructors and methods of a class make up the public interface of
the class. These are the operations that any code in your program can
call to create and alter BankAccount objects.
Ex: the public interface of the
BankAccount class is
public BankAccount()
public BankAccount(double initialBalance)
public void deposit (double depositAmount)
public void withdraw(double withdrawAmount)
public double getBalance()
The behavior of our BankAccount class allows you to carry out all the
common operations on bank accounts.
Example: Using some BankAccount
objects (this code would not go in the BankAccount class - it might go
in a class called BankAccountTest, for example)
Take $3000 from Mom's
savings account and move it to my checking
account:
double amt = 3000;
momSavings.withdraw(amt);
myChecking.deposit(amt);
We can use objects of the BankAccount class to manipulate money without
knowing how the BankAccount objects carry out these operations.
Providing the user of a class with the public interface and hiding the
implementation details is called encapsulation,
an important object-oriented concept.
Implementing the Class
Now that we have decided what methods and constructors we want our
class to have, and how we want to use them, we need to implement them
and add necessary instance fields to our class.
What data do we need to store for our bank account objects? The balance.
Example: BankAccount class
definition
public class BankAccount
{
private double
balance; // only allow access
to the balance through the getBalance() method. Only the BankAccount
// methods and constructors can
access.
// The balance is a private implementation detail of this class - this
is encapsulation!
public
BankAccount() // create a bank account
with a 0 balance
{
balance = 0;
}
public
BankAccount(double initialBalance) //
create a bank account with the specified balance
{
balance = initialBalance;
}
public void
deposit (double depositAmount)
{
balance += depositAmount;
}
public void
withdraw (double withdrawAmount)
{
if((balance -
withdrawAmount) >= 0) // do not allow account to be overdrawn
balance -=
withdrawAmount;
}
public double
getBalance()
{
return balance;
}
}
Note:
when I refer to an
instance variable like balance in my code, I am referring to the
balance of the current object.
Example: BankAccountTest class
public class BankAccountTest
{
// This class
tests the BankAccount class
public static
void main(String[] args)
{
BankAccount myChecking
= new BankAccount(); // initial zero balance
myChecking.deposit(2000); // deposit a check for $2000
System.out.println("My
balance is: " + myChecking.getBalance());
BankAccount momSavings = new
BankAccount (5000);
momSavings.withdraw(2000);
}
}
Steps in creating a class:
- Consider what you need to do
with instances of
the class - what
operations do you need for the current application? For example, if you
are writing a Vehicle class, you cannot possibly include all attributes
of Vehicles, or all possible operations of Vehicles - there are too
many. You must choose the operations and attributes you need for the
given problem you are solving - this is called abstraction. Abstaction is an
important OO concept.
- Choose method names, and
determine the
parameter types and return
type for all methods.
- Write documentation that
indicates exactly what
each method does.
- Determine what instance
variables you need.
Determine the type
and names of these instance variables.
- Determine what constructors
you need for
objects of this class.
- Implement the methods.
- Test the class.
Exercise: Write a class that
represents a coin that can be flipped.
Exercise: Write a class to test
your Coin class. This class should prompt the user to choose either
heads or tails. Then it should toss a coin and tell the user if they
won or not.