Download public static void main(String[] args)

Document related concepts
no text concepts found
Transcript
IOPROG – Ingmar Olsson
Begin with Java 2
Begin with Java 2
Object-Oriented Programming Foundations
Table of Contents
Object-Oriented Programming – OOP ………………………………………
2
Generics ……………………………………………………………………………………
23
Java and Database Technique without Database – ArrayList ….
38
An Application using ArrayList as a Database ………………………….
46
1
IOPROG – Ingmar Olsson
Begin with Java 2
Object-Oriented Programming – OOP
The three “pillows”
In order to understand OOP, you need to understand the following three concepts or OOP “pillows”:
Encapsulation
Inheritance
Polymorphism
(“Begin with Java 2”)
(“Begin with Java 3”)
(“Begin with Java 3”)
The first “pillow”: the concept class–encapsulation–abstract datatype
In Java and all other OOP languages, we refer to an encapsulated abstract, textual or visual construction
(template, blueprint ) as a class.
A slogan:
“Object Oriented Programmers do it with class!”
What is a class?
A BankAccount is a class, not the way the money is earned for the BankAccount.
A Student is a class, not the air a student breath.
As we already said on page 2 in “Begin with Java 1”, all Java programs consist of one or more class definitions.
As we already said, even a stand-alone Java application needs a primary class definition, must have the same
name as the filename it is saved in and requires a method named main().
What is an object?
Other classes defined by a Java programmer (or available in the Java JDK via the import directive). Once the
class definition is available, that programmer, (or other programmers), can use it to produce millions of nearly
identical objects or instances (the terms object and instance are used interchangeably).
An object is a software construct that encapsulates data, along with the ability to use or modify that data, into a
software entity.
What is an Object-Oriented Program?
An Object-Oriented Program consists of a group of cooperating objects, exchanging messages, for the purpose of
achieving a common objective.
What is encapsulation?
Encapsulation is the concept that an object should totally separate its interface (public methods in the class) from
its implementation (the code in the methods). All the data and implementation code for an object should be
entirely hidden behind its interface.
The idea is that we can create an interface and, as long as that interface remains consistent, the application can
interact with our objects. This remains true even if we entirely rewrite the code within a given method thus the
interface is independent of the implementation.
What is abstract datatype?
Object oriented languages allow you to create whole new types with their own data (fields, data members)
and with their own operations (methods) that apply to that internal data. They are called abstract data
types.
An abstract data type is a user-defined data type that satisfies the following two conditions:
– The representation of, and operations on, objects of the type are defined in a single syntactic unit
– The representation of objects of the type is hidden from the program units that use these objects, so the only
operations possible are those provided in the type's definition
An abstract data type is simply an encapsulation that includes only the data representation of one specific data
type and the methods that provide the operations for that type
An instance of an abstract data type is called an object.
Object-oriented programming is an outgrowth of the use of data abstraction.
Java’s support abstract data types. All user-defined data types in Java are classes and all objects are allocated
from the heap and accessed through reference variables and the support for abstract data types in Java can only
be defined in classes.
Java also includes packages as one of its encapsulation constructs.
2
IOPROG – Ingmar Olsson
Begin with Java 2
A visual approach: A class can be illustrated as a 3-compartment box
A class can be visualized as a three-compartment box:
1.
2.
3.
Name (or identity): identifies the class.
Data/Variables (or attribute(s), state(s), field(s)): contains the static data of the class.
Methods (or behaviour, function, operation): contains the dynamic behaviours of the class.
This is in fact the visual notation that is used in UML, Unified Model Language.
Name
Data,
Variables,Attributes
Behavior
Methods
The followings figure shows a few examples of classes:
Name, Identifier
Variables, Attributes
Student
BankAccount
balance
id
name
deposit()
withDraw()
getName()
printGrade()
Methods, Behavior
FootBallPlayer
Circle
name
number
radius
color
run()
jump()
getRadius()
getArea()
Car
speed
move()
accelerate()
The following figure shows two instances/objects of the class Student.
b:BankAccount
nisse:Student
sven:Student
balance = 50
id = 1234
name = “Nisse Hult”
id = 5678
name = “Sven Kula”
deposit()
withDraw()
getName()
printGrade()
getName()
printGrade()
The above class diagrams are drawn according to the UML (Unified Modeling Language) notations. A class is
represented as a 3-compartment box, containing name, variables, and method. Class name can be shown in bold
and centralized. Instance name is shown as instanceName:Classname and underlined.
Summary
In summary, a class is a programmer-defined, abstract, self-contained, reusable software entity that mimics a
real-world thing. A class packages the identity (name), the static attributes (variables) and the dynamic
behaviours (methods) in a 3-compartment box. An instance is an instantiation (or realization) of a particular item
of a class.
3
IOPROG – Ingmar Olsson
Begin with Java 2
A textual approach: a class can be given as a text in a textfile made by a texteditor.
This texteditor must give a clean text encoded to UTF-8/ASCII without any embedded “rich” format.
In Java, we use the keyword class to define a class and the textfile extension .java. For examples:
//Filename BankAccount.java
public class BankAccount
{
int balance;
void deposit() {...}
void withDraw() {...}
//Class name
//Variable, attribute
//Methods
}
//Filename Circle.java
public class Circle
{
double radius;
String color;
double getRadius() {...}
double getArea() {...}
//Class name
//Variables, attributes
//Methods
}
//Filename FootBallPlayer.java
public class FootBallPlayer
//Class name
{
int number;
//Variables, attributes
String name;
int xLocation, yLocation;
String run() {...}
void kickBall() {...}
//Methods
}
The syntax for class definition in Java is:
<AccessControlModifier> class ClassName
{
//Class body contains definition of variables and methods
...
}
We shall explain the access control modifier, such as public and private, later.
Class Naming Convention
A class name shall be a noun, or a noun phrase made up of several words. All the words shall be initialcapitalized (camel-case). Use a singular noun for class name. Choose a meaningful and self-descriptive
classname. For example, Circle, FotBallPlayer, HttpProxyServer, FileInputStream.
Creating Instances of a Class
To create an instance of a class, you have to:
1.
2.
Declare an instance identifier (variable) of a particular class.
Construct the instance (i.e., allocate storage for the instance and initialize the instance) using the "new"
operator.
Example OOP 1
Use the class BankAccount and place the text in the file BankAccount.java
4
IOPROG – Ingmar Olsson
Begin with Java 2
The BackAccount class implements a deposit with 50 and a withdraw of 20, all handled by the variable balance.
//Filename bankAccount.java
public class BankAccount
{
private int balance;
public void
{
balance =
}
public void
{
balance =
}
//Class name
//Variable, attribute
deposit()
//Methods
balance + 50;
withDraw()
balance – 20;
}
To create an instance/object of the class BankAccount we use the new operator
BankAccount b = new BankAccount();
To make this happen we need the mandatory class with the static start method
public static void main(String args[])
{
}
containing the instantiation of the BankAccount object.
This class with the static start method must be given the same name as the textfile for this class. So if you give
this class the name BankAccoutMain the textfile must be called BankAccountMain.java. It can be a good rule to
give a name with the extension Main to this class with the star/main function.
//Filename BankAccountMain.java
public class BankAccountMain
{
public static void main(String args[])
{
BankAccount b = new BankAccount();
}
}
In practice
The practical work with this textual approach we need a
text editor
or
with a convenient (Java) IDE.
Text editor
Select an optional folder/directory, for example ..\Native_Java\BankAccount (in Windows environment) or
../Native_Java/BankAccount (in Mac OS or Linux environment) and open a convenient texteditor: Emacs,
WordPad, NotePad, . . .
Step 1
Open those files in a texteditor with the filenames BankAccount.java and BankAccountMain.java
//Filename BankAccount.java
public class BankAccount
//Class name
5
IOPROG – Ingmar Olsson
Begin with Java 2
{
int balance;
//Variable, attribute
void deposit()
{
balance = balance + 50;
}
void withDraw()
{
balance = balance – 20;
}
//Methods
}
//Filename BankAccountMain.java
public class BankAccountMain
{
public static void main(String args[])
{
BankAccount b = new BankAccount();
}
}
Now we need to open a CommandLine window (in Windows environment) or a Cygwin/Terminal/Shell (in Mac
OS or Linux environment) to compile and execute the code. It is a good idea to have the texteditor and the
CommandLine/Shell window in parallel windows on the same screen to easely toggle between them: editing <–>
compile/execute for testing
Compile and execute the code in the CommandLine/Terminal/Shell window. Both the compilation and the
execution went well (we got no errors), but we application gave no functionality output.
Step 1 is a “soft” starter to introduce the practice about using an texteditor and compile/execute for a standalone application. Then most of all we must apply the rules in object-oriented programming and increase the
functionality.
In the next step we investigate how the instantiation was possible by introducing the concept constructor. In
fact we had no visible constructor in Step 1 so the Java compiler constructed one itself.
Then we concentrate on access control and the important concept Information Hinding and Encapsulation
We also introduce how to reference the variables and methods with the dot operator, . , and how to handle the
read and write functionality, "getter" and "setter" Methods, from a class applying Information Hinding and
Encapsulation
6
IOPROG – Ingmar Olsson
Begin with Java 2
Dot Operator (. )
The variables and methods belonging to a class are formally called member variables and member methods. To
reference a member variable or method, you must:
1.
2.
first identify the instance you are interested in, and then
reference the method or variable via the dot, . , operator.
Constructors
A constructor is a special method that has the same name as the class name. It is used to initialize the instance
constructed. To create a new instance of a class, you need to use a special "new" operator followed by a call to
(one of) the constructor(s).
Although we often use the term constructor method, a constructor is different from an ordinary method is the
following aspects:




The name of the constructor method is the same as the class name, and begins with an uppercase.
Constructor has no return type (or implicitly returns void). Hence, no return statement is allowed inside
the constructor's body.
Constructor can only be invoked via the "new" operator. It can only be used once to initialize the
instance constructed. You cannot call the constructor afterwards.
Constructors are not inherited (to be explained later).
Access Control Modifiers: public vs. private
An access control modifier can be used to control the visibility of a class, a member variable or a member method
without a class. We begin with the following two access control modifiers:



