Client Class Vs Object Class
Client Class Vs Object Class
Everything in Java is part of a class, which is why every Java program we’ve written so far
is defined as has started with the keywords "public class".
So far every class you've written has included a static main method and possibly other
static methods. We call these types of classes "clients". Clients are the class with the
main method that you tell Java to execute.
Here’s how a client class creates three new Bicycle objects each with their own brand
name, model name, list price, and wheel size:
Each of these three variables are an instance of a new Bicycle object, each with its own
data.
This code would be contained within a client class with a name like "BikeManager.java"
that would have a main method. When you run that class it would reference a separate
file like "Bicycle.java" that contains the object definition for "Bicycle" to know how to
create these three variables.
if (!bike1.isSold()) {
bike1.setSold();
Manual m = bike1.getManual();
These two method only refer to the inner state of the bike1 variable, but leave the bike2
and bike3 object instances untouched.
The code for these methods exist in the object definition, but they are executed in the
client.
You'll probably recognize this syntax for calling methods from when we used it with
String variables:
if (name.length() > 0) {
name = name.toUpperCase();
As you can see, you use the name of the specific object variable to call the method on
that instance, like so:
variableName.objectMethod();
// fields
String name;
int grad;
int ID;
double GPA;
int abs;
// constructor
public Student(String name, int grad, int ID, double GPA, int abs) {
this.name = name;
this.grad = grad;
this.ID = ID;
this.GPA = GPA;
this.abs = abs;
// behavior
return (GPA > 2.0 && abs < 10 && grad == 12);
}
In the above you can see there are generally three distinct parts to this code. In Java,
objects are composed of three distinct parts. In your Java class, they are usually
organized like this
STATE
The state of an object is defined by the collection of instance variables who's scope is
that of the entire object. We call these "fields". This collection of variables holds all the
data associated with an object instance. Together, they represent the state of an object,
everything that distinguishes it from other objects of the same type, or from itself at
different points in time. If you created another object with exactly the same state, it
would behave identically, but still be considered a separate object. That is because each
time you make a new object you create a space for it in memory, so even if that memory
stores the same values they are still distinct allocations of data.
CONSTRUCTORS
Constructors are a special type of method that is invoked by the "new" operator. This is
what creates and initialize instances of the object and typically sets the initial value for
all the fields.
BEHAVIOR
The behavior of an object is dictated by what methods you define in the object class.
These methods represent the things a client class can do with an objects of this type.
These methods typically modify the state, but they can also interact other classes or with
the user like a Scanner or a PrintStream does. (System.out is actually an object of the
PrintStream class.)
State
The state of an object is the collection of values that are stored within an object's fields.
DEFINING FIELDS
You define fields the same way define any other variable, but you define them outside
of a method, traditionally right after the class header.
int field2 = 0;
By defining the fields outside any method that gives them the scope of the entire class.
This means that they can be used by any method within the class, so you should try to
limit them to those values that are strictly necessary.
You need to determine what Java data type to use and they can be a primitive data
types, or any type of object including other classes that you have defined. Here’s what
our Bicycle object might have:
...
These are the aspects of a bicycle that are most important for the shop owner, so they
are created as fields.
Fields can be objects as well. For example, you could create a list of all the different
accessories that come installed on the bike:
These accessories might even be objects themselves, defined in Accessory.java; if so, the
field would look like:
ArrayList<Accessory> accessoryList = new ArrayList<Accessory>();
USING FIELDS
Once you've created a field it works just like any other variable. You refer to it by name
whenever you need to use it within your object's code.
listPrice = salePrice;
You can also access an object instance's fields from the client class using the name of
the variable like so:
myBike.listPrice = 1000.00;
}
However keep in mind that directly accessing the fields from the client code is not
considered good style. We will talk about how to improve this in the encapsulation
section.
THIS KEYWORD
Sometimes it can get confusing between what parameters are inside your class and
which are being passed in from an external source. To help make this more clear you
can add the "this" keyword in front of your object fields.
For example, you might have a method that takes in a parameter from the client that
you want to save into the value of your field. You can use the this keyword to make it
easier to distinguish between the parameter and the field.
this.listPrice = newPrice;
We will learn more situations in which to use the "this" keyword in the following
sections.
Behavior
The behavior of an object is the collection of methods within the object.
These methods will represent the different things you want your client class to be able
to do with the state stored in an object's fields. You should think through how your
client class will use your object and that should help you determine which methods to
include in your object.
DEFINING METHODS
You write methods for an object the same way you’ve written other methods, except
you omit the static property.
public returnType methodName(parameters) {
statements;
You will want to define your methods after your fields within your class, like so:
int field2 = 0;
field2 = param;
The job of these methods is to execute some action, so often they will have names that
begin with verbs like "get", "set", "calculate" etc...
As this work is typically performed on the fields, you will usually want to combine your
verb with which field this method acts upon.
Let's look at our Bicycle example. Our Bicycle field has the following fields:
...
This Bicycle class is intended to be used by a shop keeper who sells Bicycles, so some
things they might want to do are:
// the bicycle
isSold = true;
return listPrice;
// during a sale
isSold = true;
return salePrice;
}
As you can see we can create behaviors based on what a user might want to be able to
do with the fields.
This is another case where the "this" keyword could help make things more clear. The
above method could be rewritten:
The client code would use this method on two separate Bicycle variables, like so:
bike2.listPrice = bike1.listPrice;
}
Constructors
Recall that a client class creates objects by using the new operator with a statement
similar to this one:
The right hand side of the declaration looks a bit like a method call that takes in
parameters. This is because the keyword "new" does call a method, a special method
called a "constructor".
WRITING CONSTRUCTORS
In your object class you can specify what happens when your client calls the "new"
keyword by adding a special type of method, the constructor. Here is what the
constructor looks like for our Bicycle class:
this.brand = myBrand;
this.model = myModel;
this.price = myPrice;
As you can see there are a couple things in the constructor header that are different
from typical methods:
2. There is no return type (void, int, etc.) specified for the method, because a constructor
will always return an object of its own class. If you specify a return type by mistake, even
void, you will have a standard method, not a constructor and the client call above won’t
work.
Since the constructor is called when creating a new instance of an object you will want
to do any work to set up the object for use by the client. Often this means initializing the
fields. If we want the user to be able to specify the initial values for the fields, we need
parameters that match the fields.
String brand;
String model;
double price;
boolean isSold;
double salePrice;
brand = myBrand;
model = myModel;
price = myPrice;
isSold = false;
salePrice = 0.0;
Notice:
This constructor only accepts the value of three fields from the client; the other fields are
set to defaults.
Because we set all the fields values within the constructor we no long need to set their
values at their declaration. This approach of splitting declaration and initialization is the
preferred style.
We used different names for the parameters than the fields, but because they store the
same type of data it’s really tempting to write:
brand = brand;
model = model;
price = price;
...
But, this will NOT set the values of the fields! Remember that parameters create local
variables of the same name in the scope of a method, and that variable will "mask" the
field of the same name in this method, so brand = brand uselessly sets itself to its own
value. Oops!
Java does permit you to explicitly qualify that you want the object to refer to its own
field by using the keyword this. You could write the constructor using the field names as
parameter names as long as you distinguish the difference with the "this" keyword:
this.brand = brand;
this.model = model;
this.price = Price;
...
DEFAULT CONSTRUCTORS
You do not have to provide a constructor for an object at all. If you don’t, Java provides
a default for you known as the zero argument constructor. In the case of our Bicycle
class it would look like this:
public Bicycle() {
If you do not specify a constructor yourself, then when the client class creates a new
object it cannot pass in any arguments. This means that the fields will initially store their
default values:
OVERLOADING CONSTRUCTORS
You can in fact have as many constructors as you like through overloading. In this way
you can allow users to decide what amount of data they want to specify when creating
and object, and what amount they want to rely on default values.
To do this properly you should first create a constructor that initializes all fields inside
the constructor:
String brand;
String model;
double price;
int tireSize;
boolean isSold;
double salePrice;
public Bicycle (String brand, String model, double price, boolean isSold,
double salePrice) {
this.brand = brand;
this.model = model;
this.price = price;
this.isSold = isSold;
this.salePrice = salePrice;
As you can see we have moved all the field declarations within the constructor, giving
the user complete control over the initial state of the object. Now that this constructor
exists you can add other constructors that include default values so your user doesn't
have to set everything. You can call the most specific constructor from the less specific
constructors to reduce redundancy. You call one constructor from the other with the use
of the "this" keyword in the place a method name would normally be.
If some bikes don’t have a model, for example, you could provide:
public Bicycle() {
What is Encapsulation?
The modern world depends on a concept called "abstraction" that separates how to
use something from the details of how it’s implemented. You can press the brake pedal
of a car and stop effectively without knowing anything about disc brakes, calipers,
hydraulics, or frictional coefficients – thank goodness!
In object oriented programming this separation of how to use code from its
implementation details becomes important in facilitating relationships between code
entities. Imagine you are writing an object that a coworker is going to build off of in
their code, it would take forever if everyone had to understand every single line in the
code base just to be able to use eachother's work! Instead you want to clearly separate
the code in your object that other code will use from the intricate details of how you
maintain your object.
The way that you define this separation is by "hiding" implementation details from view
with something called "encapsulation". Encapsulation, or information hiding, was
perhaps the first major step forward when Object Oriented programming emerged in
the 1980s, allowing one team to use the products of another team without having to
understand how it worked internally.
Encapsulation also allows you to strictly control how a user interacts with your object. By
hiding all the inner workings of your object from the user you can guarantee that your
object stays in a good state.
For example, you can hide your fields from the user so that you are the only one who
can set their values. This can prevent your user from accidentally setting field values that
don't make sense.
Just imagine if you didn't have a brake pedal and everyone driving was expected to
know how to apply pressure to the disk breaks, chances are a lot of people would ruin
their cars! By hiding the inner workings of the car with the casing and providing a clear
way to interact with the brakes (the pedal) you help keep the car in working order.
Public vs Private
If "encapsulation" is the act of "hiding" things from your user, how do you set the
visibility of code elements?
Obviously, some things must be public or no one could use the object! But now by
using "private" and "public" intentionally you can decided exactly how external code
should interact with your object.
PRIVATE FIELDS
...
As they store the foundational information about your object fields should generally all
be made private. This way you can use them like normal variables within your class, but
your client code cannot change their values directly. This can protect the inner state of
your object from being corrupted.
If you want your client code to know the current value of a field, you'll want to write
separate public methods that limit the way a user interacts with your fields. That way
you can protect your object in several ways:
Restrict the value of fields to a range of valid values (maximum speed, minimum price,
only certain values, etc.)
Prevent clients from making assumptions about field values that you may not have
intended.
Let's say we are writing a class that represents the current state of a Student within a
school.
These pieces of information are all either very private, or have very specific limitations
on what is considered "valid" values. For example, in some schools a GPA can only be
between 0.0 and 4.0, but if you leave that field private client code could set it to a
number that doesn't make sense.
PRIVATE METHODS
When a method is declared as "private" it means you can only call that method from
within the class in which it is defined.
Usually, methods are public unless they are an internal "helper" method that is used by
other public methods. These private methods can help you remove redundancy and
clean up your own work. They are not for external users to have access to behavior, but
rather a way for you to internally structure your own code.
Let's say we are writing methods for our Student class, and we find that we keep
repeating the check to see if they are eligible to graduate. This is a check you might
have to do often, but is such an important state you might not want external code to be
able to perform that update. If you make a private method you can call if within your
class to eliminate redundancy, but you protect your Student state from being updated
by a client class.
private boolean updateGrad(double gpaUpdate, int attendanceUpdate) {
daysAbsent += attendanceUpdate;
PRIVATE CONSTRUCTORS
private MyClass() {
Rarely will you want to make a constructor private, as the constructor is what enables
your user to even create an instance of your object. However, if you are overloading
constructors and you are using a constructor that sets each individual field to eliminate
redundancy you might want to make it private and only expose the constructors that
take the correct parameters for your user.
this.name = name;
this.gpa = gpa;
this.daysAbsent = daysAbsent;
this.canGraduate = canGraduate;
}
/* Create a new student at the beginning of the school year */
/* this method works even though the other Student's fields are marked as
private */
ACCESSORS
Accessors are a type of method that exposes the current value of your field to external
code. You can think of these as a "read only" method for your field's values. Often they
are referred to as "getters" because typically their names are getFieldName() like so:
return gpa;
It's common for you to have an accessor method for each of your fields. They typically
do not take in any parameters and simply return the current value of the field they are
accessing.
MUTATORS
Mutators are a type of method that allows external code to change the value of a field.
This is a lot of responsibility, so often you will want to add logic to these methods to
maintain a good state for your fields.
this.name = name.toLowerCase();
Mutator methods typically take in a parameter and change the value of a field after
doing some checks to see if it is an appropriate value.
The static keyword
Until we started dealing with objects, all the methods we wrote were "static" and the
only variables we defined outside of static methods were class constants, who's values
never varied.
Since we started writing our own methods we stopped using the "static" in front of
methods and fields, so what does static really do, and how is it useful? Static simply
means "not part of an object", or "not dynamically created" as part of an object when
the object is created.
STATIC FIELDS
When a field is static it is shared by all objects in a class. Sometimes it’s referred to as "a
class variable". This means each individual instance of that object can all read the field's
value and update it. There is only one instance of this field across all instances of the
object so the static field's current value is the last value set by any object.
accumulating statistics or totals for all members of class: total sales for all vendor
objects, the number of Bicycle objects created, etc.
public class Bicycle {
public Bicycle() {
bikeCount++; // stores the count of how many Bicycle objects have been created
shared values that all objects of a class use: current speed limit, value for gravity, and
other values that might change but need to affect all objects.
minDrivingAge = newDrivingAge;
Static fields belong to the class as a whole, not to a specific object of the class. So, if you
reference it outside the class, you use the class name to qualify it, not an object name:
for example, Bicycle.numberOfBikes, Vendor.totalSales, etc.
The class constants we saw before are simply class variables that are also final and so
can never change. When they are public, they are usually "universal constants" like
Math.PI or Color.BLUE.
Static fields behave differently from the typical instance fields.
Class.name objectVariable.name
"statically" allocated before any objects are created "dynamically" allocated each time an object is created
STATIC METHODS
Like static fields are shared across all instances of an object, so are static methods. This
means that in any class, a static method is part of the class as a whole:
The main method that starts a Java program is always static. It usually creates the first
objects. There is only one main method for each execution of a Java program.
From within a static method you cannot call a non-static method without specifying
which instance that method belongs to; for example, bike1.getBrand(), or
vendor1.addSale().
When a static method exists within an object declaration it’s often a "public service"
method. This is often something that doesn’t deal with any objects at all, but just acts on
data provided as parameters or static variables. For example, whenever we use methods
from the Math class: Math.pow(2,2).
This project is designed to help you practice building your own object class and testing
it with a client class. You will be creating two classes, one called Fraction and the other
called FractionCalculator. The Fraction class is an object that holds information about a
fraction (numerator and denominator). It will have several constructors and both private
and public methods implementing the behavior of a fraction. The FractionCalculator
class is a class that will allow the user to enter in fractions and operations, calculating
and displaying the result. It will run until the user tells it to quit. When this program is
complete, you won’t have to second guess your fraction arithmetic ever again!
Fields
two private instance variables to hold the numerator and denominator as ints
Constructors
o If the user enters a negative denominator bump the negative sign to the numerator. For
example, -3/-2 should be converted to 3/2. Likewise, 5/-3 should be converted to -5/3
one parameter constructor that initializes the object equal in value to the integer
parameter.
o example: Fraction myFrac = new Fraction(3) would create a Fraction with numerator
equal to 3 and denominator equal to 1.
zero parameter constructor that initializes the object to 0, meaning the numerator is 0
and the denominator is 1
o example: Fraction myFrac = new Fraction(); would create a fraction who's decimal value
is 0
You should eliminate as much redundancy as possible by letting your constructors rely
on one another using the "this" keyword.
Methods
Method to
parameter return description
implement
getNumerator() none int exposes the value of the numerator field to the user
getDenominator() none int exposes the value of the denominator field to the user
add() Fraction Fraction returns a new Fraction that is the sum of other and this fractions
other
Method to
parameter return description
implement
subtract() Fraction Fraction returns a new Fraction that is the difference between the other
other and this fraction
multiply() Fraction Fraction returns a new Fraction that is the product of the other and this
other fraction
divide() Fraction Fraction returns a new Fraction that is the division of the other and this
other fraction, throw an IllegalArgumentException() if the user asks
you to divide by 0
equals() Object other boolean must take in an "Object" to properly override the Object class's
equals method, but should ultimately check if two fractions are
equal
toLowestTerms() none none converts the current fraction to the lowest terms
gcd() int num, int int takes in two ints and determines the greatest common divisor
den of the two ints, should be a static method
equals()
Override the Object equals() method so that it accurately determines whether or not
two fractions are equal. In order to have it override, it has to take an Object as a
parameter. Your method should check whether or not the parameter is an instanceof
Fraction, since if it is not a Fraction it cannot be equal. Don’t forget to cast the
parameter to a Fraction after you check if it is an Object of type Fraction so that you can
access its variables. Two fractions are equal if they represent the same number (i.e. 3/6 =
1/2 and -2/3 = 2/-3).
toLowestTerms()
To convert a fraction to lowest terms we have to determine the greatest common divisor
(factor) between the numerator and denominator. The greatest common divisor of two
numbers a and b, is the largest number that evenly divides both a and b.
The Euclidean Algorithm is a fast method for determining the GCD of two numbers.
Here is pseudocode for its implementation:
set a to b
return a
Loop
Value of a at end of loop run Value of b at end of loop run a%b
Iteration
3 42 21 105 % 42 = 105 - 84 = 21
4 21 0 42 % 21 = 0
gcd()
Implement gcd() as a public static method that takes two integers as parameters and
returns an int that is their greatest common divisor.
validFraction() String input boolean returns true if the parameter is in the form "a/b"
where a is any int and b is any positive int
getOperation()
Here is example output from a call
to getOperation():
At the end of this run, getOperation would have returned “*”.
validFraction()
Some things to be mindful of when implementing the validFraction() method:
The first character may or may not be a "-" character. If a negative shows up anywhere
else, then it is not a valid fraction. It may be helpful to remove the "-" character if there
is one.
If there is no "/" character, then every character in the string must be a number (if you
removed the "-" sign).
If there is a "/" character, then it may be helpful to create substrings for the numerator
and denominator.
getFraction()
Here is example output from a call to getFraction(). If the user enters any thing that is
not a valid Fraction, it should re-prompt them until it is
valid:
This call would return a new Fraction object equal to -31/1. No user input should throw
an exception! If you are getting exceptions, then it is likely your validFraction method
isn’t correct.
1. Write a short introduction method that describes the calculator program and welcomes
your user
3. As long as the user enters something that’s not "q" or "Q" when asked for an operation
you should run the calculator
4. Get two fractions from the user and then perform whichever operation they ask for