Today's class introduces some of the fundamental concepts of object-oriented programming. The idea of delegation and the mechanics of delegating to a utility class are discussed.
In 1020, the client is you, the programmer of the main
method. You are called a client because you will need to shop for
components that can provide you with services that can help you
solve a programming problem.
We have already used one component named System.out
;
that component provided us with services named
print
and
println
that let us send output to a console.
As the client, you can choose to entrust computation to a component.
What are some advantages of delegating computation?
Suppose you want to know how to translate "hi" in French.
1. Find someone who is fluent in French.
2. Ask, "Celine, how do you say hi in French?"
3. Celine replies, "Salut."
To delegate computation you need:
The component will:
In Java, a utility class is a component that groups together related tasks into a single place.
For example, the utility class java.lang.Math
groups together a number of mathematical tasks. You can compute
the square root of 2.0 by writing:
double irrational = Math.sqrt(2.0);
Math
sqrt
2.0
The component will:
1.4142135623730951
, which we store in the
variable named irrational
static
Methodsdouble irrational = Math.sqrt(2.0);
sqrt
is a static
method that is a
member of the utility class Math
.
A method performs a task.
The parentheses enclose the information you want to give
to the method.
In this example, the information is the literal 2.0
.
Each piece of information is called an argument.
We say, "we invoke the sqrt
method on
the Math
class passing 2.0
as the argument."
*Note that you do not have to use a literal as an argument.
Any value whose type is compatible with double
can be used as an argument for sqrt
.
static
Methods
Some methods require more than one argument to invoke. For
example, the hypot
method of Math
computes the length of the hypotenuse of a right angle triangle.
public class Hypotenuse { public static void main(String[] args) { double side1 = 3.0; double side2 = 4.0; double side3 = Math.hypot(side1, side2); } }
Multiple arguments are passed to the method using a comma followed by a space to separate the arguments.
static
Attributes
The Math
utility also stores some mathematical
constants, namely the values for e and π. Data stored by
a class are called static
attributes. Like
variables, attributes have a name, type, and value.
Constant values are usually named using all capital letters.
The constants in Math
are called E
and PI
; they both have type double
.
You access them by using their name and no parentheses.
System.out.println(Math.E);
System.out.println(Math.PI);
double radius = 5.0; double circleArea = Math.PI * radius * radius;
Attributes can be other components called objects, and the client can delegate to these objects. You invoke methods on an object much like you invoke methods on a class.
One example is the utility class named System
.
It has an attribute named out
that we have been
using to print strings to the screen.
System.out.println("Hello");
It also has an attribute named in
that on a PC
can be used by another component to read input from the keyboard.
import java.util.Scanner; public class InputExample { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.println("Enter the temperature in Fahrenheit"); int degF = input.nextInt(); // convert degF to Celsius... } }
Notice that by giving the mathematical constants a name
(E
and PI
) it is very easy for
the reader to tell what they represent. This might be a
good idea for client code as well. For example, what does
the following fragment do?
double c = 0.5555555555555556 * (f - 32);
Literals such as 0.5555555555555556
and
32
that appear in an expression are called
magic numbers because it is often difficult to determine
exactly what they represent (but they work!).
If we used some meaningful names, it becomes clearer that the expression converts from degrees Celsius to degrees Fahrenheit.
final double DEG_F_PER_DEG_C = 5.0 / 9; final int ZERO_C_IN_F = 32; double c = DEG_F_PER_DEG_C * (f - ZERO_C_IN_F);
The modifying keyword final
means that we can only
assign a value to the modified name once (i.e.,
DEG_F_PER_DEG_C
and ZERO_C_IN_F
are effectively constants).
Java convention and our coding style uses all capital letters and underscores for names of constants.
Our coding style says that
the only magic numbers you may use outside of a final
statement are -2, -1, 0, 1, and 2.
The methods and attributes of a class that are available to ordinary clients are called the features of the class. One tool that software engineers use to concisely convey class features is the Unified Modelling Language (UML) class diagram.
For the Math
utility class, you start by writing
« utility » java::lang::Math |
You list the attributes in the next section. You give the attribute name, followed by a colon, followed by its type.
« utility » java::lang::Math |
E: double PI: double |
You list the methods in the next section. You give the method name, the comma separated list of parameter types in parentheses, and the return type.
« utility » java::lang::Math |
E: double PI: double |
hypot(double, double): double sqrt(double): double |
A UML class diagram gives a concise description of the features of a class; however, as a client you probably need more information than the class diagram provides. For this, we introduce the notion of an interface.
A driver drives a car using a reasonably small number of controls
and information displays:
The controls and displays form the driver's interface to the car.
The car's interface allows the driver to easily control the car without the driver needing to know how the car exactly works. Imagine how difficult it would be to drive a car if the driver had to synchronize the control of all of the individual car components.
As a client programming in Java, you are primarily interested in two features when using a component:
The attributes and methods that are directly usable by a client are called public features of the component.
The public features are documented in the Application Programming Interface (API) of the component.
The API only describes what actions a component can perform, but not how the component actually performs the action.
The component can also have features that are hidden from the client. These private features are not part of the component's API (see the discussion on access modifiers on page 62 of the textbook). These hidden features are typically related to how the component provides its functionality.
Features that are labelled protected are part of the API, but are not directly accessible to normal clients. They are used by special clients (class implementers) when extending an existing class.
In 1020, we use the term encapsulation to describe the separation of the interface from the implementation.