public: The class/variable/method is accessible and available to all the other objects in the system.
private: The class/variable/method is accessible and available within this class only.
if you don't place an access modifier on a method, class, or a variable, it is automatically recognized by
the compiler as default. Default method can be accessed within the class where it was declared.
In UML notations, public entity is denoted with a "+", while private entity is denoted with a "-" in the class
diagram. More access control modifiers will be discussed later.
Information Hiding and Encapsulation
A class encapsulates the name, static attributes and dynamic behaviours into a "3-compartment box". Once a
class is defined, you can seal up the "box" and put the "box" on the shelve for others to use and reuse. Anyone
can pick up the "box" and use it in their application. This cannot be done in the traditional procedural language
like C, as the static attributes (or variables) are scattered over the entire program and header files. You cannot
"cut" out a portion of C program, plug into another program and expect the program to run without extensive
changes.
Member variables (attributes, fileds) of a class are typically hidden from the outside word (i.e., the other
classes), with the private access control modifier. Access to the member variables are provided via the public
assessor methods, e.g., getBalance(), getRadius() and setRadius().
This follows the principle of information hiding. That is, objects communicate with each others using well-defined
interfaces. Objects are not allowed to know the implementation details of others. The implementation details are
hidden or encapsulated within the class. Information hiding facilitates reuse of the class.
Rule of Thumb: Do not make any variable public, unless you have a good reason.
7
IOPROG – Ingmar Olsson
Begin with Java 2
"getter" and "setter" Methods
To allow other classes to read the value of a private variable says xxx, you shall provide a get method (or getter
or accessor method) called getXxx(). A get method need not expose the data in raw format. It can process the
data and limit the view of the data others will see. get methods cannot modify the variable.
To allow other classes to modify the value of a private variable says xxx, you shall provide a set method (or
setter or mutator method) called setXxx(). A set method could provide data validation (such as range
checking), and transform the raw data into the internal representation.
Step 2
//Filename bankAccount.java
public class BankAccount
{
private int balance;
//Class name
//Private variable, attribute
BankAccount()
{
balance = 0;
}
//”Default” constructor
void deposit()
{
balance = balance + 50;
}
void withDraw()
{
balance = balance – 20;
}
//Methods
public int getBalance()
{
return balance;
}
//Get method, no set method yet
}
//Filename BankAccountMain.java
public class BankAccountMain
{
public static void main(String args[])
{
BankAccount b = new BankAccount();
b.deposit();
//Deposit 50
b.withDraw();
//Withdraw 20
System.out.println(b.getBalance()); //Output on the screen
}
}
Step 3
Put comments on the constructor codelines, i.e. take this code away from the compilation and execution.
//BankAccount()
//{
// balance = 0;
//]
//”Default” constructor
Try to deposit 50 and withdraw 20.
Compile and execute the code.
8
IOPROG – Ingmar Olsson
Begin with Java 2
Output: 30
The java compiler had created an implicit “default” constructor with the value balance = 0.
Step 4
Take away the comments on the constructor codelines, i.e. compile and execute the “default” constructor.
BankAccount()
{
balance = 0;
]
//”Default” constructor
Compile and execute the code.
Output: 30
Do we need any “default” constructor? To construct robust and reliable code, YES! See, Step 6!
Step 5
Initiate a new value balance = 100 in the “default” constructor.
BankAccount()
{
balance = 100;
]
//”Default” constructor
Compile and execute the code.
Output: 130
Method Overloading
Method overloading means that the same method name can have a few different implementations. However,
the different implementations must be distinguishable by their parameter/argument list (either the number of
arguments, or the type of arguments, or their order). This rule about method overloading is valid for both
ordinary methods and constructors. For example, the above BankAccount class has two (or more) versions of
constructor differentiated by their argument list, as followed:
BankAccount();
BankAccount(int amount );
//No parameter/argument, “default” constructor
//One parameter/argument, “parameter” constructor
Depending on the actual parameter/argument list used when invoking the method, the matching constructor will
be invoked. If your argument list does not match any one of the methods, you will get a compilation error.
Step 6
//Filename bankAccount.java
public class BankAccount //Class name
{
private int balance; //Private variable, attribute
//BankAccount()
//{
// balance = 0;
9
IOPROG – Ingmar Olsson
Begin with Java 2
//}
BankAccount(int amount) //”Parameter” constructor
{
balance = balance + amount;
}
void deposit()
//Methods
{
balance = balance + 50;
}
void withDraw()
{
balance = balance - 20;
}
int getBalance()
{
return balance;
}
}
//Filename BankAccountMain.java
public class BankAccountMain
{
public static void main(String args[])
{
BankAccount b = new BankAccount(100); //Instansiering med “parameter” constructor
b.deposit();
b.withDraw();
System.out.println("Output: " + b.getBalance());
}
}
Compile and execute the code.
Output: 130
Do we need any “default” constructor? To construct robust and reliable code, YES! How can we be sure that the
value is balance = 0?!
Step 7
To get robust and reliable code, define also the “default” constructor by yourself!
Take away the comments on the constructor codelines, i.e. compile and execute the “default” constructor.
BankAccount()
{
balance = 0;
}
Compile and execute the code.
Output: 130
10
IOPROG – Ingmar Olsson
Begin with Java 2
Member Variables
A member variable has a name (or identifier) and a type, as descried in the earlier chapter.
Variable Naming Convention: A variable name shall be a noun, or a noun phrase made up of several words.
The first word is in lowercase and the rest of the words are initial-capitalized, e.g., thefontSize, roomNumber,
xMax, yMin and xTopLeft. Take note that variable name begins with an lowercase, while class name begins with
an uppercase.
The formal syntax for variable definition in Java is:
<AccessControlModifier> type variableName <= initialValue>;
<AccessControlModifier> type variableName-1 <= initialValue-1> <, type variableName-2 <=
initialValue-2>> ... ;
For example,
private double radius;
public int length = 1, width = 1;
Member Methods
A method :
1.
2.
3.
receives parameters from the caller,
performs the operations defined in the method body, and
returns a piece of result (or void) to the caller.
The syntax for method declaration in Java is as follows:
<AccessControlModifier> returnType methodName (<argumentList>)
{
//Method body or implementation
......
}
For examples:
public int getBalance()
{
return balance;
}
public double getArea()
{
return radius*radius*Math.PI;
}
Method Naming Convention:
A method name shall be a verb, or a verb phrase made up of several words. The first word is in lowercase and
the rest of the words are initial-capitalized. For example, getRadius(), getParameterValues().
Take note that variable name is a noun (denoting a static attribute), while method name is a verb (denoting an
action). They have the same naming convention. Nevertheless, you can easily distinguish them from the context.
Methods take arguments in parentheses (possibly zero argument with empty parentheses), but variables do not.
In this writing, methods are denoted with a pair of parentheses, e.g., println(), getArea() for clarity.
11
IOPROG – Ingmar Olsson
Begin with Java 2
IDE proposal: BlueJ
Using BlueJ
Start BlueJ and the BlueJ interface opens. Select the menu New Project. Choose and invoke a project name, for
example BankAccount and select a relative location in the directory/folder system, for example
BlueJ_JavaProjects
A new BlueJ window is opened.
The document icon is a README file editor and is an important feature to be filled in for all applications. This can
be opened and updated at an optional occasion and we leave it for now.
Select and click New Class … button. Fill in the name of class, in this case BankAccount
12
IOPROG – Ingmar Olsson
Begin with Java 2
A striped UML class diagram alike graphical notation is created.
Double-click on the class diagram icon. A texteditor is opened.
A textfile is proposed with a private variable/attribute/field, a “default” constructor and a public method. Delete
this code!
Fill in the code for BankAccount.java used in Example OOP 1, Step 2. Save the file.
Navigate to the selected directory/folder for the BlueJ project and open the projrct directory/folder BankAccount.
There is the file BankAccount.java textfile, exactly the same as created in the stand-alone scenario we made
earlier.
13
IOPROG – Ingmar Olsson
Begin with Java 2
Now go back to the “New Class …” window and create a new class BankAccountMain
Now we have two “striped” Class diagram icons, BankAccout and BankAccountMain. We also got the relation
between the two classes (the instantiation of the BankAccount clas in the BankAccountMain class) as a IML “uses”
relation notated as arrow between the classes.
Click the Compile button. The stripes disappear (when the compilation is succeeded) and a message Compiling
.- Done is written in the lower frame of the window.
Navigate to the selected directory/folder for the BlueJ project and open the project directory/folder BankAccount.
Now there are all the files BankAccount.java, BankAccountMain.java, BankAccount.class and
BankAccountMain.class.
14
IOPROG – Ingmar Olsson
Begin with Java 2
How to instantiate classes and run the application from within BlueJ.
Right-click or ctrl-click on the BankAccount class diagram. The a pop-up windo with the text new BankAccont()
appears.
Activate the new BankAccount() alternative and a new pop-up window opens. Invoke an optional name for the
BankAccount instance, for example (as in Example OOP 1) b. Click OK and a red icon for the instantiated object
b is visible in the lower area called object bench.
The opened pop-up window lshow the methods in the instantiation b. There is also an alternative called inspect.
Select this option and a pop-up for the data (variables, attributes,fields) in the object b is open.
In the same way we can instatiate an object of BankAccountMain class and call it for example bMain. But there
are no accessible methods because the only methotd we have in BankAccountMain is the static void
main(String args[]) mrethod and this is not accessible through an object, only direct as a starting method for
all Java applications.
15
IOPROG – Ingmar Olsson
Begin with Java 2
Right-click or ctrl-click on the BankAccountMain class diagram. The a pop-up windo with the option void
main(String[] args) appears.
Then a pop-up window with the call/referens to BanAccountMain.main appears. For the moment we give no
argument, just click OK to run the main() method. Then BlueJ opens a terminal window with the (expected)
outout 30. This is comparable to run the Java virtual machine with the java command in a stand-alone
application.
16
IOPROG – Ingmar Olsson
Begin with Java 2
Using the BlueJ Debugger
The main tasks for a debugger are
setting breakpoints
stepping through the code
inspecting variables
This can be used to find errors but also to investigate the flow when the code in an application is executed. BlueJ
has a debugger integrated in the environment.
Open the code for the BankAccount class. Click on the left margin and put a breakpoint on the first line in the
parameter constructor BankAccount(int amount)
Run the BankAccount application from the BankAccountMain class.
Running the application from the BankAccountMain class wiil show a black arrow in the left marginal following the
executed row. A debug window is shown.
If a breakpoint is set in BankAccountMain on the constructor instantiation, clicking the Step tool in the Debugger
window can be used to follow the execution within the constructor BankAccountMain(int amount) in the
BankAccount class.
The static, instance and local variables can automatically be inspected in the debug window.
17
IOPROG – Ingmar Olsson
Begin with Java 2
IDE proposal: Eclipse
Using Eclipse
Create a new Java project with the name BankAccount. Clck Finish.
The projekt is opened in the Project Explorer
Open (right-click or ctrl-click) the src option and select New Class option. Choose for
moment not to fill in the Package field (default package). Invoke the class name
BankAccount. Don’t check the “public static void main(String[] args)” checkbox. Click
Finish.
18
IOPROG – Ingmar Olsson
Begin with Java 2
You get an empty class BackAccount with the filename BankAccount.java in the
texteditor.
Fill in the code in BankAcoount class we have used earlier.
Create a new class BankAccountMain (in the same default package). Check the “public
static void main(String[] args)” checkbox. Click Finish.
19
IOPROG – Ingmar Olsson
Begin with Java 2
The BankAccountMain class with the public static void main(String[] args)
function is filled in.
Fill in the code in BankAcoountMain class we have used earlier.
Open the Run menu. WE get the expected output in the Console view.
20
IOPROG – Ingmar Olsson
Begin with Java 2
Using the Eclipse Debugger
.....
Example OOP 2
Constructors - again
In a class Circle, there are three so-called constructors Circle(...).
Circle c1 = new Circle();
Circle c2 = new Circle(2.0);
Circle c3 = new Circle(3.0, "Red");
For examples, suppose that we have a class called Circle, we can create instances of Circle as follows:
// Declare 3 instances of the class Circle, c1, c2, and c3
Circle c1, c2, c3;
// Allocate and construct the instances via new operator
c1 = new Circle();
c2 = new Circle(2.0);
c3 = new Circle(3.0, "Red");
// You can declare and construct in the same statement
Circle c4 = new Circle();
Although we often use the term constructor method, a constructor is different from an ordinary method is the
following aspects:




The name of the constructor method is the same as the class name, and begins with an uppercase.
Constructor has no return type (or implicitly returns void). Hence, no return statement is allowed inside
the constructor's body.
Constructor can only be invoked via the "new" operator. It can only be used once to initialize the
instance constructed. You cannot call the constructor afterwards.
Constructors are not inherited (to be explained later).
Dot Operator (. )
The variables and methods belonging to a class are formally called member variables and member methods. To
reference a member variable or method, you must:
3.
4.
first identify the instance you are interested in, and then
reference the method or variable via the dot, . , operator.
For example, suppose that we have a class called Circle, with two variables (radius and color) and two methods
(getRadius() and getArea()). We have created three instances of the class Circle, namely, c1, c2 and c3. To
invoke the method getArea(), you must first identity the instance of interest, says c2, then use the dot
operator, in the form of c2.getArea(), to invoke the getArea() method of instance c2. For example,
// Declare and construct instances c1 and c2 of the class Circle
Circle c1 = new Circle ();
Circle c2 = new Circle ();
// Invoke member methods for the instance c1 via dot operator
System.out.println(c1.getArea());
System.out.println(c1.getRadius());
// Reference member variables for instance c2 via dot operator
c2.radius = 5.0; //Notice the “Rule of Thumb” on page 9!
c2.color = "Blue"; //Notice the “Rule of Thumb” on page 9!
21
IOPROG – Ingmar Olsson
Begin with Java 2
In general, suppose there is a class called AClass with a member variable called aVariable and a member
method called aMethod(). An instance called anInstance is constructed for AClass. You use
anInstance.aVariable and anInstance.aMethod().
Now we put this together in a practical session.
A class called Circle is to be defined with two variables: radius of type double and color of type String; and
three methods: getRadius(), getColor(), and getArea(), as illustrated in the following class diagram:
Class defintion
Circle
-radius:double
-color:String
+getRadius():double
+getArea():double
+getColor():String
Instances
c1:Circle
c2:Circle
c3:Circle
-radius = 2.0
-color = “Blue”
-radius = 2.0
-color = “Red”
-radius = 1.0
-color = “Red”
+getRadius()
+getArea()
+getColor()
+getRadius()
+getArea()
+getColor()
+getRadius()
+getArea()
+getColor()
The source codes for Circle.java is as follows:
22
IOPROG – Ingmar Olsson
Begin with Java 2
public class Circle
{
//Private variables
private double radius;
private String color;
//Constructors (overloaded)
public Circle()
{
radius = 1.0;
color = "Red";
}
public Circle(double r)
{
radius = r;
color = "Red";
}
public Circle(double r, String c)
{
radius = r;
color = c;
}
// Circle class, saved as "Circle.java"
// 1st Constructor
// 2nd Constructor
// 3rd Constructor
//Public methods
public double getRadius()
{
return radius;
}
public String getColor()
{
return color;
}
public double getArea()
{
return radius*radius*Math.PI;
}
}
Compile Circle.java. Notice that the Circle class does not have a main() method. Hence, it is not a standalone program
and you cannot run the Circle class by itself. Circle class is meant to be used in other classes.
We shall now write another class called CircleMain, which uses the Circle class. TestCircle has a main()
method and can be executed.
public class CircleMain
{
public static void main(String[] args)
{
//Construct an instance c1 of the class Circle
Circle c1 = new Circle(2.0, "blue"); //Uses 3rd constructor
System.out.println("Radius is " + c1.getRadius() //Use dot operator
//to invoke member methods
+ " Color is " + c1.getColor()
+ " Area is " + c1.getArea());
//Construct an instance c2 of the class Circle
Circle c2 = new Circle(2.0);
//Uses 2nd constructor
System.out.println("Radius is " + c2.getRadius()
+ " Color is " + c2.getColor()
+ " Area is " + c2.getArea());
//Construct an instance c3 of the class Circle
Circle c3 = new Circle();
// uses 1st constructor
System.out.println("Radius is " + c3.getRadius()
+ " Color is " + c3.getColor()
+ " Area is " + c3.getArea());
}
}
23
IOPROG – Ingmar Olsson
Begin with Java 2
Compile and run the CircleMain and study the outputs:
Radius is 2.0 Color is blue Area is 12.566370614359172
Radius is 2.0 Color is red Area is 12.566370614359172
Radius is 1.0 Color is red Area is 3.141592653589793
In our Circle class, the variables radius and color are declared private. That is to say, they are only available
within the Circle class and not visible in any other classes - including CircleMain class. You cannot access the
private variables radius and color from the CircleMain class directly - via says c1.radius or c1.color. The
Circle class provides two public accessor methods, namely, getRadius() and getColor(). These methods are
declared public. The class CircleMain can invoke these public accessor methods to retrieve the radius and
color of a Circle object, via says c1.getRadius() and c1.getColor().
There is no way you can change the radius or color of a Circle object, after it is constructed in the CircleMain
class. You cannot issue statements such as c1.radius = 5.0 to change the radius of instance c1, as radius is
declared as private in the Circle class and is not visible to other classes including CircleMain. If the designer of
the Circle class permits the change the radius and color after a Circle object is constructed, he/she has to
provide the appropriate set methods, e.g.,
// Setter for color
public void setColor(String c)
{
color = c;
}
// Setter for radius
public void setRadius(double r)
{
radius = r;
}
With proper implementation of information hiding, the designer of a class has full control of what the user of the
class can and cannot do.
Keyword "this"
You can use keyword "this" to refer to this class inside a class definition.
One of the main usage of keyword this is to resolve ambiguity.
public class Circle
{
double radius;
public Circle(double radius)
{
this.radius = radius;
}
...
}
//Member variable called radius
//Method's argument also called radius
In the above codes, there are two identifiers called radius - a member variable of the class and the method's
argument. This certainly causes naming conflict. To avoid the naming conflict, you could name the method's
argument r instead of radius. However, radius is certainly more approximate and meaningful in this context.
Java provides a keyword called this to resolve this naming conflict. "this.radius" refers to the member variable;
while "radius" refers to the method's argument.
Using the keyword "this", the getter and setter methods for a private variable called xxx of type Ttt are as
follows:
24
IOPROG – Ingmar Olsson
Begin with Java 2
// A variable named xxx of type Ttt
Ttt xxx;
// A getter for variable xxx of type Ttt receives no argument and return a value of type Ttt
Ttt getXxx()
{
return xxx;
}
// A setter for variable xxx of type Ttt receives a parameter of type Ttt and return void
void setXxx(Ttt xxx)
{
this.xxx = xxx;
}
Furthermore:



In a constructor, we can use this(...) to call another constructor.
Inside a method, we can use the statement "return this" to return this instance to the caller.
this.varName refers to varName of this class. this.methodName(...) invokes methodName(...) of this
class.
Method toString()
Every well-designed Java class should have a public method called toString() that returns a string description
of the object. You can invoke the toString() method explicitly by calling instanceName.toString() or
implicitly via println() or String concatenation operator '+'. Running println(anInstance) with an object
argument invokes the toString() method of that instance implicitly.
For example, if the following toString() method is included in our Circle class:
public String toString()
{
return "Circle with radius = " + radius + " and color of " + color;
}
In the CircleMain class, you can get a short text descriptor of a Circle object by:
Circle c1 = new Circle();
//Explicit call
System.out.println(c1.toString());
//Implicit call to c1.toString()
System.out.println(c1);
System.out.println("c1 is: " + c1);
The signature of toString() is:
public String toString() { ...... }
Class Variables, Class Methods and Constants
When a number of objects are created from the same class blueprint, they each have their own distinct copies of
instance variables. In the Circle class (Example OOP 1) the instance variable are radius and color. Each
Circle object has its own values for these variables, stored in different memory locations.
Sometimes, there is a need for variables that are common to all objects. This is accomplished with the static
modifier. Fields that have the static modifier in their declaration are called static fields or class variables.
They are associated with the class, rather than with any object. Every instance of the class shares a class
variable, which is in one fixed location in memory. Any object can change the value of a class variable, but class
variables can also be manipulated without creating an instance of the class.
A typical use of a class variable is to count the number of instances you have created with the constructors. In
the Circle class you can use
//Add a class variable for the number of Circle objects instantiated
private static int numberOfCircles = 0;
25
IOPROG – Ingmar Olsson
Begin with Java 2
Class variables are referenced by the class name itself, as in Circle.numberOfCircles
You can use the Circle constructor to set the id instance variable and increment the numberOfCircles class
variable with numberOfCircles++; in all constructors.
If you want to printout the number of instances with the call Circle.numberOfCircles you must use the public
access modifier
public static int numberOfCircles = 0;
This breaks the class encapsulation idea! A better way is to use a static method!
The Java programming language supports static methods as well as static variables. Static methods, which
have the static modifier in their declarations, should be invoked with the class name, without the need for
creating an instance of the class, as in
ClassName.methodName(args)
A common use for static methods is to access static fields. For example, we could add a static method to the
Circle class to access the numberOfCircles static field:
public static int getNumberOfCircles()
{
return numberOfCircles;
}
This method can then be used e.g. in a printout statements as
System.out.println("Number of Circle instances: " + Circle.getNumberOfCircles());
The static modifier, in combination with the final modifier, is also used to define constants. The final modifier
indicates that the value of this field cannot change.
For example, the following variable declaration defines a constant named PI, whose value is an approximation of
pi (the ratio of the circumference of a circle to its diameter):
static final double PI = 3.141592653589793;
Constants defined in this way cannot be reassigned. By convention, the names of constant values are spelled in
uppercase letters. If the name is composed of more than one word, the words are separated by an underscore
(_).
Example OOP 3
This application is a cash register that totals up sales and computes change due.
Using a texteditor IDE
Implement a CashRegister class.
Use an optional texteditor and create a file with the filename CashRegister.java.
Implement a “default” constructor (constructor without input parameters) and the mutator methods
recordPurchase(), enterPayment() and the accessor method getChange().
The mutator method, sometimes called a "setter", is most often used in object-oriented programming, in keeping
with the principle of encapsulation. According to this principle, member variables of a class are made private to
hide and protect them from other code, and can only be modified by a public member function (the mutator
method), which takes the desired new value as a parameter, optionally validates it, and modifies the private
member variable.
Often a "setter" is accompanied by a "getter" (also known as an accessor), which returns the value of the private
member variable.
//CashRegister.java
/**
A cash register totals up sales and computes change due.
*/
public class CashRegister
{
private double purchase;
26
IOPROG – Ingmar Olsson
Begin with Java 2
private double payment;
/**
Constructs a cash register with no money in it.
*/
public CashRegister()
{
purchase = 0;
payment = 0;
}
/**
Records the sale of an item.
@param amount the price of the item
*/
public void recordPurchase(double amount)
{
double total = purchase + amount;
purchase = total;
}
/**
Enters the payment received from the customer.
@param amount the amount of the payment
*/
public void enterPayment(double amount)
{
payment = amount;
}
/**
Computes the change due and resets the machine for the next customer.
@return the change due to the customer
*/
public double getChange()
{
double change = payment - purchase;
purchase = 0;
payment = 0;
return change;
}
}
Implement the class CashRegisterMain in the file CashRegisterMain.java
//CashRegisterMain.java
import java.util.Scanner;
/**
A class to start the CashRegister class.
*/
public class CashRegisterMain
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
System.out.print("Price of item: ");
double purchase1 = sc.nextDouble();
System.out.print("Price of item: ");
double purchase2 = sc.nextDouble();
System.out.print("Payment: ");
double payment = sc.nextDouble();
CashRegister register = new CashRegister();
27
IOPROG – Ingmar Olsson
Begin with Java 2
register.recordPurchase(purchase1);
register.recordPurchase(purchase2);
register.enterPayment(payment);
double change = register.getChange();
System.out.println("Amount in return: " + change);
}
}
Compile and run (in an optional Shell tool or Command Prompt) the CashRegister application from the folder with
the files CashRegisterMain.java and CashRegister.java.
Using BlueJ IDE
Create a new class CashRegister with the same code as in CashRegister.java above.
Create a new class CashRegisterMain with the same code as in CashRegisterMain.java above.
Run the application from the BlueJ IDE and activate the void main(String[] args) method from the class
CashRegisterMain.
28
IOPROG – Ingmar Olsson
Begin with Java 2
Interact with the application from the opened BlueJ terminal window.
Another way to execute the application directly in BlueJ is to right-click the class CashRegister and create a new
instance of the class without starting from the main() method.
From the opened BlueJ Method Call window for the CashRegister instance, the methods
void recordPurchase(double amount);
void enterPayment(double amount);
double getChange()
can be called in the same way as from the main() method.
29
IOPROG – Ingmar Olsson
Begin with Java 2
Exercise OOP 1
Use the keyword this to get the correct output from the instantiation of the class Account.
public class Exercise1
{
private int a;
private int b;
public Exercise1()
{}
public void setData(int a ,int b)
{
a = a;
b = b;
}
public void showData()
{
System.out.println("Value of A = "+ a);
System.out.println("Value of B = "+ b);
}
public static void main(String args[])
{
Exercise1 e = new Exercise1();
30
IOPROG – Ingmar Olsson
Begin with Java 2
e.setData(2,3);
e.showData();
}
}
Exercise OOP 2
Public class Exercise2
{
private int a;
private int b;
public Exercise2()
{}
public void setData(int c,int d)
{
a=c;
b=d;
}
public void showData()
{
System.out.println("Value of a = "+a);
System.out.println("Value of a = "+b);
}
public static void main(String args[])
{
Exercise2 e1 = new Exercise2();
Exercise2 e2 = new Exercise2();
e1.setData(1,2);
e2.setData(3,4);
e1.showData();
e2.showData();
//Exercise2 e3;
//e3=e2;
//e3.showData();
//e2=null;
//e3.showData();
//e3=null;
//e3.showData();
//1)
//1)
//1)
//2)
//2)
//3)
//3)
}
}
Uncomment the lines numbered 1). Save , compile and run the code. Two reference variables are pointing to the
same object. Describe in a figure the heap
Uncomment the lines numbered 2). Save, compile and run the code.
Describe in a heaps the reference variables. s2 is eligible for garbage collection but s3 is not. Why?
Uncomment the lines numbered 3) . Save , compile and run the code.
Which references are eligible for garbage collection?
Exercise OOP 3
public class Exercise3
{
private int a;
//Initialized to zero
private static int b; //Initialized to zero only when class is loaded not for each object
//created.
public Exercise3()
{
b++;
}
//Constructor incrementing static variable b
public void showData()
{
System.out.println("Value of a = "+a);
31
IOPROG – Ingmar Olsson
Begin with Java 2
System.out.println("Value of b = "+b);
}
//public static void increment()
//{
//a++;
//}
}
class Main
{
public static void main(String args[])
{
Exercise3 e1 = new Exercise3();
e1.showData();
Exercise3 e2 = new Exercise3();
e2.showData();
//Exercise3.b++;
//1)
//e1.showData();
//1)
}
}
Uncomment the line numbered 1). Save , compile and run the code.
Describe how reference variables and objects are created and static variables are accessed by the different
instances.
What kind of class in Main?
Exercise OOP 4
public class Book
{
private int itemCode;
private String title;
public int getItemCode()
{
return itemCode;
}
public void setItemCode (int newItemCode)
{
if (newItemCode > 0) itemCode = newItemCode;
}
public String getTitle()
{
return title;
}
public void setTitle (String newTitle)
{
title = newTitle;
}
public void display()
{
System.out.println(itemCode + " " + title);
}
}
public class BookMain
{
public static void main(String[] args)
{
Book b = new Book();
b.setItemCode( . . . . );
b.setTitle(". . . . .”);
System.out.println(b.getItemCode() + " " + b.getTitle());
System.out.print("From display: ");
b.display();
}
}
Use the class BookMain to instantiate an object of a Book.
Exercise OOP 5
32
IOPROG – Ingmar Olsson
Begin with Java 2
The following information will be stored for each employee:
employee ID (an integral number, automatically assigned when a new employee is added)
first name and last name
department number (an integral value, call it dept)
pay rate (a floating-point value, using a double)
In addition, we would like:
a method called getPayInfo() that will return a sentence with the employee's name, id, department, and check
amount
a method called getFullName() that will return the first and last names separated by a space
Define a class called Employee with these characteristics, using standard practices for limiting data access and for
method naming
In order to be useful, there should be methods to set and get all properties (except setting the employee id,
which will happen automatically in a manner to be determined later; for now, just let it default to 0)
Create a class called Payroll with a main method, it should: instantiate an Employee object
set values for all properties
call the getPayInfo() method to see the results
Modify the Employee class to use a constructor that accepts parameters for the first and last names, department,
and pay rate.
In Payroll, modify main to add another Employee variable that receives an instance created using this
constructor .
Also add a constructor that takes no parameters and does nothing (as we discussed above)
Add more Employee constructors:
one that takes values for first and last names only
one that takes values for first name, last name, and department
one that takes values for first name, last name, and pay rate
note that, in practice, you can use the parameter lists for constructors to help enforce what you would consider
valid combinations of properties - for example, if you would not want an employee to exist in a state where they
had name and department information, but no pay rate, then the absence of that particular constructor would
help ensure that
judicious use of copy-paste-edit can speed up this process, but be careful to make every necessary edit if you do
this!
Create and pay additional instances using these constructors
You will find yourself writing somewhat repetitive code, setting the same values the same way in several different
constructors - we will address this in a few pages
Add a private and static integer property called nextId to the Employee class (give it an initial value of 1).
Modify the declaration of the id property as follows:
private int id = nextId++;
What happens when each new Employee gets instantiated?
Exercise OOP 6
Implement an object-oriented class version BubbleSort of the earlier prepared example (“Begin with Java 1”)
with the Bubblesort algoritm. Implement a constructor BubbleSort() with the same code for generating the
random numbers as the void slumptal(int a[], int n) method.
Give the BubbleSort class the private datamembers
private int a[];
private int n;
Change the classification for the other methods to class member methods (delete the word static).
Use the below proposal as a main() method.
public static void main(String args[])
{
System.out.print("Give the number of integers to be sorted: ");
Scanner input = new Scanner(System.in);
int antal;
antal = input.nextInt();
33
IOPROG – Ingmar Olsson
Begin with Java 2
int helTal[] = new int[antal];
BubbleSort bSort = new BubbleSort(helTal, antal);
System.out.println("Unsorted: ");
bSort.skrivut(helTal, antal);
bSort.sortering(helTal, antal);
System.out.println("Sorted: ");
bSort.skrivut(helTal,antal);
}
Exercise OOP 7
Implement an object-oriented class version MasterMind of the earlier prepared example of the MasterMind
game.
Implement the datastructure in the earlier code as private datamembers in the class MasterMind. Implement a
default constructor MasterMind() to call the same code as in earlier method play().
Change the classification for the other static methods to class member methods.
Use the below proposal as a main() method.
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
char c;
do
{
MasterMind mastermind = new MasterMind();
System.out.print("Once more? (Y/N): ");
String s = scan.next();
c = s.charAt(0);
} while (c == 'y' || c == 'Y');
}
Exercise OOP 8
Implement a TicketMachine class for a ticket machine that issues fare tickets. Use for example the private
datamembers
// The price of a ticket from this machine.
private int price;
// The amount of money entered by a customer so far.
private int balance;
// The total amount of money collected by this machine.
private int total;
and the constructor TicketMachine(int ticketPrice) to initiate the datamembers
Use methods like
int getPrice(), getting the ticket price specified in the constructor
void insertMoney(int amount), control enough money for the ticket
void printTicket(), print a simple textual layout
Implement a control that a ticket will only be printed if enough money has been input.
If using a texteditor/shell tool IDE instantiate the class TicketMachine from a class TicketMachineMain with a
static main() method.
If you are using BlueJ IDE you can instantiate and call the methods directly from the BlueJ IDE.
Exercise OOP 9
Playing cards. In a typical card game, each player gets a hand of cards. The deck is shuffled and cards are dealt
one at a time from the deck and added to the players' hands. In some games, cards can be removed from a
hand, and new cards can be added. The game is won or lost depending on the value (ace, 2, ..., king) and suit
(spades, diamonds, clubs, hearts) of the cards that a player receives. If we look for nouns in this description,
there are several candidates for objects: game, player, hand, card, deck, value, and suit. Of these, the value and
the suit of a card are simple values, and they will just be represented as instance variables in a Card object. The
ones that are most obviously reusable are: card, hand, and deck.
34
IOPROG – Ingmar Olsson
Begin with Java 2
If we look for verbs in the description of a card game, we see that we can shuffle a deck and deal a card from a
deck. This gives use us two candidates for instance methods in a Deck class. Cards can be added to and removed
from hands. This gives two candidates for instance methods in a Hand class. Cards, the Card class, are relatively
passive things, but we need to be able to determine their suits and values.
A program that lets the user play a very simple card game is the card version of HighLow. A deck of cards is
shuffled, and one card is dealt from the deck and shown to the user. The user predicts whether the next card
from the deck will be higher or lower than the current card. If the user predicts correctly, then the next card from
the deck becomes the current card, and the user makes another prediction. This continues until the user makes
an incorrect prediction. The number of correct predictions is the user's score. The following step of this card game
is BackJack which will be covered later on.
Implement a program HighLow that uses the Card and Deck classes. The files Card.java and Deck.java are
available as separate files and discussed separately.
public class HighLow
{
public static void main(String[] args)
{
//Output som instructions for the HighLow cardgame
// Proposals for optional datamembers
int gamesPlayed = 0;
// Number of games user has played.
int sumOfScores = 0;
// The sum of all the scores from all the games played.
char playAgain;
// User's response for another game.
do
{
int someResult;
someResult = play();
// Play the game and get the result (score).
// . . . . .
// Output "Play again? Y/N";
// . . . . .
} while (playAgain == ‘y’ || playAgain == ‘Y’);
// Output of the result of the game(s)
}
static int play()
{
Deck deck = new Deck();
// Get
// the
Card currentCard;
// The
Card nextCard;
// The
char guess;
// The user's
a new deck of cards, and store a reference to it in
variable deck
current card.
next card in the deck.
guess. 'H' for higher, 'L' for lower.
deck.shuffle();
currentCard = deck.dealCard();
//Output currentCard
while (true)
{
// Get the user's prediction, 'H' or 'L'.
// . . . . .
do
{
//. . . . .
} while (guess != 'H' && guess != 'L');
//Get the next card and show it to the user.
nextCard = deck.dealCard();
//Output nextCard
//Check the user's prediction. */
if (nextCard.getValue() == currentCard.getValue())
{
//. . . . .
break;
}
else if (nextCard.getValue() > currentCard.getValue())
35
IOPROG – Ingmar Olsson
Begin with Java 2
{
if (guess == 'H')
{
//. . . . .
}
else
{
//. . . . .
break;
}
}
else
{
if (guess == 'L')
{
//. . . . .
}
else
{
//. . . . .
break;
}
}
//Next iteration of the loop, the nextCard becomes the currentCard
//Output the currentCard
}
//Output some result about the guesses
return someResult;
}
}
Generics
36
IOPROG – Ingmar Olsson
Begin with Java 2
Introduction
Generics are a very important change to the Java language in a long time, possibly since it was created. They
make reusable Java code easier to write and read.
It's been more than 10 years since the introduction of the Java programming language. In that time, the Java
language has matured and come into its own. But only with Java 5.0, the sixth major release of Java, did the
core language itself change in a significant way.
Generics are about abstraction. Generics let you create classes and methods that work in the same way on
different types of objects. The term "generic" comes from the idea that we'd like to be able to write general
algorithms that can be broadly reused for many types of objects rather than having to adapt our code to fit each
circumstance. This concept is not new; it is the impetus behind object-oriented programming itself. Java generics
do not so much add new capabilities to the language as they make reusable Java code easier to write and easier
to read.
Generics take reuse to the next level by making the type of the objects we work with an explicit parameter of the
generic code. For this reason, generics are also referred to as parameterized types. In the case of a generic
class, the developer specifies a type as a parameter (an argument) whenever she uses the generic type. The
class is parameterized by the supplied type, to which the code adapts itself.
In other languages, generics are sometimes referred to as templates, which is more of an implementation term.
Templates are like intermediate classes, waiting for their type parameters so that they can be used. Java takes a
different path, which has both benefits and drawbacks that well describe in detail in this chapter.
The most compelling case for generics is container classes and collections. But we start to introduce generic
methods, which intelligently infer their parameter types based upon how they are invoked. Then we get into the
details of writing generic classes and then look at a couple of real-world generic classes in the Java API.
Motivation
It would be nice if we could write a single sort method that could sort the elements in an Integer array, a
String array or an array of any type that supports ordering (i.e., its elements can be compared). It would also be
nice if we could write a single Stack class that could be used as a Stack of integers, a Stack of floating-point
numbers, a Stack of Strings or a Stack of any other type. It would be even nicer if we could detect type
mismatches at compile time—known as compile-time type safety. For example, if a Stack stores only integers,
attempting to push a String on to that Stack should issue a compile-time error.
Generic methods and generic classes enable programmers to specify, with a single method declaration, a set of
related methods or, with a single class declaration, a set of related types, respectively. Generics also provide
compile-time type safety that allows programmers to catch invalid types at compile time.
We might write a generic method for sorting an array of objects, then invoke the generic method with Integer
arrays, Double arrays, String arrays and so on, to sort the array elements. The compiler could perform type
checking to ensure that the array passed to the sorting method contains same type elements.
We might write a single generic Stack class that manipulates a stack of objects, then instantiate Stack objects for
a stack of Integers, a stack of Doubles, a stack of Strings and so on. The compiler could perform type checking to
ensure that the Stack stores elements of the same type.
Generic Methods
Example Generics 1
To motivate generic methods we use this example that contains three overloaded printArray methods.
Overloaded methods are often used to perform similar operations on different types of data. These methods
print the string representations of the elements of an Integer array, a Double array and a Character array,
respectively. Note that we could have used arrays of primitive types int, double and char in this example. We
chose to use arrays of type Integer, Double and Character (type-wrapper class) to set up our generic method
example, because only reference types can be used with generic methods and classes.
public class OverloadedMethods
{
//Method printArray to print Integer array
public static void printArray( Integer[] inputArray )
{
37
IOPROG – Ingmar Olsson
Begin with Java 2
//Display array elements, using "for-each" loop: "Begin with Java”, p 23
for (Integer element : inputArray )
System.out.printf( "%s ", element );
System.out.println();
}
//Method printArray to print Double array
public static void printArray(Double[] inputArray )
{
//Display array elements
for ( Double element : inputArray )
System.out.printf( "%s ", element );
System.out.println();
}
//Method printArray to print Character array
public static void printArray(Character[] inputArray )
{
//Display array elements
for ( Character element : inputArray )
System.out.printf( "%s ", element );
System.out.println();
}
public static void main( String args[] )
{
//Create arrays of Integer, Double and Character
Integer[] integerArray = { 1, 2, 3, 4, 5, 6 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };
Character[] characterArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println( "Array integerArray contains:" );
printArray(integerArray );
System.out.println( "\nArray doubleArray contains:" );
printArray(doubleArray );
System.out.println( "\nArray characterArray contains:" );
printArray(characterArray );
}
}
If the operations performed by several overloaded methods are identical for each argument type, the overloaded
methods can be more compactly and conveniently coded using a generic method. You can write a single generic
method declaration that can be called with arguments of different types. Based on the types of the arguments
passed to the generic method, the compiler handles each method call appropriately.
Following are the rules to define Generic Methods:
All generic method declarations have a type parameter section delimited by angle brackets (< and >)
that precedes the method's return type ( <T> in the next example).
Each type parameter section contains one or more type parameters separated by commas. A type
parameter, also known as a type variable, is an identifier that specifies a generic type name.
-
The type parameters can be used to declare the return type and act as placeholders for the types of the
arguments passed to the generic method, which are known as actual type arguments.
A generic method's body is declared like that of any other method. Note that type parameters can
represent only reference types not primitive types (like int, double and char).
Example Generics 2
38
IOPROG – Ingmar Olsson
Begin with Java 2
This example reimplements the application in Example Generics 1 using a generic printArray method. Note that
the printArray method calls are identical to those in Example Generics 1 and that the outputs of the two
applications are identical. This dramatically demonstrates the expressive power of generics.
public class GenericMethod
{
//Generic method printArray, using "for-each" loop: "Begin with Java”, p 23
public static <T> void printArray( T[] inputArray )
{
//Display array elements
for ( T element : inputArray )
System.out.printf( "%s ", element );
System.out.println();
}
public static void main(String args[])
{
//Create arrays of Integer, Double and Character
Integer[] integerArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };
Character[] characterArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println( "Array integerArray contains:" );
printArray( integerArray );
System.out.println( "\nArray doubleArray contains:" );
printArray( doubleArray );
System.out.println( "\nArray characterArray contains:" );
printArray( characterArray );
}
}
Generic method syntax
The syntax definition of a (static void) generic method is
public static <T> void <methodName>(<T-datatype> <parameterName>)
The definition starts with a placeholder or a type-parameter section <T> in which T is optional name for the type
parameter but a common selection (it could be Type, E, …). Other parts are similar to non-generic methods as
stated in “Begin with Java 1”, page 28.
In Example Generics 2 this is realized as the method signature
public static <T> void printArray(T[] inputArray )
A generic method can also have a type parameter as a return type.
The syntax definition of a (static returnType) generic method is
public static <T> returnType <methodName>(<T-datatype> <parameterName>)
where the returnType could be a non-generic datatype or a generic type parameter T
As an example of a generic method with returntype we can take the method max which returns the largest of
three T-datatype object parameters.
The relational operator < can not be used with reference types so we have to use the interface Comparable<T> for
type parameter T to be able to use the built-in method compareTo.
This restriction or constraint for the type parameter T is called an upper bound type parameter and is
expressed with the keyword extends in a general sense to mean either "extends" (as in classes) or
"implements" (as in interfaces).
39
IOPROG – Ingmar Olsson
Begin with Java 2
Then the signature for the generic max method can be written
public static <T extends Comparable<T>> T max(T x, T y, T z)
and the generic max method
public static <T extends Comparable<T>> T max(T x, T y, T z)
{
T m = x;
if (y.compareTo(m) > 0
m = y;
if (z.compareto(m) > 0)
m = z;
return m;
}
Example Generics 3
The generic method max can be used like this
public class GenericMethod
{
public static void main(String[] args)
{
System.out.printf("Maximum of %d, %d and %d is %d\n\n", 3,4,5, max(3,4,5));
System.out.printf("Maximum of %.1f, %.1f and %.1f is %.1f\n\n", 6.6, 7.7, 8.8,
max(6.6,7.7,8.8));
System.out.printf("Maximum of %s, %s and %s is %s\n", "Nisse", "Sven", "Allan",
max("Nisse", "Sven", "Allan"));
}
public static <T extends Comparable<T>> T max(T x, T y, T z)
{
T m = x;
if (y.compareTo(m) > 0)
m = y;
if (z.compareTo(m) > 0)
m = z;
return m;
}
}
The output is
Maximum of 3, 4 and 5 is 5
Maximum of 6,6, 7,7 and 8,8 is 8,8
Maximum of Nisse, Sven and Allan is Sven
Type Erasure
When a generic type is instantiated, the compiler translates those types by a technique called type erasure — a
process where the compiler removes all information related to type parameters and type arguments within a
metod or a class. By default all generic types are replaced with the root type Object. Type erasure enables Java
applications that use generics to maintain binary compatibility with Java libraries and applications that were
created before generics.
Example Generics 4
40
IOPROG – Ingmar Olsson
Begin with Java 2
Here is a generic version of the Bubble sort method with the same algoritm as the non-generic version, just a
new generic signature and given the local tTemp variable a generic datatype, from “Begin with Java 1”, Example
Array 3, page 38.
static <T extends Comparable<T>> void bubbleSortGeneric(T[] gArray, int n)
{
int i,j;
T tTemp;
for (i = 0; i < n-1; i++)
for (j = n-1; j >= i+1; j--)
if (gArray[j-1].compareTo(gArray[j]) > 0)
{
tTemp = gArray[j-1];
gArray[j-1] = gArray[j];
gArray[j] = tTemp;
}
}
public static <T> void printArray(T[] gArray, int n)
{
int i = 0;
for (T element : gArray)
{
System.out.printf("%s ", element);
if ((i % 20 == 0) && (i > 0))
System.out.println();
i++;
}
System.out.println();
}
public static void slumptal(Integer[] a, int n)
{
Random r = new Random();
for (int i = 0; i <= n-1; i++)
a[i] = Math.abs(r.nextInt()) % 1000;
}
public static void stringInput(String[] s, int n)
{
Scanner input = new Scanner(System.in);
for (int i = 0; i < n; i++)
{
System.out.print("String " + (i+1) + ": ");
s[i] = input.next();
}
}
This generic sort method can be used for Inte
ger and String datatypes like this.
public static void main(String args[])
{
System.out.print("Give the number of integers to be sorted: ");
Scanner input = new Scanner(System.in);
int antal;
antal = input.nextInt();
Integer[] helTal = new Integer[antal];
slumptal(helTal, antal);
System.out.println("Unsorted: ");
printArray(helTal, antal);
41
IOPROG – Ingmar Olsson
Begin with Java 2
bubbleSortGeneric(helTal, antal);
System.out.println("Sorted: ");
printArray(helTal,antal);
/*
System.out.print("Give number of strings: ");
Scanner input = new Scanner(System.in);
int antal;
antal = input.nextInt();
String[] s = new String[antal];
stringInput(s, antal);
System.out.println("Unsorted: ");
printArray(s, antal);
bubbleSortGeneric(s, antal);
System.out.println("Sorted: ");
printArray(s,antal);
*/
}
42
IOPROG – Ingmar Olsson
Begin with Java 2
Generic Classes
A generic class declaration looks like a non-generic class declaration, except that the class name is followed by
a placeholder or type parameter section <T>.
As with generic methods, the type parameter section of a generic class can have one or more type parameters
separated by commas. These classes are known as parameterized classes or parameterized types because they
accept one or more parameters.
Generic class motivation (again)
A common example with non-generic datatypes is the following. Suppose a class Buffer:
class Buffer
{
private Object[] data;
public void put(Object o) {...}
public Object get() {...}
}
This can result in problems, even when the root class Object is used:
Type casts needed:
buffer.put(3);
// Boxing imposes run-time costs
int x = (int)buffer.get();
// Type cast imposes run-time costs
One cannot statically enforce homogeneous data structures
buffer.Put(3); buffer.put(new Rectangle());
Rectangle r = (Rectangle)buffer.get();
// Can result in a run-time error!
Special types IntBuffer, RectangleBuffer, ... introduce redundancy
Generic classes cure those problems by providing
Type-safe code
Performance
No code bloat
Constraints
More restrictive object model
Example Generics 5
Here is a simple example on a generic class (without defined constructor(s))
public class GenericClass<T>
{
private T t;
public void add(T t)
{
this.t = t;
}
public T get()
{
return t;
}
public static void main(String[] args)
{
GenericClass<Integer> integerClass = new GenericClass<Integer>();
GenericClass<String> stringClass = new GenericClass<String>();
43
IOPROG – Ingmar Olsson
Begin with Java 2
integerClass.add(new Integer(10));
stringClass.add(new String("Hello World"));
System.out.printf("Integer Value: %d\n\n", integerClass.get());
System.out.printf("String Value: %s\n", stringClass.get());
}
}
The instantiation of objects of the class is made by the keyword new as for non-generic classes with the <T>
placeholder/type parameter changed to the wanted datatype.
As we said before the instantiation must use the reference datatypes, the type-wrapper classes (in package
java.lang), not the primitive datatypes. That means Integer, Short, Long, Float, Double, Byte,
Character, Boolean classes. Those classes enable the primitive types to be manipulated as objects.
The output is:
Integer Value: 10
String Value: Hello World
Example Generics 6
This example demonstrate a non-generic stack
public class NonGeneric_Stack
{
public static void main(String args[])
{
NonGeneric integerObject;
integerObject = new NonGeneric(88);
integerObject.showType();
int v = (Integer) integerObject.pop();
System.out.println("Integer value: " + v);
NonGeneric strOb = new NonGeneric("String test");
strOb.showType();
String str = (String) strOb.pop();
System.out.println("String value: " + str);
//integerObject = strOb;
//v = (Integer) integerObject.pop();
}
}
public class NonGeneric
{
Object ob;
NonGeneric(Object o)
{
ob = o;
}
Object pop()
{
return ob;
}
void showType()
{
System.out.println("Type of ob is " +
ob.getClass().getName());
44
IOPROG – Ingmar Olsson
Begin with Java 2
}
}
The output is:
Type of ob is java.lang.Integer
Integer value: 88
Type of ob is java.lang.String
String value: String test
Take away the comments in the statements and execute again!
//integerObject = strOb;
//v = (Integer) integerObject.pop();
Example Generics 7
This example demonstrates a generic version of the stack in Example Generics 6.
public class GenericStack
{
public static void main(String args[])
{
Generic<Integer> intGen;
intGen = new Generic<Integer>(88);
intGen.showType();
int v = intGen.pop();
System.out.println("Integer value: " + v);
System.out.println();
Generic<String> strGen = new Generic<String>("String test");
strGen.showType();
String str = strGen.pop();
System.out.println("String value: " + str);
}
}
public class Generic<T>
{
T obj; //Declare an object of type T
Generic(T object)
{
obj = object;
}
T pop()
{
return obj;
}
void showType()
45
IOPROG – Ingmar Olsson
Begin with Java 2
{
System.out.println("Type of T is " + obj.getClass().getName());
}
}
The output is:
Type of T is java.lang.Integer
Integer value: 88
Type of T is java.lang.String
String value: String test
Exercise Generics 1
This is an implementation of a non-generic sorting algoritm called InsertionSort. Implement a generic version
of this sorting algoritm.
import java.util.Random;
public class InsertionSort
{
private int[] data;
private static Random generator = new Random();
public InsertionSort( int size )
{
data = new int[ size ];
// Fill array with random ints in range 10-99
for ( int i = 0; i < size; i++ )
data[ i ] = 10 + generator.nextInt( 90 );
}
// Sort array using selection sort
public void sort()
{
int insert;
for ( int next = 1; next < data.length; next++ )
{
insert = data[ next ];
int moveItem = next;
while ( moveItem > 0 && data[ moveItem - 1 ] > insert )
{
data[ moveItem ] = data[ moveItem - 1 ];
moveItem--;
}
data[ moveItem ] = insert; // place inserted element
printPass( next, moveItem ); // output pass of algorithm
}
}
public String toString()
{
StringBuilder temporary = new StringBuilder();
46
IOPROG – Ingmar Olsson
Begin with Java 2
for ( int element : data )
temporary.append( element + " " );
temporary.append( "\n" );
return temporary.toString();
}
}
Exercise Generics 2
This is an implementation of a non-generic Stack (with the elements in the Stack (class Entry) made as a linked
list). Implement a generic version of this Stack.
public class Stack
{
Entry top;
public void push(Object data)
{
top = new Entry(top, data);
}
public Object pop()
{
if (top == null) throw new NullPointerException();
Object result = top.data;
top = top.next;
return result;
}
class Entry
{
public Entry next;
public Object data;
public Entry(Entry next, Object data)
{
this.next = next;
this.data = data;
}
}
}
public class NonGeneric_Stack
{
public static void main(String[] args)
{
Stack s = new Stack();
s.push(1);
s.push(10);
s.push(100);
System.out.println(s.pop());
System.out.println(s.pop());
//System.out.println(s.pop());
Integer num = (Integer)s.pop();
System.out.println(num);
//String number = (String)s.pop();
//System.out.println(number);
}
}
47
IOPROG – Ingmar Olsson
Begin with Java 2
Use the generic Stack on class Integer.
public class GenericStack
{
public static void main(String[] args)
{
Stack<Integer> s = new Stack<Integer>();
s.push(1);
s.push(10);
s.push(100);
System.out.println(s.pop());
System.out.println(s.pop());
System.out.println(s.pop());
}
}
public class GenericStack
{
public static void main(String[] args)
{
Stack<Person> sPerson = new Stack<Person>();
sPerson.push(new Person("Pers1"));
sPerson.push(new Person("Pers2"));
sPerson.push(new Person("Pers3"));
System.out.println(sPerson.pop().toString());
System.out.println(sPerson.pop().toString());
System.out.println(sPerson.pop().toString());
}
}
Use the Stack on the user defined class Person
public class Person
{
private String namn;
private long anstNummer;
static long aNummer = 1000; //Initialt anställningsnummer
public Person(String anstNamn)
{
namn = anstNamn;
//Call to get anstNummer
anstNummer = KonstrueraAnstNummer();
}
public long VisaAnstNummer()
{
return anstNummer;
}
public String VisaNamn()
{
return namn;
48
IOPROG – Ingmar Olsson
Begin with Java 2
}
public static long KonstrueraAnstNummer()
{
return aNummer++;
}
public String toString()
{
//System.out.printf("%s %s\n",namn, anstNummer);
String s = "Namn: " + namn + " " + "Anst nr: " + anstNummer;
return s;
}
}
Use the following client program.
public class GenericStack
{
public static void main(String[] args)
{
Stack<Person> sPerson = new Stack<Person>();
sPerson.push(new Person("Pers1"));
sPerson.push(new Person("Pers2"));
sPerson.push(new Person("Pers3"));
System.out.println(sPerson.pop().toString());
System.out.println(sPerson.pop().toString());
System.out.println(sPerson.pop().toString());
}
}
Wildcards – Wildcard-type argument
Java has several predefined data structures, called Collections, used to organize, store and retrieve data. One
of those Collection classes is ArrayList which exist in both a no-generic and generic, ArrayList<T>, version.
This is examined in the next chapter “Java and Database Technique without Database – ArrayList”.
To examine the wildcard-type argument denoted by a question mark, ?, “unknown type”, the generic
ArrayList<T> will be used a little in advance.
If any type-wrapper datatype (Integer, Double, …) is used there is a built-in subclass for all those classes called
Number. The abstract class Number in java.lang library is the superclass of classes Byte, Double, Float,
Integer, Long, and Short. Subclasses of Number must provide methods to convert the represented numeric
value to byte, double, float, int, long, and short.
Example Generics 8
In this example the datastructure ArrayList<Number> is used in a generic method sum to calculate the sum of
different numbers.
import java.util.ArrayList;
49
IOPROG – Ingmar Olsson
Begin with Java 2
public class NonWildcard
{
public static void main( String args[] )
{
//Number[] contains both Integers and Doubles
Number[] numbers = { 1, 2.4, 3, 4.1 };
ArrayList< Number > numberList = new ArrayList< Number >();
for ( Number element : numbers )
numberList.add( element );
System.out.printf( "The list of numbers contains: %s\n", numberList );
System.out.printf( "Total of the elements in numberList: %.1f\n",
sum( numberList ) );
}
//Calculate sum
public static double sum( ArrayList< Number > list )
{
double total = 0; // initialize total
for ( Number element : list )
total += element.doubleValue();
return total;
}
}
Example Generics 9
If we want Number to contain any subclass to Number, Integer, Double, … we can use the wildcard to extend
the Number class and get the wildcard-type argument ? to denote an upper bound to Number. This is done with
generic type:
ArrayList<? extends Number>
import java.util.ArrayList;
public class Wildcard
{
public static void main( String args[] )
{
//ArrayList of Integers
Integer[] integers = { 1, 2, 3, 4, 5 };
ArrayList< Integer > integerList = new ArrayList< Integer >();
for ( Integer element : integers )
integerList.add( element );
System.out.printf( "IntegerList contains: %s\n", integerList );
System.out.printf( "Total of the elements in integerList: %.0f\n\n",
sum( integerList ) );
//ArrayList of Doubles
Double[] doubles = { 1.1, 3.3, 5.5 };
ArrayList< Double > doubleList = new ArrayList< Double >();
for ( Double element : doubles )
doubleList.add( element );
System.out.printf( "DoubleList contains: %s\n", doubleList );
System.out.printf( "Total of the elements in doubleList: %.1f\n\n",
sum( doubleList ) );
//ArrayList of Numbers containing both Integers and Doubles
Number[] numbers = { 1, 2.4, 3, 4.1 };
ArrayList< Number > numberList = new ArrayList< Number >();
50
IOPROG – Ingmar Olsson
Begin with Java 2
for ( Number element : numbers )
numberList.add( element );
System.out.printf( "numberList contains: %s\n", numberList );
System.out.printf( "Total of the elements in numberList: %.1f\n",
sum( numberList ) );
}
//Calculate sum
public static double sum( ArrayList< ? extends Number > list )
{
double total = 0; // initialize total
for ( Number element : list )
total += element.doubleValue();
return total;
}
}
51
IOPROG – Ingmar Olsson
Begin with Java 2
Java and Database Technique without Database – ArrayList
To handle and store data in volume you need to have a database software (database manager and a database
engine) that can be installed and connected to the development environment and running system.
To handle smaller amount of data and less complex data it can be suitable to use a powerful and generic
Collection datastructure like ArrayList as an in-memory database and use a simple textfile technique for
keeping the data permanent.
The next sections Non-generic ArrayList and Generic/Parameterized Type ArrayList contain basic information of
how to use ArrayList as a surrogate database.
Non-generic ArrayList
The built-in JDK class java.util.ArrayList allows for expandable arrays and has the following advantages over
an array:
An ArrayList automatically expands as data is added.
Access to any element of an ArrayList is O(1). Insertions and deletions are O(N).
An ArrayList has methods for inserting, deleting, and searching.
An ArrayList can be traversed using either iterators or indexes.
Automatic expansion. Use ArrayList when there will be a large variation in the amount of data that you would
put into an array. Arrays should be used only when there is a constant amount of data. For example, storing
information about the days of the week should use an array because the number of days in a week is constant.
Use an array list for your email contact list
because there is no upper bound on the number of contacts.
Objects only. A disadvantage of a ArrayList is that it holds only objects and not primitive types (eg, int). To use
a primitive type in an ArrayList, put it inside an object (eg, to save an integer value use the Integer class or
define your own class). If you use the Integer wrapper, you will not be able to change the integer value, so it is
sometimes useful to define your own class.
Implementation. ArrayLists are implemented with an underlying array, and when that array is full and an
additional element is added, a new array is allocated and the elements are copied from the old to the new.
Because it takes time to create a bigger array and copy the elements from the old array to the new array, it is a
faster to create an ArrayList with a size that it will commonly be when full. Of course, if you knew the final size,
you could simply use an array. However, for non-critical sections of code programmers typically don't specify an
initial size.
Constructors
ArrayList alist1 = new ArrayList();
// Created with default size.
ArrayList alist2 = new ArrayList(300); // Starts with 300 elements
To Add elements to the end of an ArrayList
a.add(s); // adds s to the end of the ArrayList a
To get the elements from an ArrayList
Use either a for loop with an integer index to get all the elements from an ArrayList, or go over all elements in a
ArrayList using an Iterator (forward) or ListIterator (forward / backward).
for loop with index - this is the fastest method, but will need to be changed you later decide to change to a
LinkedList structure.
ListIterator - Allows traversal of the ArrayList, and allows inserts and deletes (although both are very slow for
an ArrayList). It also allows bidirectional traversal. Can be used if the data structure is later changed.
Iterator - Allows simple forward traversal. Can be used for the largest number of other kinds of data structures.
This example uses an Iterator to print all elements (Strings) in an ArrayList. It uses hasNext(), which returns true
if there are more elements, and next(), which returns the next element as an Object, which must be downcast to
the appropriate type (until Java 1.5 additions).
// Without Java 5 generics.
for (Iterator iter = a.iterator(); iter.hasNext();)
{
52
IOPROG – Ingmar Olsson
Begin with Java 2
System.out.println((String)(iter.next()));
}
The following is faster, but less general:
// Without Java 5 generics.
for (int i = 0; i < a.size(); i++)
{
System.out.println((String)(a.get(i)));
}
Sorting
If the data in your ArrayList has a natural sorting order (ie, implements Comparable, as do String, Integer, ...),
you can simply call the static Collections.sort() method. This is a stable, guaranteed n log n sort.
Collections.sort(yourArrayList);
If you want to choose a different sort criterion or your data doesn't implement xxxx, you will have to define a
Comparator and pass that to the sort() method.
Collections.sort(yourArrayList, yourComparator);
Check out Collections for other useful utility methods.
Common ArrayList methods and constructors. Here are some of the most useful ArrayList methods.
a is an ArrayList, i is an int, obj is an Object, iter is an Iterator, liter is a ListIterator.
Result
Method
Description
Constructors
a=
a=
a=
new ArrayList()
new ArrayList(cap)
new ArrayList(coll)
Creates ArrayList with initial default capacity 10.
Creates ArrayList with initial int capacity cap.
Creates ArrayList from the Collection coll.
a.add(obj)
a.add(i, obj)
adds obj to end of ArrayList a
Inserts obj at index i, shifting elements up as
a.set(i,obj)
Sets the element at index i to obj.
Adding elements
necessary.
Replacing an element
Getting the elements
obj =
a.get(i)
Returns the object at index i.
oarray =
a.toArray()
Returns values in array.
oarray =
a.toArray(Object[])
The array parameter can be any Object subclass
(eg, String). This returns values in that array (or a larger array if necessary).
Iterators
iter =
a.iterator()
Returns an Iterator for forward traversal.
liter =
a.listIterator(i)
Returns a ListIterator for forward / backward /
modifying traversal, starting at index i. Start from end with a.listIterator(a.size())
liter =
a.listIterator()
Returns a ListIterator for forward / backward /
modifying traversal.
Searching
b=
a.contains(obj)
Returns true if ArrayList a contains obj
i=
a.indexOf(obj)
Returns index of first occurrence of obj, or -1 if
not there.
i=
a.lastIndexOf(obj)
Returns index of last occurrence of obj, or -1 if not
there.
Removing elements
Other
i=
a.clear()
a.remove(i)
a.removeRange(i, j)
removes all elements from ArrayList a
Removes the element at position i.
Removes the elements from positions i thru j.
a.size()
Returns the number of elements in ArrayList a.
53
IOPROG – Ingmar Olsson
Begin with Java 2
Generic/Parameterized Type ArrayList
JDK 5.0 provides generic or parameterized typed array list. Before JDK 5.0 Array List store the objects of type
Object. But now the type of the elements of an ArrayList can be specified.
This includes a very significant addition of generics feature in which object containers can actually know what
object type they should hold.
Then any attempt to insert an object of the wrong type results in a compile-time error rather than a runtime
ClassCastException.
This generic type notation is also known as a parameterized type.
Syntax:
Type parameter naming: T, U, ...
Although any names are possible for type parameters, they are traditionally written in upper case and often
taken from the sequence T, U, V, ... Other upper case letters are used when they have specific meanings, eg, K
for the type of a key, E for element type.
Reading type parameters
Notation
List<T>
List<?>
Meaning
List of elements of type T (T is a concrete type)
List of any type (? is an unbounded wildcard type)
Example Database-ArrayList 1
import java.util.ArrayList;
public class MyArrayList
{
public static void main(String[] args)
{
Seller sel = new Seller();
Buyer buy = new Buyer();
// Declare an array list of type Seller
ArrayList<Seller> list = new ArrayList<Seller>();
list.add(sel); //Add object of type Seller which is permissible
list.add(buy); //This statement will give an error
}
}
Example Database-ArrayList 2
// Purpose: An example using Scanner, ArrayList, and Collections.sort.
//
Read words, sort them, print them.
import java.util.*;
public class Alphabetize
{
public static void main(String[] args)
{
//... Declare variables.
Scanner in = new Scanner(System.in);
ArrayList<String> words = new ArrayList<String>();
//... Read input one word at a time.
System.out.println("Enter words. End with EOF (CTRL-Z then Enter)");
System.out.println("
or click Close Input in NetBeans.");
//... Read input one word at a time, adding it to an array list.
while (in.hasNext())
{
words.add(in.next());
}
54
IOPROG – Ingmar Olsson
Begin with Java 2
//... Sort the words.
Collections.sort(words);
//... Print the sorted list.
System.out.println("\n\nSorted words\n");
for (String word : words)
{
System.out.println(word);
}
}
}
java.util.ArrayList<E> allows for expandable arrays. An ArrayList has these characteristics:
An ArrayList automatically expands as data is added.
Access to any element of an ArrayList is O(1). Insertions and deletions are O(N).
An ArrayList has methods for inserting, deleting, and searching.
An ArrayList can be traversed using a foreach loop, iterators, or indexes.
Arrays or ArrayList? Programmers are frequently faced with the choice of using a simple array or an ArrayList. If
the data has a known number of elements or small fixed size upper bound, or where efficiency in using primitive
types is important, arrays are often the best choice. However, many data storage problems are not that simple,
and ArrayList (or one of the other Collections classes) might be the right choice.
Automatic expansion. Use ArrayList when there will be a large variation in the amount of data that you would put
into an array. Arrays should be used only when there is a constant amount of data. For example, storing
information about the days of the week should use an array because the number of days in a week is constant.
Use an array list for your email contact list because there is no upper bound on the number of contacts.
Objects only. A possible disadvantage of ArrayList is that it holds only object types and not primitive types (eg,
int). To use a primitive type in an ArrayList, put it inside an object or use of the wrapper classes (eg, Integer,
Double, Character, ...). The wrapper classes are immutable, so if you use, eg, Integer, you will not be able to
change the integer value. In this case it may be more useful to define your own mutable class.
Implementation. ArrayLists are implemented with an underlying array, and when that array is full and an
additional element is added, a new, larger, array is allocated and the elements are copied from the old to the
new. Because it takes time to create a bigger array and copy the elements from the old array to the new array, it
is a slightly faster to create an ArrayList with a size that it will commonly be when full. Of course, if you knew the
final size, you could simply use an array. However, for non-critical sections of code programmers typically don't
specify an initial size.
Common ArrayList methods and constructors
Here are some of the most useful ArrayList methods. Assume these declarations. Note that E is the notation for
the type of an element in a collection. Sun recommends using single upper case letters for generic types.
int i;
ArrayList<E> a;
E e;
Iterator<E> iter;
ListIterator<E> liter;
E[] earray;
Object[] oarray;
Result
Method
Constructors
a=
a=
a=
new ArrayList<E>()
Creates ArrayList with initial default capacity 10.
new ArrayList<E>(cap) Creates ArrayList with initial int capacity cap.
new ArrayList<E>(coll<E>) Creates ArrayList from the Collection coll.
Adding elements
up as necessary.
Replacing an element
Description
a.add(e)
a.add(i, e)
adds e to end of ArrayList a
Inserts e at index i, shifting elements
a.set(i,e)
Sets the element at index i to e.
55
IOPROG – Ingmar Olsson
Begin with Java 2
Getting the elements
e=
a.get(i)
Returns the object at index i.
oarray =
a.toArray()
Returns values in array of objects.
earray =
a.toArray(E[])
The array parameter should be of the E
class. Returns values in that array (or a larger array is allocated if necessary).
Iterators
iter =
a.iterator()
Returns an Iterator for forward
traversal.
liter =
a.listIterator(i)
Returns a ListIterator for forward /
backward / modifying traversal, starting at index i. Start from end with a.listIterator(a.size())
liter =
a.listIterator()
Returns a ListIterator for forward /
backward / modifying traversal.
Searching
b=
i=
if not there.
i=
if not there.
Removing elements
Other
i=
ArrayList a.
a.contains(e)
a.indexOf(e)
Returns true if ArrayList a contains e
Returns index of first occurrence of e, or -1
a.lastIndexOf(e)
Returns index of last occurrence of e, or -1
a.clear()
a.remove(i)
a.removeRange(i, j)
a.size()
Removes all elements from ArrayList a
Removes the element at position i.
Removes the elements from positions i thru j.
Returns the number of elements in
Adding elements to the end of an ArrayList, getting them by index
ArrayList<E> a = new ArrayList<E>(); // Default size.
E s;
// Declare s to be an object type E.
...
a.add(s);
// Adds s to the end of the ArrayList a
...
s = a.get(i); // Assigns ith element from a to s.
To get successive elements from an ArrayList - Four ways
Use either a for loop with an integer index to get all the elements from an ArrayList, or go over all elements in a
ArrayList using an Iterator (forward) or ListIterator (forward / backward).
1. foreach loop. This is fast and works for all kinds of lists, but is not entirely flexible (only sequential forward
with no deletions, additions, or multiple references). This should be your first choice in programming. Works
efficiently with both ArrayList and LinkedList.
ArrayList<String> a = new ArrayList<String>();
. . .
for (String s : a)
{
System.out.println(s);
}
2. for loop with index. This is fast, but should not be used with a LinkedList. It does allow orders other than
sequentially forward by one.
for (int i = 0; i < a.size(); i++)
{
System.out.println(a.get(i));
}
3. Iterator<E> - Allows simple forward traversal. Can be used for the largest number of other kinds of data
structures.
56
IOPROG – Ingmar Olsson
Begin with Java 2
This example uses an Iterator to print all elements (Strings) in an ArrayList. It uses hasNext(), which returns
true if there are more elements, and next(), which returns the next element. Works with both ArrayList and
LinkedList.
for (Iterator<String> iter = a.iterator(); iter.hasNext();
{
System.out.println(iter.next());
}
)
4. ListIterator<E> - Allows traversal of the ArrayList, but it is more general than a simple Iterator, allowing
inserts and deletes (although both are very slow for an ArrayList). It also allows bidirectional traversal. Works
efficiently with both ArrayList and LinkedList.
Sorting
If the data in your ArrayList has a natural sorting order (ie, implements Comparable, as do String, Integer, ...),
you can simply call the static Collections.sort() method. This is a stable, guaranteed n log n sort.
Collections.sort(yourArrayList);
If you want to choose a different sort criterion or your data doesn't implement xxxx, you will have to define a
Comparator and pass that to the sort() method.
Collections.sort(yourArrayList, yourComparator);
Check out Collections for other useful utility methods.
Console Menu
In all applications, small or huge, it is necessary to have a robust and user friendly user interface. This can be a
TUI (Textual User Interface) or a GUI (Graphic User Interface).
Here is a skeleton for a TUI or a console menu that is suitable for many applications. GUI will be covered in
future chapters.
The menu alternative and the activities are optional and are adopted to the application.
//Menu.java
import java.util.*;
class AddCustomer
{
public AddCustomer()
{
System.out.println("AddCustomer not implemented");
}
}
class AddItem
{
public AddItem()
{
System.out.println("AddItem not implemented");
}
}
class AddRental
{
public AddRental()
{
System.out.println("AddRental not implemented");
}
}
class UpdateProduct
{
public UpdateProduct()
{
System.out.println("UpdateProduct not implemented");
}
}
57
IOPROG – Ingmar Olsson
Begin with Java 2
class DeleteProduct
{
public DeleteProduct()
{
System.out.println("DeleteProduct not implemented");
}
}
class ViewProduct
{
public ViewProduct()
{
System.out.println("ViewProduct not implemented");
}
}
public class Menu
{
public static void main(String[] args) throws Exception
{
Scanner scan = new Scanner(System.in);
int menu = 0;
boolean quit = false;
do
{
menu();
System.out.println();
System.out.print("Please enter your choice: ");
menu = scan.nextInt();
System.out.println();
switch(menu)
{
case 1:
AddCustomer addC = new AddCustomer();
break;
case 2:
AddItem addI = new AddItem();
break;
case 3:
AddRental addR = new AddRental();
break;
case 4:
UpdateProduct update = new UpdateProduct();
break;
case 5:
DeleteProduct delete = new DeleteProduct();
break;
case 6:
ViewProduct view = new ViewProduct();
break;
case 9:
quit = true;
break;
default:
System.out.println("Invalid Entry!");
}
}
while (!quit);
}
public static void menu()
{
System.out.println();
System.out.println("Menu");
System.out.println();
System.out.println("1. Add Customer");
System.out.println("2. Add Item");
System.out.println("3. Add Rental");
System.out.println("4. Update Product");
System.out.println("5. Delete Product");
System.out.println("6. View Product");
System.out.println("7. Write Database (Textfiles)");
58
IOPROG – Ingmar Olsson
Begin with Java 2
System.out.println("8. Read Database (Textfiles)");
System.out.println("9. Exit");
System.out.println();
}
This menu/TUI can be exercised like this!
59
IOPROG – Ingmar Olsson
Begin with Java 2
An application using ArrayList as a Database
Database introduction
A database table is a container that holds information about like items. For example, an Customers table would
contain the same basic details on each customer: number, name, title, department and so on. Each detail, each
chunk of information you need to store lives in a field. When you view a single customer record, you can displays
it in a textual print-out or a graphical form. Whenever you want to view more that one record at a time, you do
so in a table report, where fields appear as columns and each record is a row.
A relationship between tables is usually a one-to-many affair. In other words, one record in the master table
relates to many records in the detail table. For example, one course has many students assigned to it. But what if
you need to assign MANY students to MANY courses?
To accomplish this many-to-many connection, you can add a third table that acts as a go-between or relation and
handles all the possible combinations involved.
Datamodel
You can represent the tables with a picture (datamodel) like this:
Customer
1
∞
CustomerNimber
CustomerName
many
Rental
CustomerNumber
ItemNumber
∞
many
1
Item
ItemNumber
ItemName
Here are some examples on applications/datamodels where you have to use the many-to-many technique:
Customer
Customer
Borrower
Student
Pupil
Author
Rental
Order
Loan
Enrollment
Schedule
Published
Item
Product
Book
Course
Class
Book
Design and Implementation
This application is supposed to have functionality for a rental/business company which wants to store and handle
information about current rental/order, customer, rental/product items as DVDs, CDs, Mobile Phones, Cars,
Tools, TV sets, Toys, … and similar.
In the first design step and implementation of the application we use a generic ArrayList as an in-memory
database and a textfile for persistency of the data.
As a data model we use a Customer class, Rental class and an Item class that can be specialized for different
item.
Implement the Customer class. Use only two datamembers so far: number and name and the corresponding
accessor methods, getCustomerID() and getCustomerName().
Implement the Item class. Datamembers ID and name, accessors getItemID() and getItemName().
Implement the “join”, “many-to-many” Rental class. Datamembers number (key from Customer class) and ID
(key from Item class), accessors getCustomerID() and getItemID().
//Customer.java
public class Customer
{
private int number;
private String name;
public Customer(String n, int i)
{
number = i;
60
IOPROG – Ingmar Olsson
Begin with Java 2
name = n;
}
public int getCustomerID()
{
return number;
}
public String getCustomerName()
{
return name;
}
}
//Item.java
public class Item
{
private int ID;
private String name;
public Item (String n, int i)
{
name = n;
ID = i;
}
public int getItemID()
{
return ID;
}
public String getItemName()
{
return name;
}
}
//Rental.java
public class Rental
{
private int number;
private int ID;
public Rental (int n , int i)
{
number = n;
ID = i;
}
public int getItemID()
{
return ID;
}
public int getCustomerID()
{
return number;
}
}
Implement a class Database and use generic/parameterized ArrayLists as the built-in datastructure for the
database.
//Database.java
import java.util.ArrayList;
public class Database
{
private ArrayList<Rental> rental;
private ArrayList<Customer> customer;
private ArrayList<Item> item;
61
IOPROG – Ingmar Olsson
Begin with Java 2
public Database()
{
rental = new ArrayList<Rental>();
customer = new ArrayList<Customer>();
item = new ArrayList<Item>();
}
}
To get the persistency for the database use in this application the simpliest form of textfiles handling the read
and write functionality with the built-in Java classes Scanner and Formatter.
Database monitor
To handle the database interface with the user, use a textual user interface (TUI). In a database system this is
often called a monitor. In this application it is shaped as a menu.
//Menu.java
import java.util.*;
public class Menu
{
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
Database d = new Database();
int menu = 0;
boolean quit = false;
do
{
menu();
System.out.println();
System.out.print("Please enter your choice: ");
menu = scan.nextInt();
System.out.println();
switch(menu)
{
case 1:
WriteCustomer_TextFile writeC = new WriteCustomer_TextFile();
writeC.openFile();
writeC.addRecords();
writeC.closeFile();
break;
case 2:
WriteItem_TextFile writeI = new WriteItem_TextFile();
writeI.openFile();
writeI.addRecords();
writeI.closeFile();
break;
case 3:
WriteRental_TextFile writeR = new WriteRental_TextFile();
writeR.openFile();
writeR.addRecord();
writeR.closeFile();
break;
//case 4:
//case 5:
//case 6:
//case 7:
//case 8:
case 9:
quit = true;
break;
default:
System.out.println("Invalid Entry!");
}
}
while (!quit);
}
62
IOPROG – Ingmar Olsson
Begin with Java 2
public static void menu()
{
System.out.println();
System.out.println("Menu");
System.out.println();
System.out.println("1. Write/Add Customer Database Table (TextFile)");
System.out.println("2. Write/Add Item Database Table (TextFile)");
System.out.println("3.
System.out.println("4.
System.out.println("5.
System.out.println("6.
System.out.println("7.
System.out.println("8.
System.out.println("9.
System.out.println();
Write/Add Rental Database Table (TextFile)");
Read Customer Database Table (TextFile)");
Read Item Database Table (TextFile)");
Read Rental Database Table (TextFile)");
Find Customer rentals of Items");
Find Items rented by Customer");
Exit");
}
Write/Add Customer Database Table (TextFile)
Continue with implementation of the Database Monitor/Menu functionality for
1. Write/Add Customer Database Table (TextFile)
case 1:
WriteCustomer_TextFile writeC = new WriteCustomer_TextFile();
writeC.openFile();
writeC.addRecords();
writeC.closeFile();
This functionality is included in the class WriteCustomer_TextFile that is instantiated in case 1: alternative in
the Menu class.
This class implements three methods:
void openFile()
This method opens the textfile Customer_Textfile.txt (“hard-coded” name, but can be optional) in read mode
with the built-in class Scanner. This textfile must exists even if it is empty when the program starts. Otherwise
you get the programmed exception. The textfile is created by a texteditor like Notepad, WordPad, xemacs or
other texteditor in the same filesystem/folder as the applications project/.java files.
The method reads the existing texfile, creates Customer objects with the number and name datamembers and
add the objects to an ArrayList. The textfile is closed.
The method openFile() now opens the textfile with the same name Customer_TextFile.txt again in write
mode with the built-in class Formatter. It will then be overwritten! The method now writes the numbers and
names from existing Customer objects in the ArrayList (in-memory database) to the textfile
Customer_TextFile.txt (“permanent” database). The textfile is not closed!
void addRecords()
The method addRecords() now asks the user of the application for new Customer’s number and name and
write directly (at the end) to the textfile Customer_TextFile.txt
(open in write mode) .
void closeFile()
The method closeFile() closes the textfile Customer_TextFile.txt.
//WriteCustomer_Textfile.java
import java.util.ArrayList;
import java.io.File;
import java.util.Formatter;
import java.util.Scanner;
import java.io.FileNotFoundException;
public class WriteCustomer_TextFile
{
private Formatter output;
private Scanner readFile;
63
IOPROG – Ingmar Olsson
Begin with Java 2
public void openFile()
{
try
{
//Homemade append
//Saves the existing textfile with the object (Customer) datamembers
//in an object ArrayList
//The textfile must exists and the name of the textfile is "hardcoded"
//to "Customer_TextFile.txt"
Customer c;
int tempNumber;
String tempName;
ArrayList<Customer> tempList = new ArrayList<Customer>();
readFile = new Scanner( new File( "Customer_TextFile.txt" ) );
while(readFile.hasNext())
{
tempNumber = readFile.nextInt();
tempName = readFile.next();
c = new Customer(tempName,tempNumber);
tempList.add(c);
}
readFile.close();
//Open the (same) existing textfile in write mode
// The existing textfile will be overwritten
//Write the existing datamembers for the objects from the ArrayList
output = new Formatter("Customer_TextFile.txt");
for (int i = 0; i <= tempList.size() - 1; i++)
{
tempName = ((Customer)tempList.get(i)).getCustomerName();
tempNumber = ((Customer)tempList.get(i)).getCustomerID();
output.format("%-10d%-50s\n", tempNumber, tempName);
}
}
catch ( FileNotFoundException filesNotFoundException )
{
System.err.println( "Error creating file." );
System.exit( 1 );
}
}
public void addRecords()
{
int number;
String name;
Customer c;
//Continue to append (write to end of) the open textfile with new object
//datamembers for the Customer class.
Scanner input = new Scanner( System.in );
System.out.printf( "%s\n%s\n%s\n%s\n\n",
"To terminate input, type the end-of-file indicator ",
"when you are prompted to enter input.",
"On UNIX/Linux/Mac OS X type <ctrl> d then press Enter",
"On Windows type <ctrl> z then press Enter" );
System.out.printf("Enter customer number (> 0), customer name (space between): " );
while ( input.hasNext() )
{
number = input.nextInt();
name = input.next();
c = new Customer(name, number);
if (number > 0)
{
output.format("%-10d%-50s\n", c.getCustomerID(), c.getCustomerName());
}
else
64
IOPROG – Ingmar Olsson
Begin with Java 2
{
System.out.println("Account number must be greater than 0." );
}
System.out.printf("Enter customer number (> 0), customer name (space between): " );
}
}
public void closeFile()
{
if ( output != null )
output.close();
}
}
Compile the files Database.java, Customer.java, WriteCustomer_TextFile.java and Menu.java. Start
and run the program from the compiled class Menu.
The resulted Customer_TextFile.txt file is like this
1
2
3
Nisse
Allan
Sven
This textfile can be opened/read as usual by Notepad, WordPad, xemacs or other texteditor directly from the
filesystem/folder where the applications projectfiles/.java files are located.
Exercise Database-ArrayList 1
Implement the Database Monitor/Menu functionality for
2. Write/Add Item Database Table (TextFile)
case 2:
WriteItem_TextFile writeI = new WriteItem_TextFile();
writeI.openFile();
writeI.addRecords();
writeI.closeFile();
This implementation is entirely similar to the implementation of WriteCustomer_TextFile class.
65
IOPROG – Ingmar Olsson
Begin with Java 2
Exercise Database-ArrayList 2
Implement the Database Monitor/Menu functionality for
3. Write/Add Rental Database Table (TextFile)
case 3:
WriteRental_TextFile writeR = new WriteRental_TextFile();
writeR.openFile();
writeR.addRecord();
writeR.closeFile();
The implementation of the class WriteRental_TextFile shall cover the “many-to-many” connection between
the Customer and Item table/class . This class contains the methods
void openFile();
void addRecord();
void writeR.closeFile();
The method void openFile() needs to have the same append functionality for Rental_TextFile.txt as in
class WriteCustomer_TextFile and in class WriteItem_TextFile. Then it needs to have methods like int
findCustomer() and int findItem() to decide what Item (number) a given Customer (number) wants to
rent, the “many-to-many” connection. This Customer-Item connection is then written to Rental_TextFile.txt
by the method void addRecord(). This method is not the same as the earlier methods void addRecords()!
Exercise Database-ArrayList 3
Implement the Database Monitor/Menu functionality for
4. Read Customer Database Table (TextFile)
5. Read Item Database Table (TextFile)
6. Read Rental Database Table (TextFile)
Exercise Database-ArrayList 4
Implement the Database Monitor/Menu functionality for
7. Find Customer Rentals of Items
Exercise Database-ArrayList 5
Implement the Database Monitor/Menu functionality for
8. Find Items rented by Customer
66