java

260
Java Page 1 - Copyright © 2012 Walter Milner - all rights reserved Java The First Step ...................................................................................................................................... 4 Basic Programming Ideas .................................................................... 6 Command line programming .............................................................................................................. 7 Installing and Using an IDE ................................................................................................................ 10 Writing Your Own Programs ............................................................................................................. 12 How Java works................................................................................................................................. 14 Data ................................................................................................................................................... 16 Data types ......................................................................................................................................... 17 Variables ........................................................................................................................................... 18 Input and Output .............................................................................................................................. 20 Statements ........................................................................................................................................ 23 The Three Frames of Programming .................................................................................................. 24 Expressions........................................................................................................................................ 27 Increment decrement and short-cut ................................................................................................ 29 Conditional Statements .................................................................................................................... 30 Algorithms ......................................................................................................................................... 35 Loops ................................................................................................................................................. 38 Testing ............................................................................................................................................... 43 Data Structures ................................................................................................................................. 44 Bitwise operations ............................................................................................................................ 51 Using a Debugger .............................................................................................................................. 54 Type casts.......................................................................................................................................... 57 Structured Programming .................................................................. 59 Static methods and parameter passing ............................................................................................ 60 Scope ................................................................................................................................................. 64 Recursion .......................................................................................................................................... 66 When it does not work ..................................................................................................................... 69 OOP ................................................................................................... 72 Classes and objects ........................................................................................................................... 73 Characters and Strings ...................................................................................................................... 76

Upload: rulz-andrei

Post on 21-Jul-2016

107 views

Category:

Documents


2 download

DESCRIPTION

Java

TRANSCRIPT

Page 1: Java

Java

Page 1 - Copyright © 2012 Walter Milner - all rights reserved

Java

The First Step ...................................................................................................................................... 4

Basic Programming Ideas .................................................................... 6

Command line programming .............................................................................................................. 7

Installing and Using an IDE ................................................................................................................ 10

Writing Your Own Programs ............................................................................................................. 12

How Java works ................................................................................................................................. 14

Data ................................................................................................................................................... 16

Data types ......................................................................................................................................... 17

Variables ........................................................................................................................................... 18

Input and Output .............................................................................................................................. 20

Statements ........................................................................................................................................ 23

The Three Frames of Programming .................................................................................................. 24

Expressions........................................................................................................................................ 27

Increment decrement and short-cut ................................................................................................ 29

Conditional Statements .................................................................................................................... 30

Algorithms ......................................................................................................................................... 35

Loops ................................................................................................................................................. 38

Testing ............................................................................................................................................... 43

Data Structures ................................................................................................................................. 44

Bitwise operations ............................................................................................................................ 51

Using a Debugger .............................................................................................................................. 54

Type casts .......................................................................................................................................... 57

Structured Programming .................................................................. 59

Static methods and parameter passing ............................................................................................ 60

Scope ................................................................................................................................................. 64

Recursion .......................................................................................................................................... 66

When it does not work ..................................................................................................................... 69

OOP ................................................................................................... 72

Classes and objects ........................................................................................................................... 73

Characters and Strings ...................................................................................................................... 76

Page 2: Java

Java

Page 2 - Copyright © 2012 Walter Milner - all rights reserved

A first look at Swing .......................................................................................................................... 80

The Java API ...................................................................................................................................... 83

Subclassing ........................................................................................................................................ 84

Variables and values ......................................................................................................................... 87

Wrapper Classes................................................................................................................................ 94

Overloading ....................................................................................................................................... 95

Inheritance ........................................................................................................................................ 98

The Object class .............................................................................................................................. 100

Overloading and overriding ............................................................................................................ 102

super ............................................................................................................................................... 103

this................................................................................................................................................... 108

static ................................................................................................................................................ 110

Date and Time in Java ..................................................................................................................... 115

Interfaces ........................................................................................................................................ 119

Event handling ................................................................................................................................ 121

Defining a new class ........................................................................................................................ 124

Projects and Packages ..................................................................................................................... 126

Encapsulation .................................................................................................................................. 128

Writing new classes - a personnel system ...................................................................................... 130

Writing New Classes - Tic Tac Toe ................................................................................................... 140

Binary Trees .................................................................................................................................... 146

Hash tables ...................................................................................................................................... 151

Swing .............................................................................................. 155

Starting a Swing application ............................................................................................................ 156

Swing event handling ...................................................................................................................... 157

Swing containers ............................................................................................................................. 161

Swing widgets ................................................................................................................................. 168

Images ............................................................................................................................................. 170

Color ................................................................................................................................................ 172

Fonts................................................................................................................................................ 173

Menus, Popups andToolbars .......................................................................................................... 174

Swing and MVC ............................................................................................................................... 177

Inheritance - a GUI Tic Tac Toe ....................................................................................................... 181

Java 2D ............................................................................................................................................ 186

Page 3: Java

Java

Page 3 - Copyright © 2012 Walter Milner - all rights reserved

More OOP ....................................................................................... 192

abstract ........................................................................................................................................... 193

Annotations ..................................................................................................................................... 198

Nested Classes ................................................................................................................................ 200

Generics .......................................................................................................................................... 205

The Collections Framework ............................................................................................................ 211

Enums .............................................................................................................................................. 216

Exceptions ....................................................................................................................................... 218

Multi-threading ............................................................................................................................... 225

Classes and types ............................................................................................................................ 237

Input and Output ............................................................................................................................ 241

Reflection ........................................................................................................................................ 249

Networking - UDP ........................................................................................................................... 251

Networking - TCP ............................................................................................................................ 256

Networking - URLs........................................................................................................................... 258

Page 4: Java

Java

Page 4 - Copyright © 2012 Walter Milner - all rights reserved

The First Step

This is intended for people who are learning Java and who have never programmed before.

Java is a big deal. Learning to program in Java is not like learning wordprocessing or learning how to

use a graphics program or editing a video. Such applications try to be as easy as possible to use. Java

is a language which was designed to be used by experienced professional programmers who were

experienced in coding in C. It was designed to be the best possible general-purpose language,

designed on the basis of around 50 years development of programming languages. It was designed

to be the best, not the easiest.

So expect to take this seriously, expect to have to think hard, and expect to spend considerable time

learning it - mostly by using it to write programs. An undergraduate might expect to learn basic Java

over their first year. They might follow more advanced topics over the next two yeas.

You will find it easier if you also learn basic computer science at the same time - compilers

interpreters and syntax, algorithms and data structures and so on. This will help to make more sense

of many of the topics.

Try out the code in the book. It is easiest and faster if you copy and paste it from an electronic

version. Try and make small changes, and see what happens. Write lots of your own small programs.

If things won't work - look at the chapter about debugging.

What is Java?

Java is a general purpose programming language, designed by a small group working at Sun

MicroSystems. Any further description would not make sense until you learn more of the concepts

involved.

What to read first

You could start at the beginning and read it to the end. Or you could start at the end, but this is not

recommended.

The inter-relationships between the concepts in Java mean it is not possible to order the

presentation into a single line. So you might read a section with partial understanding, read on, then

go back and re-read with more understanding. In fact you should.

The reason for this is that Java was designed so that experienced programmers could learn it quickly.

But they already had a significant set of concepts already developed. If you are a beginner, you do

not, and so you will probably have to go back and forth.

There are five main sections:

Basic programming ideas - including setting up your computer to write and run Java

Structured programming

OOP - object-oriented programming

Page 5: Java

Java

Page 5 - Copyright © 2012 Walter Milner - all rights reserved

Swing - writing GUI programs in Java

More OOP - not so basic OOP ideas.

What else to read

There is a great deal of Java material on the web. Some is good, most is not.

The most reliable material is from Oracle (who took over Sun). 'The Java Programming Language' by

Arnold, Gosling and Holmes is the key text, but not the easiest. 'The Java Language Specification' sets

out formally the language. This is a free download, but is not for beginners. 'The Java Virtual

Machine Specification' is another free download but again is not for beginners.

Oracle offer an on-line set of tutorial 'Trails'. These are more suitable for people converting from

other languages.

Useful Links

Where appropriate, links to reliable learning materials are given. Some key links follow. These are

not suitable for total beginners, but bookmark them now:

The Java SE 7 API

The Java 7 Language Specification

Java 7 Virtual Machine Specification

The Oracle Java Tutorials

Java 7 SE Documentation

Page 6: Java

Java

Page 6 - Copyright © 2012 Walter Milner - all rights reserved

Basic Programming Ideas

This part is mostly about what a computer program actually is, how you can work out what a

program will do, and how you write one.

Some people think these ideas are obvious. Others do not, and so programming makes no sense to

them, and they quickly drop out. Many courses do not address these ideas.

If you are new to programming, read this carefully.

This part also leads you through what to install on your computer and how to set it up so that you

can write and run Java programs.

You must write lots of small simple programs. Or you will not understand anything.

Page 7: Java

Java

Page 7 - Copyright © 2012 Walter Milner - all rights reserved

Command line programming

This section is about setting up a computer and writing a first Java program using the 'command

line'. Most people think this is the best way to start. The details here assume you are using

Windows. If you use Linux or another OS, the principles are the same but the details are different -

use Google.

Follow through this tutorial as you read it.

You need to:

Use a text editor, such as Notepad, to write the source code. You save this as a file with the

extension .java.

Use the compiler to compile it into a bytecode file, with the extension .class. You might get

error messages at this stage.

Use the JRE to execute the bytecode. Error messages are also possible here.

You need to have the compiler and other tools installed – this is called the software development

toolkit ( JDK ). This is a free download from the web. Google Java JDK. You want Java SE (Standard

Edition) not J2EE (Enterprise Edition). The JRE (to run Java) is bundled with the JDK (to write Java).

Select the one matching your OS – Windows, Linux, Mac or Solaris.

Once you have installed the JDK, we can start using it, as follows:

To get to the command line (on Windows XP) go Start.. Accessories.. Command Prompt. (On

Windows 7, go Start..All

programs..Accessories..

Command Prompt.) You will

see a window with a black

background and a prompt like

C:\Documents and

Settings\Walter Milner>

Type in the word java and

press Enter. In other words you

would see:

C:\Documents and Settings\Walter Milner>java

and you hit Enter (things you type are in yellow). You should get lots of lines of help messages listing

options. We are just checking you have the JDK correctly installed.

If it says ‘Not recognised’, check the download and installation, and also the 'path' setting. The path

is an 'environment variable' which is a list of folders. When you type in a command, the OS searches

in those folders for a program with the same name. In this case we want it to find and run the

program named java.exe. This will probably be in the folder named

C:\Program Files\Java\jdk1.7.0\bin

Command line interface

Page 8: Java

Java

Page 8 - Copyright © 2012 Walter Milner - all rights reserved

depending on the version. Check

you have this, then make sure

this is included in the list of

folders in the path. Google how to

set the path for your version of

Windows.

Type in

cd Desktop

This changes directory to your

Desktop.

Type in

notepad

This will start Notepad, the text editor, running. In Notepad type in the following:

public class ProgramOne { public static void main(String[] args) { System.out.println("It works"); } }

Type it exactly as it is here. The best way if possible is to cut and paste it. It must be capital P for

ProgramOne, capital S for String, capital S for System. Each bracket must be the correct type. The

quotes must be double “ not single ‘.

Then save this, in the Desktop. The filename must be ProgramOne.java – note the capital P.

Click back at the command line. Type in

dir *.java

This means list all the files ending in java. You should see your file ProgramOne.java listed. If not you

have saved it in the wrong place.

Next type in

javac ProgramOne.java

javac is the Java compiler. You are telling the compiler to compile your file ProgramOne.java into

bytecode. You might get an error message. If so, read it very carefully – it will tell you the line

number where the error is. Go back to Notepad, find the line and correct it. Save it again and run the

compiler. Repeat until you get no error message.

Type in

dir *.class

Running java.exe

Page 9: Java

Java

Page 9 - Copyright © 2012 Walter Milner - all rights reserved

which lists all files ending in class. You should see ProgramOne.class, which is the bytecode produced

by the compiler.

Then type in

java ProgramOne

Check capital P. This invokes the JRE and executes your bytecode. You should see

It works

You have now started. You are no longer maggots.

You can write all your Java code like this – use Notepad to write it, compile it with ‘javac’ and run it

with ‘java’.

Summary

To write and run Java programs at the command line, you need the JDK and the JRE, which are free

downloads.

Exercise

Make sure you follow through this tutorial on your computer

Page 10: Java

Java

Page 10 - Copyright © 2012 Walter Milner - all rights reserved

Installing and Using an IDE

An IDE is an 'integrated desktop environment'. This is a piece of software which includes an editor, in

which you can write your source code, and the ability to compile and run the code from one button.

They also include many other features, which take a long time to explore - probably you will not use

some of them. It is suggested you start with the basic usage described here, and progress on a need

to know basis.

There are two common (and

free) IDEs - NetBeans and

Eclipse.

Netbeans

Google NetBeans, and download

the latest version for your OS.

This will include the JRE.

For a first try-out, do the

following:

Run NetBeans

From the menu, go File..

New project.. Choose

category Java.. Java

application..Next..

Project name

ProgramOne .. Create

main class yes, and set

as main project yes,

then Finish

You should see

something like on the

left. The right-hand pane

headed Main.java is

your source code. The ‘syntax colouring’ helps you see what is what. On the left you see your

projects, with the Source packages containing the package programone,File..New.. Java Project and

inside that, the source code Main.java.

Make a small change to the source code, like this:

public static void main(String[] args) { System.out.println("It works"); }

so you just change the TODO line.

NetBeans 7.1.2 running on openSUSE Linux

Figure 1

Page 11: Java

Java

Page 11 - Copyright © 2012 Walter Milner - all rights reserved

Then compile it and run the bytecode by clicking the green triangle button under the menu.

You’ll either get an error message, or towards the bottom of the screen, a pane headed Output will

appear, saying “It works”.

This has set up a 'project'. This is a set of source files - in this case, just one, called Main.java, but for

typical projects there will be several. There might also be additional 'libraries' of system code which

your project uses, and maybe resources like image or sound files.

Using Eclipse

Google Eclipse downloads. You want Eclipse for Java Developers. Download and install it.

For your first try-out, start Eclipse,

then go File.. New.. Java

project..Project Name

programone.. Finish.

Then go File..New..Java class..

Name Main, check public static

void main. You should see:

The source code editor pane is on

the right. Make a small change to

the source code, like this:

public static void main(String[] args) { System.out.println("It works"); }

so you just change the TODO line.

Run it by clicking the green arrow button under the menu. Towards the bottom you will see a pane

headed “Console”, which should say “It works”.

How to carry on

You can use the code in the following sections, and write your own, by just changing the source

code. At the command line you need to save, compile and run it. In NetBeans or Eclipse, just change

the source code and run it.

Summary

You can use IDEs such as NetBeans or Eclipse to write and run Java instead of using teh command

line. Both are free downloads.

Page 12: Java

Java

Page 12 - Copyright © 2012 Walter Milner - all rights reserved

Writing Your Own Programs

Here is a Java program to use as a model for your programs:

class MyProgram { public static void main(String[] args) { System.out.println("Hello"); } }

Modify this like :

Write your code to replace the System.out.println as shown.

The class name ( MyProgram ) must match the filename it is saved in, including capitalisation. So the

class MyProgram must be save in the file named MyProgram.java.

Using the command line

1. Use Notepad or any text editor to write the program.

2. Save it with the correct filename. If the class name is ProgramTwo, save it as ProgramTwo.java

3. Compile it by typing javac <filename>. So if you wrote ProgramTwo.java, say javac

ProgramTwo.java

4. Run it by saying java <classfile>. So if you are writing PrograTwo, say java ProgramTwo.

Using NetBeans

In NetBeans, programs are written as groups of files called 'Projects'. Do as follows:

1. From the menu, go File.. New Project.. Java..Java application (Next) Project Name 'Whatever' ,

Create Main Class Test (or whatever), and Finish

2. In the editor pane you will see a source code file, public class Test (or whatever), and a public

static void main. Write you code there.

3. To compile and run it, click the green arrow in the toolbar.

Using Eclipse

This is very similar. See the part on Eclipse in the previous section.

Page 13: Java

Java

Page 13 - Copyright © 2012 Walter Milner - all rights reserved

Summary

1. Use the model given as a template for your own programs.

2. The filename must match the name of the class, and end .java

Exercise

Modify and run a program at the command line or using an IDE

Page 14: Java

Java

Page 14 - Copyright © 2012 Walter Milner - all rights reserved

How Java works

People use computers as if they were servants. But there are significant differences.

Computers are very fast – like several thousand million operations per second

There are a very limited set of kinds of things they can do – like moving pieces of data

around in memory, doing arithmetic, comparing data and so on

Processors seem to be like brains – but in fact they are electronic devices, which can input

binary codes which are treated as ‘instructions’ and which are carried out – moving data and

so on.

How computers work

Computers and all other programmable digital devices contain a processor. This is an electronic

device which can recognise and execute instructions. An instruction is a very simple step - like

moving data around in memory, doing arithmetic, comparing data and so on. These instructions are

encoded as binary strings, like 0110 1101, and held in memory. The processor fetches one

instruction at a time from memory, decodes it, carries it out, and moves on to the next one. The

processor will carry out around a thousand million instructions per second.

A program is contains a sequence of these instructions. A program is stored in a file, and must be

loaded into memory before the instructions are carried out (because it would be too slow to read it

in from file one instruction at a time). This is called machine code or native code.

Different processor chips have different instruction sets - so a machine code program for a Motorola

chip will not work on a computer with an Intel chip.

Programs also use facilities provided by the OS (Windows or Linux and so on). This means the same

program will not run on different OS.

Writing programs using machine code is extremely difficult and error-prone. Instead programs are

normally written in a high-level language such as Java, which uses English words.

High-level language programs must be converted into machine

code before they can be executed. This is done by a piece of

software called a compiler. The program as you write it is called

source code.

In fact Java from the start was based on the Internet, and so Java

programs needed to work on a wide range of computers with

different processors (and so different machine code) and

different operating systems (such as Windows, Linux, MacOS and

Solaris). In other words Java is cross-platform.

But how to do this? The instruction sets of different processors

are different - so how could the same Java program work on

different processors?

The solution to this was the idea of a virtual machine ( the Java Source code and byte code

Page 15: Java

Java

Page 15 - Copyright © 2012 Walter Milner - all rights reserved

Virtual machine, JVM). This was a piece of software which in effect ironed out the differences of

different platforms, so that they all seemed the same. Each different platform has its own JVM,

taking into account the hardware differences.

A Java application is compiled into an intermediate form called bytecode. A piece of software called

the Java Runtime Environment (JRE) then executes the bytecode on the JVM.

This means the same Java program will run on a wide range of platforms. This is one of the most

significant feature of Java. Compared with other languages, especially C and C++, it is slightly slower

– but it has the big advantage that it will run unchanged on many different platforms.

EXAMPLE

Suppose you were planning to write a personal finance application which people could use to track

their spending and saving. This could be a desktop application – in other words it would be a

program which ran on the user’s computer, rather than on a server across the Internet. You plan to

sell the application as a download from your website.

Do you use Java or C++? C++ would probably be slightly faster, but this is not a speed-critical

application. If you use C++, you would need to write different versions for different types of

computers – Windows machines, Linux, Macs and so on. By contrast, the same Java code would

work the same on all these platforms, provided users have the JRE installed.

Having decided to use Java, you would write the program as source code. You would then need to

compile it, producing bytecode. It is this bytecode which users would buy. They would download and

install the bytecode. When this ran, the JRE would execute it on the JVM. Different types of

computers would have different JVMs, making them all seem the same and enabling the same code

to run on different platforms.

Summary

1. Java source code is compiled into an intermediate form called bytecode.

2. Bytecode runs on a JVM

3. There are JVMs for different hardware/OS platforms

4. The same Java program will run on several different platforms

Exercise

1. Why do we need to use compilers?

2. Is the bytecode of a Java app different on different platforms?

3. What is a JVM?

Page 16: Java

Java

Page 16 - Copyright © 2012 Walter Milner - all rights reserved

Data

Computer programs deal with data. Here are some examples of data in different contexts:

Word processing - the text of the document, including font name and size and style, colour, spacing.

Images and their psoitions. Page size, margin sizes. Most of this data is made of strings (sequences of

characters) but some is numeric - like the size of margins. The data is in memory when the document

is being edited, and otherwise placed in a file, usually stored on disc.

Email - the text of messages, the email addresses of contacts, dates and times of messages.

Graphics programs - an image can be represented in different ways, but the most common is to have

a rectangle made of rows and columns of pixels. Each pixel will have three numbers representing the

red, green and blue parts of the colour at that point. There might be a fourth number for how

transparent the pixel is.

Browser - this handles a web page, which is a piece of text representing the page in HTML. The

browser has to render the html and present a visual version of it.

Summary

programs handle data

data is held in memory or in a file

data is input (from a keyboard, mouse, a file, a network connection etc) and output (to a

screen, a printer, a file etc).

Page 17: Java

Java

Page 17 - Copyright © 2012 Walter Milner - all rights reserved

Data types

In general data comes in different types - numbers, text and so on.

In a programming language, the idea of data type is very important.

In Java there are two kinds of types:

Reference types. These are about objects. More on objects and references later

Primitive types. These are single values. This section is about primitive types.

An example of a primitive type is an int. This is short for integer - a whole number. The int type

represents a positive or negative whole number. An int is held in 32 binary digits, bits, which is 4

bytes, of memory. This means there is a minimum value - about -2 billion - and a maximum, of +2

billion. The numbers are held using a method called two's complement (see bit-wise operations).

Integer arithmetic is completely accurate.

Sometimes this range is not enough - or sometimes it is too much, so other types of whole number

are available. Here is the complete set:

Name Memory usage

(bytes) Minimum value Maximum

byte 1 -128 127 short 2 -32,768 32,767 int 4 -2,147,483,64 2,147,483,63 long 8 -9,223,372,036,854,775,808 9,223,372,036,854,775,807

Often we need numbers with decimal parts - what mathematicians would call rational numbers. In

computing these are called floating point numbers. Two versions are available - float (in 4 bytes) and

double (in 8 bytes). Floating point arithmetic is slower than using integers, and in general it is not

completely accurate. This is because many numbers cannot be represented as a finite sequence of

bits, in base 2.

In addition to numbers , there are two other primitive types.

boolean data has just two possible values - true and false. boolean data is used for logic.

char represents a character. Java uses the Unicode character set, which uses 2 bytes = 16 bits to

represent each character.

Summary

Java operates with several different data types

Exercise

1. How do you decide whether to use a byte, short, int or long?

2. What is the difference between a double and an int?

3. Some programing languages use ASCII. Why does Java use Unicode?

Page 18: Java

Java

Page 18 - Copyright © 2012 Walter Milner - all rights reserved

Variables

Java programs handle data by using variables. Here is a program fragment which is pretty easy to see

what it does:

int x; int y; int z; x = 2; y = 3; z = x+y;

Clearly the program adds 2 and 3. In more detail:

The program uses three variables, named x y and z. The variables have data type int. The program

starts by declaring these variables:

int x; int y; int z;

Variables must be declared like this, before they are used. The declaration tells the compiler what

memory it needs to allocate for this data, how they will be referred to (their names) and what data

type they are.

The three lines are three statements. These are declaration statements. All statements must end in a

semi-colon ; if you miss that out, the compiler will give you an error message.

You can put statements on the same line:

int x; int y; int z;

but this makes things harder to read - don't do it.

You can declare variables of the same type together, like

int x,y,z;

The program then has three assignment statements:

x = 2; y = 3; z = x+y;

An assignment statement assigns a value to a variable. The first statement gives x the value 2. The 2

and the 3 are literal constants. These are of type int - if you want type long, say for example 2L.

The third assignment is different. 'x+y' is an expression. The compiler sets up code so that the values

of x and y will be added, and the resulting value of the expression will be assigned to z.

Note that the calculation takes place at run-time, not compile-time. We can see that obviously z will

be 5 - but the compiler does not actually work that out. It produces code which will do the addition,

when the program runs.

A variable has three attributes - a name, a type, and a value. Once declared, we cannot change its

name or its type, only its value. There is a fourth attribute, namely the address in memory where it is

Page 19: Java

Java

Page 19 - Copyright © 2012 Walter Milner - all rights reserved

held, but we cannot get or refer to that in Java - we do not need to. Also, this is an address in the

JVM, not the physical machine.

Summary

Changing data items in a program are called variables

Variables have type

Variables must be declared before use

Variables can have values assigned to them

Variables are held in memory

Exercise

1. Variables must be …………….. before use?

2. What is a 'literal constant'? Give an example.

3. Give an example of an 'expression'.

Page 20: Java

Java

Page 20 - Copyright © 2012 Walter Milner - all rights reserved

Input and Output

To start with we will look at output, to the 'console' - so this is just output of characters, not

graphics.

This is done with a statement like

System.out.println("A B C D E");

This outputs everything in the string enclosed by the double quotes, including the spaces. If we want

to output a number, we can say it like

int x; x=4; System.out.println(x);

We can output a string and a number like

System.out.println("The value of x is "+x);

Note the string is joined to the variable by a +. Or two values:

System.out.println("x = "+x+" and y = "+y);

println goes on to a new line after it has finished, but print stays on the same line. For example

System.out.print("A"); System.out.print("B"); System.out.print("C");

would output

ABC

all on the same line.

Input

We can have assignments like

x=3;

which give variables constant values, known at compile-time. But we usually need to enable our

programs to input data values at run-time. Wordprocessing, for example, means the user inputs data

(text) when the wordprocessor software is running. This is what we mean by input.

Keyboard input can be done using a class called Scanner. For example:

java.util.Scanner scanner = new java.util.Scanner(System.in); int x, y, z; x = scanner.nextInt(); y = scanner.nextInt(); z = x + y; System.out.println(z);

We will improve this program in three steps:

Comments

Page 21: Java

Java

Page 21 - Copyright © 2012 Walter Milner - all rights reserved

A comment is some text which will be ignored by the compiler. Comments are used to say who

wrote the program, when, why, what its supposed to do, and to explain obscure parts of code.

There are two ways of having comments in Java. One is to start with /* and end with */. This can

cover several lines. The other is a line comment, which starts // and goes to the end of the line. For

example

/* A program to input 2 numbers and output the sum */ // create the keyboard input scanner java.util.Scanner scanner = new java.util.Scanner(System.in); int x, y, z; // input 2 ints x = scanner.nextInt(); y = scanner.nextInt(); z = x + y; // calculate sum System.out.println(z); // output result

Import

The class Scanner is located in the package (group of classes) called java.util. Its fully-qualified name

is java.util.Scanner. This tells the compiler where to find Scanner, and distinguishes it from any class

also called Scanner in other packages. But its a lot of typing. Provided we say

import java.util.Scanner;

then we can just say

Scanner scanner = new Scanner(System.in);

so the whole thing is

import java.util.Scanner; /* input 2 numbers and output the sum */ class Test { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int x, y, z; x = scanner.nextInt(); y = scanner.nextInt(); z = x + y; System.out.println(z); } }

IDEs typically generate import statements for you - in NetBeans, right-click and choose Fix Imports.

Program listings here will usually omit import statements.

User prompts

A user prompt is some output to tell the user what to do. For example:

Page 22: Java

Java

Page 22 - Copyright © 2012 Walter Milner - all rights reserved

Scanner scanner = new Scanner(System.in); int x, y, z; System.out.println("Enter a number, then Enter"); x = scanner.nextInt(); System.out.println("Now another"); y = scanner.nextInt(); z = x + y; System.out.println(z);

which produces, for example Enter a number, then Enter 3 Now another 4 7 Summary

As a program runs, data values can be input from the keyboard and other sources Results can be output to the screen or elsewhere.

Exercise

1. Change the program so it subtracts the two values.

2. Change the program so it inputs and adds three values.

3. What is the difference between println and print?

4. Give three reasons for using a comment.

Page 23: Java

Java

Page 23 - Copyright © 2012 Walter Milner - all rights reserved

Statements

A statement is an important part of Java code.

Previously we have seen three types of statement. The first is a declaration statement, like

int x;

The second is an assignment statement, like

z=x+y;

The third is a method invocation:

System.out.println("Hello");

There are several other types of statements which we will meet.

In Java one statement is usually written on one line. It does not have to be, but code is easier to read

if it is. The important point is that a statement ends with a ; semi-colon.

Page 24: Java

Java

Page 24 - Copyright © 2012 Walter Milner - all rights reserved

The Three Frames of Programming

When writing a program, or reading someone else's, there are three mental frames you need to

think about. In other words, there are three areas you must pay attention to:

Program text

Changing variable values

Input/output

The first one, program text, is obviously important - its what the program is.

The second means tracking how variable values change, as the code executes step by step. This is

needed because when an early program step changes a variable value, this will in general affect

what later program steps do. Some people think this is obvious, but some do not.

We will return to input/output later.

For example: ( * means multiply)

int x; int y; x=3; y=2*x; x=x+1; y=y*x; System.out.println(y);

What will this program do?

We could guess, or try to work it out in our heads. An

easier and more reliable way is to trace it - track what

will happen step by step, in the program code and in

memory.

In the table alongside, on the left we see what values

we have in memory, after each step. On the right, we

see the program text. The step which has just executed

in shown in yellow. We have to be careful – are we

looking at memory before it has executed, or after? In

this table we see the memory contents after that step.

Look at this table very carefully. Make sure you

understand everything it shows.

We will use this technique of tracing to see what more

complex program structures do. With experience you

will be able to think about how program text and

memory affect each other with ease.

Variable exchange

As an example - how can we exchange the values of two variables? Suppose the variables are x and

y, and initially x is 1 and y is 2. After the swap, x should be 2 and y 1.

Memory Program text

int x; int y; x=3; y=2*x; x=x+1; y=y*x;

int x; int y; x=3; y=2*x; x=x+1; y=y*x;

int x; int y; x=3; y=2*x; x=x+1; y=y*x;

int x; int y; x=3; y=2*x; x=x+1; y=y*x;

Page 25: Java

Java

Page 25 - Copyright © 2012 Walter Milner - all rights reserved

The obvious way to do this is with two statements:

x=y; y=x;

Suppose we trace this:

Values in memory Program step

Effect

x 1

y 2

Initial state

x 2

y 2

x=y; y=x;

The value from y (2) has been written into cell x, over-

writing the previous 1

x 2

y 2

x=y; y=x;

The value from x (now 2) is written into y - which was 2

anyway.

The problem is that the first x=y over-writes the initial value of x, which is lost and cannot be placed

in y. How can we fix this?

The usual solution is to use an extra location, as a temporary store. One initial value is copied there,

the other initial value written into the first, and then the copy written into the second. In other

words:

temp=x; x=y; y=temp;

We trace this to check:

Values in memory Program step

Effect

x 1

y 2

temp ?

Initial state

x 1

y 2

temp 1

temp=x; x=y;

y=temp;

We've made a temporary copy of x

x 2

y 2

temp 1

temp=x; x=y;

y=temp; Write the value of y into x

Page 26: Java

Java

Page 26 - Copyright © 2012 Walter Milner - all rights reserved

Exercise

Suppose we have three variables, x,y and z, and we need to 'shuffle' their values : x->y, y->z, z->x. So

if to start with x=1, y=2 and z=3, afterwards x=3, y=1, z=2.

How would you program this?

Try it and test it works.

x 2

y 1

temp 1

temp=x; x=y;

y=temp;

Write the initial value of x, from temp, into y

Page 27: Java

Java

Page 27 - Copyright © 2012 Walter Milner - all rights reserved

Expressions

Something like 4-3 is an expression. In an assignment statement, we say something like

x = <an expression >;

We use – for subtraction, * for multiplication and / for division. So examples of expressions are

4 * 3

12-3

12 / 4

For example

y = 20/5;

makes the value of y to be 4.

% is the modulo operator, or remainder

so 10%3 is 1, because 10 divided by 3 gives remainder 1

17%5 is 2

10%5 is 0

% 10 is useful for getting the separate digits of a number. For example

int x= 12345;

x%10 is 5

What about

2+3*4 ?

Will it do the addition first (so it gets 20) or the multiplication first, so it gets 14? The answer is that it

works the same as normal mathematics, which means it will do multiplication and division first, then

addition and subtraction. So

4+5*2 is 14, not 18.

Also as in normal maths we can use brackets – operations in brackets are done first. So

(4 + 5) * 2 = 9 * 2 = 18

Note if we are using ints, division works using a whole number result, and remainders are discarded.

So for example

13/3 is 4

Page 28: Java

Java

Page 28 - Copyright © 2012 Walter Milner - all rights reserved

12/3 is 4

15/3 is 5

16/3 is 5

Exercise

Evaluate the following expressions. The first two are done for you. Check your answers with little

Java programs.

2+3 = 5

2-3 = -1

2*3

6/3

7/3

0/3

2+3*4

2*3+4

3-3/4

(3 * 3)/4

(3-3)/4

(5-1)*(10-1)

Expressions with floating point numbers are similar, except that floating point division is used - so

7.0/2.0 is 3.5

Take care. 7 is an int, 7.0 is a double. So while 7.0/2.0 = 3.5, 7/2=3.

We cannot do arithmetic with boolean types, but we can do logic. We use ! for not, && for AND and

|| for OR. Google logical AND OR and NOT. For example:

boolean a=true;

boolean b=false;

then !a is false. a || b is true. a&&b is false. See the later section on conditional statements.

Page 29: Java

Java

Page 29 - Copyright © 2012 Walter Milner - all rights reserved

Increment decrement and short-cut

Increment operator

For ints, we often want to increase them by 1, and there is an operator to do this:

int x=27; x++;

makes x be 28.

In fact there are two versions of this - post-increment (x++) and pre-increment (++x). In post-

increment, the variable is first used, then incremented. For pre-increment, it is first incremented

then used. For example

int x=1; int y; y = x++;

makes y be 1, and then changes x to 2. But

int x=1; int y; y = ++x;

first increases x to 2, then makes y be 2 also.

You can also say x-- or --x

Short-cut operators

Suppose you want to increase x by 2. You cannot say x+++. You could say x++ twice, or you could say

x = x+2;

But the usual way is

x += 2;

Similarly

x -= 3; // same as x = x - 3; x *= 4; // same as x = x * 4; x /= 2; // same as x = x / 2;

and for a boolean type

boolean b = true; b != b; // same as b = !b; so now b is false

Exercise

Suppose x and y are ints, and x=2 and y=3. After

x *= y++;

How big are x and y now? Write a little program to check.

Page 30: Java

Java

Page 30 - Copyright © 2012 Walter Milner - all rights reserved

Conditional Statements

As well as arithmetic, input and output, there are only two other basic features a program can have:

1. Comparing values and doing different actions for different data

2. Repeating actions

This section is about the first of these.

Suppose we need a program which will input a number, and then output a warning message if it is

greater than 100.

That description uses the word if – and we can write it using an if statement

Scanner scanner = new Scanner(System.in); double number; System.out.println(“Enter a number”); number = scanner.nextDouble(); if (number > 100.0) System.out.println("Too big");

Try this. Run it twice – firstly entering a number less than 100, then greater than 100.

Exercise

Alter this so you only get a message if the number is greater than 1000.

Syntax

Syntax means grammar rules.

An if statement is like this:

if ( <some condition> ) <what to do if the condition is true>

The <some condition> is an expression which evaluates to true or false. If it is true, the statements in

the curly brackets are executed. If it is not, nothing happens and we just move on to what comes

next.

Example

Suppose we want a program which gives a discount of 10% if the purchase is over £100:

Scanner scanner = new Scanner(System.in); double purchase; double discount; System.out.println("Enter purchase "); purchase=scanner.nextDouble(); discount=0.0; if (purchase>100) discount=purchase*0.10; purchase=purchase-discount; System.out.println("After discount this is £"+purchase);

This sets the discount to zero before the ‘if’. This means if the purchase is not over 100, the discount

is zero, but if it is, it is 10%.

Exercise

Try this out.

Page 31: Java

Java

Page 31 - Copyright © 2012 Walter Milner - all rights reserved

Change it so you get a 20% discount.

Tracing an if

Tracing a program fragment might help to understand ifs. For example:

int x; int y; Scanner myScanner = new Scanner(System.in); x=myScanner.nextInt(); y=1; if (x>10) y=2; System.out.println(y)

Suppose the user inputs 12:

Memory Program Comment

x ?

y ?

int x; int y; Scanner myScanner = new Scanner(System.in); x=myScanner.nextInt(); y=1; if (x>10) y=2; System.out.println(y);

x and y declared

x 12

y ?

int x; int y; Scanner myScanner = new Scanner(System.in); x=myScanner.nextInt(); y=1; if (x>10) y=2; System.out.println(y);

scanner object created (omitted) and 12 input

x 12

y 1

int x; int y; Scanner myScanner = new Scanner(System.in); x=myScanner.nextInt(); y=1; if (x>10) y=2; System.out.println(y);

y becomes 1

x 12

y 2

int x; int y; Scanner myScanner = new Scanner(System.in); x=myScanner.nextInt(); y=1; if (x>10) y=2; System.out.println(y);

x is greater than 10, so y=2; is executed

x 12

y 2

int x; int y; Scanner myScanner = new Scanner(System.in); x=myScanner.nextInt(); y=1;

2 is output

Page 32: Java

Java

Page 32 - Copyright © 2012 Walter Milner - all rights reserved

if (x>10) y=2; System.out.println(y);

Conditional as flowchart

This is another way of looking at ifs, as shown at the side.

ifs, semi-colons and blocks

Do NOT put a semi-colon at the end of an if header - this is WRONG:

if (x>4); y=10;

As a result of Java syntax, this is allowable. So unfortunately the compiler will not

tell you it is wrong - but it is. The ; ends the statement, so the if stops there - and

y=10; is executed either way. In effect it says if x is greater than 4, do nothing.

Then just make y=10.

Often you want to do several things if the condition is true . A block will do this. This is just several

statements enclosed in curly brackets. For example

if (x>4) { y=10; z=2; }

A block does not need a semi-colon after it.

Else

We often want to do something if a condition is true, and something else if it is not. The if..else

structure does this:

if (something) do option one else do option two

For example, suppose we want to accept a number only if it is greater than 10. We want to tell the

user whether it was accepted of not:

.. x=myScanner.nextInt() if (x>10) System.out.println("Accepted"); else System.out.println("Not accepted");

Exercise

Write a program which inputs an integer. If the value inputted is greater than 50, output "Accepted".

Otherwise output the message "Too small".

Page 33: Java

Java

Page 33 - Copyright © 2012 Walter Milner - all rights reserved

Indentation

Indentation means setting code in from the left margin by amounts which show the code structure.

For example:

if (x>100) { .. .. } else { .. .. }

This helps to make things clearer, especially when we come to have ifs inside ifs and loops inside

loops. Many IDE editors will do this for you - right-click and choose Format.

Compound conditions

Suppose we want to require a value to be between 5 and 10. One way to do this would be to first

check if it was more than 5, then less than 10, with two ifs:

if (x>5) if(x<10) System.out.println("OK");

In this structure, the statement inside the first if is itself an if. This is OK - an if can contain any type

of statement.

But we can do the two tests together, like this:

if (x>5 && x<10) System.out.println("OK");

The && means 'and' - so it reads if x is greater than 5 and x is less than 10..

The following is WRONG:

if (x>5 && <10) System.out.println("OK");

You can say 'x is greater than 5 and less than 10' in English, but not in Java.

The symbol for 'or' is ||. So

if (x<5 || x<10) System.out.println("OK");

says OK if x is less than 5 or greater than 10.

Equality and assignment

To test if two values are equal, use ==

if (x==5) System.out.println("OK");

This says OK if x is 5, and nothing else.

This is WRONG:

Page 34: Java

Java

Page 34 - Copyright © 2012 Walter Milner - all rights reserved

if (x=5) System.out.println("OK");

x=5 is an assignment - it tells the system to make x 5. It should be x==5, which asks whether x is 5.

The symbol ! means NOT, so != mans not equal to:

if (x!=5) System.out.println("OK");

accepts anything except 5.

You need to be careful with edge values. For example

if (!(x > 10)) System.out.println("OK");

means 'if x is not greater than 10'. So it accepts 10, or less.

Exercise

Write a program which accepts numbers up to 5 inclusive, and over 9, outputting 'OK', and

outputting 'Out of range' otherwise.

Page 35: Java

Java

Page 35 - Copyright © 2012 Walter Milner - all rights reserved

Algorithms

Suppose we need some code to input two integers, and then outputs them in order of size, largest

first. So input 26, 20 outputs 26 20. Input 3,4 outputs 4,3:

import java.util.Scanner; public class Main { public static void main(String[] args) { int x; int y; Scanner myScanner = new Scanner(System.in); x = myScanner.nextInt(); y = myScanner.nextInt(); if (x > y) { System.out.println(x + " " + y); } else { System.out.println(y + " " + x); } } }

This is easy - we compare x and y, and if x is bigger, output x then y, otherwise y then x.

This is a simple algorithm.

An algorithm is a method or recipe or solution to a problem, as a series of simple logical steps. A

program is an implementation of an algorithm in a particular language.

For clever programming, finding the correct algorithm is more significant that actually writing the

program. Fortunately optimal algorithms for many standard tasks have been invented, and

sometimes even coded into languages.

Not so easy..

Suppose we need to input three numbers and output them in order, biggest first. How would you do

that? Before you read on, decide what algorithm you would use, and program it.

One algorithm would be

1. Find the biggest, and output it.

2. Find the middle and output it.

3. Find the smallest, and output it.

Finding the middle one is not easy. If the numbers are x y z, then x is the middle if the order is

y x z or z x y.

so we need to test if y is greater than x and x is greater than z, or z is greater than x and x is greater

than y.

Similarly for y or z is the middle one.

Here it is:

Page 36: Java

Java

Page 36 - Copyright © 2012 Walter Milner - all rights reserved

int x, y, z; Scanner myScanner = new Scanner(System.in); x = myScanner.nextInt(); y = myScanner.nextInt(); z = myScanner.nextInt(); // find biggest if (x > y && x > z) { System.out.println(x); } if (y > x && y > z) { System.out.println(y); } if (z > x && z > y) { System.out.println(z); } // find middle if ((x > y && x < z) || (x < y && x > z)) { System.out.println(x); } if ((x > y && y > z) || (x < y && y < z)) { System.out.println(y); } if ((z > y && z < x) || (z < y && z > x)) { System.out.println(z); } // find smallest if (x < y && x < z) { System.out.println(x); } if (y < x && y < z) { System.out.println(y); } if (z < x && z < y) { System.out.println(z); }

This is getting tricky. We have included comments like

// find biggest

to help keep track of what we are doing. Try this method.

Is it the best way? It uses 9 comparisons. If we've found the biggest and the middle, we should not

have to find the smallest - which suggests it is not.

An alternative algorithm is to simply test the 6 possibilities, which are

x y z

x z y

y x z

y z x

z x y

z y x

Here we go:

Page 37: Java

Java

Page 37 - Copyright © 2012 Walter Milner - all rights reserved

int x, y, z; Scanner myScanner = new Scanner(System.in); x = myScanner.nextInt(); y = myScanner.nextInt(); z = myScanner.nextInt(); if (x > y && y > z) { System.out.println(x + " " + y + " " + z); } if (x > z && z > y) { System.out.println(x + " " + z + " " + y); } if (y > x && x > z) { System.out.println(y + " " + x + " " + z); } if (y > z && z > x) { System.out.println(y + " " + z + " " + x); } if (z > x && x > y) { System.out.println(z + " " + x + " " + y); } if (z > y && y > x) { System.out.println(z + " " + y + " " + x); }

Exercise

Try this way. Do you think this is more efficient that the first? Could it be further improved?

Was your method more efficient?

What happens if two numbers are equal?

Page 38: Java

Java

Page 38 - Copyright © 2012 Walter Milner - all rights reserved

Loops

Suppose we want to add up the first twelve integers. This does it:

int total=0; total+=1; total+=2; total+=3; total+=4; total+=5; total+=6; total+=7; total+=8; total+=9; total+=10; total+=11; total+=12;

This works, but it's a lot of typing. Suppose we needed to add up the first 12000 integers? This

method would be impractical.

The code above has almost the same statement total+=?; twelve times. What we need is a way to

execute the same statement several times.

We could use the statement total+=n; and change the value of the variable n. This would need to be

1, then 2, then 3, up to 12. Here it is

int total = 0; int n; n = 1; while (n < 13) { total += n; n++; } System.out.println(total);

Study this code carefully. We have a new kind of statement - a while loop.

1. There is a loop header, while (n<13)

2. This is followed by the loop body - a block { } containing two statements: total+=n; and n++;

3. The loop body is repeatedly executed, so long as the condition (n<13) is true.

4. The index n is initialised to be 1.

The loop body is repeated. The first time, n is 1, so the first statement in teh loop body is in effect

total+=1;. The second statement, n++; increase n to be 2.

So on the next repeat, it does total+=2; and n is increased to 3.

On the third repeat it does total+=3;

This will continue up to and including n=12, when it does total+=12; and n increases to 13.

But then the condition to continue, n<13, is no longer true, so the loop terminates.

How could we modify this to add up integers from 1 to 20? Just change the condition:

Page 39: Java

Java

Page 39 - Copyright © 2012 Walter Milner - all rights reserved

int total = 0; int n; n = 1; while (n < 21) { total += n; n++; } System.out.println(total);

Add up the numbers from 10 to 20? Change the initialisation:

int total = 0; int n; n = 10; while (n < 21) { total += n; n++; } System.out.println(total);

Add up the odd numbers from 1 to 1000? We need 1,3,5,7, so we need to start at 1 and go up in

steps of 2:

int total = 0; int n; n = 1; while (n < 1001) { total += n; n+=2; } System.out.println(total);

Display the total as we go along? Have the output inside the loop body:

int total = 0; int n; n = 1; while (n < 1001) { total += n; System.out.println("n = "+n+" total = "+total); n+=2; }

while loops

1. The condition must be in round brackets, like (n<13) 2. The condition can be any boolean expression, such as (n<13 && x!=5) 3. There should be no semi-colon at the end of the loop header 4. If there is just one statement in the loop body, it does not need to be a block - such as while (n<10) n++; 5. You might have an endless loop, such as

while (true) total += n;

In this case, you would need to use the IDE to cancel the process, or use Task Manager in Windows.

do..while loop

The do while loop is very similar. The only difference is that the condition is checked at the end:

Page 40: Java

Java

Page 40 - Copyright © 2012 Walter Milner - all rights reserved

int total=0; int n=1; do{ total+=n; n++; } while (n<10);

In most situations the choice of while or do..while is arbitrary. The only difference is that do..while will execute at least once. In a while, if the condition is false the first time in, the loop body will never be executed.

Exercise

Write a program which adds up the even numbers from 2 to 10 inclusive and outputs the total.

Test that it gives the correct answer

Change it so it adds the even numbers from 2 to 10000.

Programming with loops example

We often need some ingenuity to solve a programming problem with a loop. A key stage is to recognise that a task involves repeating something, so a loop is needed. Suppose we need to separate, and print separately, the digits of a number. So given 1234, it should output 1 2 3 4 We need to do this for each digit - so we are repeating something and need a loop. Do we know how many times to repeat? The number could be 1234 (4 times) or 54321 (5 times) or whatever, so it is not a fixed number of repeats. How to separate the digits? Use integer division by 10, and modulo. For example, if the number is n=1234, then n%10 is 4, the lowest digit, and n/10 is 123. So change n to this, and loop. So we have an outline:

given the number n while.. digit = n%10, and output it n = n/10

When should the loop end? n will get smaller. On the last output, n is less than 10. Then it is zero. So our code is

int n = 1234; while (n > 0) { int digit = n % 10; System.out.println(digit); n /= 10; }

We have declared and assigned the variable digit inside the loop. This is OK. This is not quite right - the output is least significant digit first, when we wanted most sgnificant first. This is easily fixed using an array, which we will meet later.

for loops

The most common loop in Java is the for loop. This has a loop header and body like this:

Page 41: Java

Java

Page 41 - Copyright © 2012 Walter Milner - all rights reserved

for (.........) { // loop body }

Here is an example, to add up the numbers 1 to 5:

int number; int total; total = 0; for (int c = 1; c < 6; c++) { number = c; total = total + number; } System.out.println(total);

The loop header has three parts, separated by semi-colons. It goes

for ( start; loop so long as; change after each repeat )

So in our example, we start with c=1, we repeat so long as c is

less than 6, and after each repetition, it increases c by 1. In other

words, c goes 1 2 3 4 and 5. The loop body is repeated for each

of these. So the first time it says number = 1, then number = 2,

then number = 3, then - you've got it.

Exercise

Modify this program so it adds up the numbers 1 to 1000. Is it correct? If you cannot remember how

to work it out, google 'arithmetic progression'

Note that in the loop start:

int c=1;

we both initialise c to be 1, and declare it. We do not have to declare it here (it could have been

declared with the other variables) but it can be, and often is. If it is, it can only be used in the loop

body ('its scope is restricted to the loop')

Another example

This program outputs 100 down to 0 in steps of 2:

for (int c = 100; c > -1; c=c-2) { System.out.println(c); }

If the loop body has just one statement in it, you do not need the block (the curly braces). As with an

if, a semi-colon at the end of the header is WRONG. This is WRONG

for (x=0; x<100; x++); { .. }

The reason is the same as the if - the semi-colon ends the statement, and cuts off the loop body.

Page 42: Java

Java

Page 42 - Copyright © 2012 Walter Milner - all rights reserved

Exercise

Write loops which will output

1. 0 1 2 3 4 5 6 7 8 9 10

2. 10 8 6 4 2 0

3. 5 4 3 2 1 0 -1 -2 -3 -4 -5

4. Write a loop which will calculate the total of 1+2+3+4+5..., stopping when the total exceeds 100.

5. Write a program which first inputs an integer n, then calculates and outputs 1X2X3X4X..n (which is

called n! or n factorial)

Nested loops

The statements in a loop body can be any type, including loops themselves. Look at the following

program:

for (int c = 1; c < 6; c++) for (int d = 1; d<6; d++) System.out.println(c+" "+d);

What do you think it will output?

Try it - can you explain what it does?

Exercise

1. Write a program which will output the 5 times table, like this

1 X 5 = 5

2 X 5 = 10

3 X 5 = 15

..

12 X 5 = 60

2. Extend this so it outputs all the multiplication tables, one after the other, from the 2 to the 12

times table.

break and continue

These are two new types of statements which can be used in loops (and conditionals). You use continue; part way through a loop body. It misses out the rest of the loop body, and repeats. You would usually use it with an if, like

while(...) { .. if (..) continue; .. this is missed out if the if was true }

break is similar, but it breaks out of the loop completely. So you might say:

while (true) { .... if (..) break; // ends the loop totally .. }

You can break out of a loop, but not out of an if. This was a famous bug which crashed AT&T in 1990.

Page 43: Java

Java

Page 43 - Copyright © 2012 Walter Milner - all rights reserved

Testing

Beware of bugs in the above code; I have only proved it correct, not tried it.

- Donald E. Knuth

Testing means checking a program works by trying to run it.

You should write program code in small sections, and test each small section before you write more.

Testing is a major aspect of software engineering. In Java, the JUnit framework is a formal way of

testing code. Since testing may take a long time, the process is sometimes automated.

However the beginner programmer needs to test code in an informal manner. To test, you need to

know what the output should be - otherwise you cannot tell if it works. For example, we might have

some code to convert Centigrade temperaturs to Fahrenheit:

int centi = 17; int fahr = centi*9/5 + 32; System.out.println(fahr);

If we run this, it outputs 62. However that does not help unless we know what the correct answer is.

In fact it is 62.6. Why is our code wrong? The correct answer is not an int, but we have used that as

the type. The correction is simple:

double centi = 17; double fahr = centi*9/5 + 32; System.out.println(fahr);

Sometimes thought is needed to work out how to test something - a testing strategy. For example,

you might be working on code to write data into a file, and read it back. You might write both the

writing and reading code at the same time. How to test it? If it does not work, is the writing wrong,

or the reading? The solution is to look at the file directly, say in a text editor. If it is wrong, the

writing code has the error. If it is correct, the reading code is wrong.

Page 44: Java

Java

Page 44 - Copyright © 2012 Walter Milner - all rights reserved

Data Structures

In previous sections we have used data as single items. There are many situations where we need to

use many items of data in an organised structure. Some examples are

The color of the pixels in a line on a graphic image

The colour of the pixels in a rectangle

The set of exam marks for the students in a class

The transactions on a bank account

The frames of a video clip

The items in a data structure are called elements or nodes.

Data structures

Some standard ways of arranging data are

Linear list - data elements are

next to each other

Linked list - elements are linked

by pointers. They are not next to

each other in memory

Binary tree - each element is

linked to two others, except for

leaf nodes

Queue - elements join at one end

and leave at the other

Stack - elements join and leave at

the top

Data structures and algorithms

We need to be able to add new elements to the data structure, delete them, find one, and go

through everything in the structure - traverse it. How that is done - the algorithm - will depend on

which data structure it is. Some algorithms and data structures will use more memory and be faster

than others. The study of algorithms and data structures is central to classic Computer Science.

Page 45: Java

Java

Page 45 - Copyright © 2012 Walter Milner - all rights reserved

Data Structures and Languages

There are two different ways of looking at this -

In the abstract, using diagrams like those above

Concrete implementations of these structures in a programming language. The structures

might be 'built-in' to the language, or it might be possible for the programmer to write their

own implementations

Both ways have their advantages. The abstract language-independent approach lets us focus on the

structure itself. A concrete implementation lets us use these theoretical ideas in reality.

Data Structures in Java

The Java language allows the programmer to implement most of these ideas. The standard classes

include the 'container' classes which already provide implementations of many of them, and

'generics' offer algorithms to use them. The only thing Java does not allow is direct access to

memory through actual numeric addresses - because this is a common source of bugs.

We will look in this section at one structure - the array.

Arrays

Imagine a street of houses. Each house has a distinct house number. Each house contains different

things.

We can think of an array like this. It is a set of boxes, or elements. Each element has a different

index, which is like the house number, except that Java arrays start at 0 rather than 1. Each element

contains some data. This could be any type, such as integers, doubles, objects or whatever - but they

have to be the same type. We can get to any element through its index - to read the data out of the

element, or to change it.

Streets have street names, and arrays also have names. In a Java program arrays are variables, and

like all variables we have to declare them before use. For example:

int[] myArray = new int[5];

This declares myArray to be the type 'array of ints', and it constructs an array with five elements -

indexed 0 to 4. Java arrays are indexed using [ square brackets ].

We can put values into the array to match the picture above using:

Page 46: Java

Java

Page 46 - Copyright © 2012 Walter Milner - all rights reserved

myArray[0]=48; myArray[1]=72; myArray[2]=31; myArray[3]=99; myArray[4]=43;

Note the array index goes from 0 to 4.

We could output the values from the array like this:

System.out.println(myArray[0]); System.out.println(myArray[1]); System.out.println(myArray[2]); System.out.println(myArray[3]); System.out.println(myArray[4]);

Arrays and loops

The last two fragments show program code with very similar statements repeated. These are

situations where loops are appropriate. For example we can output the array with:

for (int i=0; i<5; i++) System.out.println(myArray[i]);

Trace through this:

Execution Value of i Action

for (int i=0; i<5; i++) System.out.println(myArray[i]);

i=0 Initialise i to 0

for (int i=0; i<5; i++) System.out.println(myArray[i]);

i=0 Output myArray[0]

for (int i=0; i<5; i++) System.out.println(myArray[i]);

i=1 Increment i, continue

for (int i=0; i<5; i++) System.out.println(myArray[i]);

i=1 Output myArray[1]

for (int i=0; i<5; i++) System.out.println(myArray[i]);

i=2 Increment i, continue

for (int i=0; i<5; i++) System.out.println(myArray[i]);

i=2 Output myArray[2]

for (int i=0; i<5; i++) System.out.println(myArray[i]);

i=3 Increment i, continue

for (int i=0; i<5; i++) System.out.println(myArray[i]);

i=3 Output myArray[3]

for (int i=0; i<5; i++) System.out.println(myArray[i]);

i=4 Increment i, continue

for (int i=0; i<5; i++) System.out.println(myArray[i]);

i=4 Output myArray[4]

for (int i=0; i<5; i++) System.out.println(myArray[i]);

i=5 Increment i, stop

Exercise

Run this program

Alter it so it outputs the array in reverse sequence. The index will need to start at 4 and stop after 0.

Page 47: Java

Java

Page 47 - Copyright © 2012 Walter Milner - all rights reserved

Random numbers

How do we get numbers to put in the array? In real programs they come from pixels read in from a

jpeg or similar. For our study programs, we could input values from the keyboard using a Scanner,

but this is tedious and for an array with a 1000 elements, impractical. A good alternative is to use

numbers generated at random by the computer.

The class Math has a method called random which produces a number in the range 0 to 1 - a double

type with decimal parts. This is called Math.random().

If we multiply it by say 1000.0, we will have a random number in the range 0 to 1000. This is

Math.random()*1000.0

We can change this to a whole number by 'casting' it to an int. This is done by

(int)(Math.random()*1000.0).

Putting this in a loop, we have

for (int i=0; i<5; i++) myArray[i]=(int) (Math.random()*1000.0);

Exercise

Follow this with the loop for outputting the array. Run the program several times. Do you get the

same random values each time?

Summing an array

We can add up all the values in an array by using the following simple algorithm

initialise a running total to 0 for each value in the array, add the value into the running total

After this, the running total will be the sum of all the elements.

For example:

int[] myArray = new int[5000]; // fill array with numbers for (int i=0; i<5000; i++) myArray[i]=(int) (Math.random()*1000.0); // find total int total=0; for (int i=0; i<5000; i++) total+=myArray[i]; // output total System.out.println("Total = "+total);

Exercise

Modify this so it outputs the average as well as the total.

Magic numbers

Magic numbers are numbers which appear in code, and do not have immediately obvious meanings.

For example in the loop header:

Page 48: Java

Java

Page 48 - Copyright © 2012 Walter Milner - all rights reserved

for (int i=0; i<5000; i++)

the 5000 is a magic number. Why 5000? We know it is because the array has been declared to have

5000 elements, but in a long and complex program we might have forgotten this. Or (more likely)

your program is being read by another programmer who has the task of maintaining your code. Do

them a favour, help them out and make the code self-evident:

final int ARRAY_LENGTH = 5000; int[] myArray = new int[ARRAY_LENGTH]; // fill array with numbers for (int i=0; i<ARRAY_LENGTH; i++) myArray[i]=(int) (Math.random()*1000.0); // find total int total=0; for (int i=0; i<ARRAY_LENGTH; i++) total+=myArray[i]; // output total System.out.println("Total = "+total);

ARRAY_LENGTH is in capitals because this is the convention for constant values. Just by looking at it

we know it is supposed to be a constant.

It is declared to be a final int. This forces it to be constant - it can only be given a value in its

initialisation. If code further on changes it, it will not compile. This is an example of using a language

feature to make bug-free programming easier. The compiler will tell us if we go wrong.

If for some reason we decide the array length should be different, we just have to change one line of

code, where ARRAY_LENGTH is initialised. Otherwise we would have had to have searched for every

occurrence of 5000, check if it was appropriate, and change it if it was.

Finding extreme values

For example, how could we find the largest number in the array? And its location?

Here is an algorithm, using the idea of 'the biggest so far'.

Set biggestSoFar to be the first element Set location to be the first For each subsequent element: If this element is bigger than the biggestSoFar, Change biggestSoFar to be this element Change location to be this location

At the end, biggestSoFar will be the biggest in the whole array.

Here is an implementation of this in Java:

Page 49: Java

Java

Page 49 - Copyright © 2012 Walter Milner - all rights reserved

final int ARRAY_LENGTH = 5000; int[] myArray = new int[ARRAY_LENGTH]; // fill array with numbers for (int i=0; i<ARRAY_LENGTH; i++) myArray[i]=(int) (Math.random()*1000000.0); // find maximum int biggestSoFar=myArray[0]; int location = 0; for (int i=1; i<ARRAY_LENGTH; i++) if (myArray[i]>biggestSoFar) { biggestSoFar=myArray[i]; location=i; } // output result System.out.println("Largest is = "+biggestSoFar); System.out.println("Located at = "+location);

The range has been changed to 0 to 1 million - otherwise the maximum is almost always 999.

Exercise

Make sure you understand every line in the above program.

Change it so it finds the smallest value.

How can you test this program?

Sorting

In computing, 'sort' means to arrange data in order.

In normal life, sorting means separating things out into different types. The reason why sort came to

mean ordering is a curious historical tale involving Herman Hollerith (the founder of IBM), the US

Census of 1901, and a method now called a radix sort. Google it for the details.

How could we re-arrange the numbers in our array into decreasing order, biggest first? Invent a

method.

One way would be to find the biggest (which we can already do) and swap it into first place. Then

find the second biggest, and swap it into second place. Then the third, and so on.

Our current find biggest starts at 0. Introduce another variable for where it starts:

// find maximum, from start int start=0; int biggestSoFar=myArray[start]; int location = start; for (int i=start+1; i<ARRAY_LENGTH; i++) if (myArray[i]>biggestSoFar) { biggestSoFar=myArray[i]; location=i; }

Then exchange the biggest value with the one at the start. Remember the variable exchange trick we

saw before:

//swap values at start and location of max int temp=myArray[start]; myArray[start]=myArray[location]; myArray[location]=temp;

Now we need to do this first with start as 0, then 1, then 2, and finally at one from the end.

In other words we need to enclose this in a loop:

Page 50: Java

Java

Page 50 - Copyright © 2012 Walter Milner - all rights reserved

for (int start=0; start<ARRAY_LENGTH-1; start++) { .. }

After we've sorted it, we want to output the array in a loop. Here's the whole thing:

final int ARRAY_LENGTH = 5000; int[] myArray = new int[ARRAY_LENGTH]; // fill array with numbers for (int i = 0; i < ARRAY_LENGTH; i++) { myArray[i] = (int) (Math.random() * 1000000.0); } // sort begins for (int start = 0; start < ARRAY_LENGTH - 1; start++) { // find maximum, from start int biggestSoFar = myArray[start]; int location = start; for (int i = start + 1; i < ARRAY_LENGTH; i++) { if (myArray[i] > biggestSoFar) { biggestSoFar = myArray[i]; location = i; } } //swap values at start and location of max int temp = myArray[start]; myArray[start] = myArray[location]; myArray[location] = temp; } // output array for (int i = 0; i < ARRAY_LENGTH; i++) { System.out.println(myArray[i]); } }

How many steps are involved in this method? To find the biggest we go through the whole array,

5000 steps. We have to do this 4999 times - about 5000. As we do this we don't have to do as many

steps - it goes from all to none, so averages half, or 2500. So the total steps is approximately 1/2

5000 X 5000, or around 12 million.

Exercise

Before you run it, roughly how long do you think it will take to sort 5000 numbers? That's 12 million

steps.

Copy and run this program.

Change the array length. Try a very small number - say 10. How long does it take? Try a bigger array -

say 100 000. That will be 5 billion steps. This is not an exceptionally large array - an image with a

resolution of 1000 by 1000 pixels has one million elements.

This method is a type of exchange sort. It is simple but slow.

Exercise

Think of a faster way. To get some ideas, google 'sorting algorithms'. Don't go mad. Find one you can

understand, and implement it in Java.

Page 51: Java

Java

Page 51 - Copyright © 2012 Walter Milner - all rights reserved

Bitwise operations

All computer data is represented by strings of bits. Java has some operators which work at the bit

level, and their use can provide some insight into how data is stored.

Shift and masks

The >> operator shifts the bits in a number to the right - shifting 0s in on the left. So x>>1 shifts the

bits in x one place right, and puts a 0 at the front.

The & operator forms a bitwise AND mask. For example, what is 12 & 3 ? In base 2, 12 is 1010, and 3

is 0011, so

1010

0011 AND

----

0010 = 2

We are taking pairs of bits and forming the logical AND. 1 AND 0 is 0, 0 AND 0 is 0, 1 AND 1 is 1 and

so on.

& is the bitwise AND, while && is the logical AND eg if (x>7 && y<3)...

& masks are usually used to isolate certain bits from a pattern. For example, a mask with 1 gets the

right-hand least significant bit only. For example 15&1 is

1111 (15)

0001 AND

----

0001 (lsb of 15)

But 8&1 is

1000 (8)

0001 AND

----

0000 (lsb of 8)

| is the corresponding OR bitwise mask.

The bit shift and mask gives us a way of outputting a number as a binary string:

Page 52: Java

Java

Page 52 - Copyright © 2012 Walter Milner - all rights reserved

// this code outputs the int b in binary int[] result = new int[32]; // to hold the result for (int n = 0; n < 32; n++) { // or each bit result[n] = b & 1; // get and store lsb b = b>>1; // shift right } int spacer = 0; // count places for (int n = 31; n != -1; n--) { // msb first System.out.print(result[n]); // output bit spacer++; if (spacer == 4) { // space every 4 bits System.out.print(" "); spacer = 0; } } System.out.println(); // new line at end

then for example

b=18 outputs 0000 0000 0000 0000 0000 0000 0001 0010

We can also use this to show the effects of the shift:

b=1234 0000 0000 0000 0000 0000 0100 1101 0010 1234>>1 0000 0000 0000 0000 0000 0010 0110 1001 1234>>2 0000 0000 0000 0000 0000 0001 0011 0100 1234>>3 0000 0000 0000 0000 0000 0000 1001 1010 1234>>4 0000 0000 0000 0000 0000 0000 0100 1101 and the & mask:

b=58 0000 0000 0000 0000 0000 0000 0011 1010 58 & 0B1111 0000 0000 0000 0000 0000 0000 0000 1010 This also shows how we can write a number in base 2 in Java code.

Negative numbers

Look at this:

b=3 0000 0000 0000 0000 0000 0000 0000 0011 2 0000 0000 0000 0000 0000 0000 0000 0010 1 0000 0000 0000 0000 0000 0000 0000 0001 0 0000 0000 0000 0000 0000 0000 0000 0000 -1 1111 1111 1111 1111 1111 1111 1111 1111 -2 1111 1111 1111 1111 1111 1111 1111 1110 -3 1111 1111 1111 1111 1111 1111 1111 1101

Positive numbers are stored in their binary form. Negative numbes are stored (in Java) in something

called 2's complement. This is formed in 2 steps - change all the 1s to 0s and vice versa, then add 1.

For example

+3 = 0000 0011

1111 1100 (step 1)

+1 (step 2)

1111 1101 ( -3 in 2's complement).

Page 53: Java

Java

Page 53 - Copyright © 2012 Walter Milner - all rights reserved

Inversion

~ switches 1s to 0s and vice versa.

Left shift

<< is left shift.

For example

123456 0000 0000 0000 0001 1110 0010 0100 0000 ~123456 1111 1111 1111 1110 0001 1101 1011 1111 123456 << 3 0000 0000 0000 1111 0001 0010 0000 0000

Exercise

Use the code in this section to display a value in binary, to show the binary form of 123456, and the

effects of & masks, | masks, inversion and left shift

Page 54: Java

Java

Page 54 - Copyright © 2012 Walter Milner - all rights reserved

Using a Debugger

As soon as we started programming, we found to our surprise that it wasn't as easy to get programs right as

we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large

part of my life from then on was going to be spent in finding mistakes in my own programs.

— Maurice Wilkes discovers debugging, 1949

This is about using a debugger - a piece of software which provides features to help debug code.

We will show this in NetBeans - other debuggers have similar features.

Suppose our code is:

int[] data = new int[100]; for (int i = 0; i < data.length; i++) { data[i] = 5; } int total = 0; for (int i = 1; i < data.length; i++) { total += data[i]; } System.out.println(total);

So we are filling an array of 100 ints with the value 5, then adding them up, and getting the answer

495 not 500. Why?

The best approach is to read the code carefully - the bug is fairly obvious. But let's pretend we can't

see it, and follow it through in a debugger.

Debugger features

A debugger offers the facility to execute single steps of code and observe the values of 'watch'

variables after each step. In more detail:

1. Step over - this means execute a single step of code. If it is a method invocation, we step

over the method and carry out. For example, if it is System.out.println, we do not want to go

thorugh all the steps in println, since that would take a long time, and we know it is error-

free

2. Step into - trace into a method - opposite of step over

3. Step out - finish this method invocation trace immediately

4. Run to cursor. We might start with a thousand lines of code which we know are OK. We do

not want to have to step through all of those. So place the cursor on the first suspect line,

and run at full speed to this point.

5. Add watch. Choose another variable - or expression - to display the value of.

6. Set breakpoint. A place in code where execution should pause, if some condition is true.

Page 55: Java

Java

Page 55 - Copyright © 2012 Walter Milner - all rights reserved

Using a debugger

Go Debug.. Debug Main project, then

Run to cursor. We have run over the initial loop, and we are about to execute total=0

Watch variables there. The array has been initialised as we expected

F8 step over. total is now 0. We are about to start the second loop

Page 56: Java

Java

Page 56 - Copyright © 2012 Walter Milner - all rights reserved

F8. About to execute loop body first time. i is 1

F8. We have executed total +=data[1] so total is now 5. But what happened to data[0]? We have found the bug.

This outlines how to use a debugger. This is a powerful technique, but it takes time to set it up. Use a

debugger to find bugs as a last resort.

Page 57: Java

Java

Page 57 - Copyright © 2012 Walter Milner - all rights reserved

Type casts

Here is a reminder of the Java primitive types

Whole numbers byte - 1 bytes long short - 2 bytes long int - 4 bytes long long - 8 bytes long

Decimal numbers float - 4 bytes long double - 8 bytes long

Character char - 2 bytes long

Boolean boolean

What happens if we assign a value of one type to a variable of another type? For example

int x = 56; long y = x;

No problem - no compile-time or runtime error. In fact a type conversion is taking place. The 4 bytes of the int and being widened to the 8 bytes of the long. This is a widening conversion and there is no problem. But

int x = 56; short y = x;

is a compile-time error, a 'possible loss of precision'. This is because we are trying to put the 32 bits of an int into the 16 bits of a short, so we might lose some - a narrowing conversion. If we are sure there will not be a problem, we can tell the compiler we understand what we are doing:

int x = 56; short y = (short) x;

Here the (short) is a type cast - an instruction to change the type. If we don't understand what we are doing, we may get an unexpected result:

int x = 70000; short y = (short) x; System.out.println(y);

this outputs 4464. This is because 70000 is too big to fit into 16 bits, and the lost bits were not all zero. Or

int x = 0B1111_1111_1111_1111_1111; // 20 1 bits short y = (short) x; // reduce to 16 System.out.println(y);

outputs -1. This is because y is 1111111111111111, which is the 2's complement form of -1. The 0B

notation to write values in base 2 only works from Java 7 onwards.

In summary - changing to a type with more bits works no problem. If you want a change to fewer

bits, you must use a type cast like (short), and you may lose bits.

Page 58: Java

Java

Page 58 - Copyright © 2012 Walter Milner - all rights reserved

The brackets on a type cast are unusual - they go around the type, not what you are going to cast.

This means you often need another pair of brackets.

For example, suppose we want random integers up to 100. Math.random() produces a random

double from 0 to 1. So we could multiply by 100 then cast to an int:

int x = (int) Math.random()*100;

but this is always 0. Why?

Because the type cast is applied first to the 0.something, producing 0, then 0*100 is 0. We must

multiply first, then do the typecast:

int x = (int) (Math.random()*100);

Exercise

What happens if you do a widening conversion?

When is an explicit type cast required?

Page 59: Java

Java

Page 59 - Copyright © 2012 Walter Milner - all rights reserved

Structured Programming

This topic is about the structure of source code.

So far, we have seen less than around 20 lines of code in each program. In real applications, there

would typically be millions of lines of code. That means it is important to think about how that code

is structured. The structure might be arranging it in separate parts, units, blocks, modules or any

kind of section. This is a question of modularity. The option of having a million lines of code in a

single unit is impractical.

Splitting code into smaller units has clear advantages. Small units are simpler and easier to write.

They are easier to test. They can be written by teams. The units can be re-used in other projects.

The units used in this section are called 'static methods'.The reason why this term is used will be

clearer later. The style of programming here is not object-oriented - it is more in the style known as

structured programming, as used in C and Pascal. But it is a useful preliminary to OOP.

As well as splitting up the code, we need a way to pass data from one section to another. This is

known as parameter passing or argument passing.

Page 60: Java

Java

Page 60 - Copyright © 2012 Walter Milner - all rights reserved

Static methods and parameter passing

Suppose we have two variables, called x and y, of type double, and we want to find their average.

Not a problem - just add them up and divide by 2:

double x=28.0; double y=17.6; double average=(x+y)/2.0;

Now suppose we want the average of a and b:

double a=8.0; double b=107.6; double average2=(a+b)/2.0;

But maybe we want to find the average of several hundred pairs of values. There are two issues - we

would have almost the same piece of code (adding and dividing by 2) duplicated hundreds of times.

But we also need the code to apply to different variables.

The solution is like this:

class Test { static double average(double d1, double d2) { double a; a = (d1 + d2) / 2.0; return a; } public static void main(String[] args) { double x = 12.3; double y = 3.4; double z; z = average(x, y); System.out.println(z); // about 7 } }

Follow through what happens:

1. Execution starts at main

2. Variables x and y are declared and assigned initial values.

3. Variable z is declared

4. We have an assignment z = average(...

5. This invokes the method named average. Execution switches to the block of code starting 'static

double average..'

6. The values of x and y in main are copied to d1 and d2, respectively, in the 'average' code block.

7. In average, a variable 'a' is declared, and there is a calculation to work out the average of d1 and

d2.

8. The code block returns the value 'a'.

9. Execution returns to main, at the point it came from. The value returned from 'average' is

assigned to z

10. z is output - so we can check it has worked.

In 'static double average..', the word double means that the type of the returned value is double.

Page 61: Java

Java

Page 61 - Copyright © 2012 Walter Milner - all rights reserved

The execution path

Execution starts at main. When the

invocation of 'average' is reached,

execution switches to it. At the

'return' statement, execution

switches back to where it came from

(here, in 'main'), and carries on from

there.

The data path

The value of x is copied to d1. The value of y is

copied to d2.

The return value, 'a', is assigned to z.

The parameters in the method header (here, d1

and 2) are sometimes called the formal

parameters. The parameters in the method

invocation ( x and y) are the actual parameters.

So the values of the actual parameters are

copied to the formal parameters.

Exercise

Modify this so that it finds the average of 3

values. Test it.

How it works

The method invocation process works using a data structure called a stack. A stack is simply a pile of

data. Data items are added to the stacked ('pushed') by placing them on top of the stack. Data is

removed (popped) by taking the top item off the stack. The effect is that a stack is a last in, first out

(LIFO) structure. The item that comes out of it will be the last thing that was put in it.

When a method is invoked, the current address (location of the program instruction) is pushed onto

the stack. At the end of a method (the return statement) a value is popped off the stack, and

execution proceeds from there - in other words, it returns to where it came from.

The issue is that inside a method, we might have an invocation of another method, and so on. In fact

we already have this in this example, since the method 'average' is invoked from the method 'main'.

But using a stack means there will not be a mix-up. No matter how many method invocations there

are, it will always return to the last one invoked, which is what is needed.

Page 62: Java

Java

Page 62 - Copyright © 2012 Walter Milner - all rights reserved

What if a method invokes itself? This would require an infinitely big stack. Your program will end,

with the error message 'Stack overflow'. See the section on recursion.

The stack is also used to pass parameters. At the invocation, the return address is pushed onto the

stack. Then copies of the actual parameters (x and y) are pushed onto the stack. At the start of the

method, the correct number of values are popped off the stack (here 2) and placed in the formal

parameters (d1 and d2). Just 1 value, the return address, is left on the stack, ready for the return

statement.

Another example - factorial

The factorial of a number n (usually written n!) is 1 x 2 x 3 x.. n. So for example 3! is 1 x 2 x 3 = 6.

We could have a method to calculate factorials:

class Test { static long factorial(int n) { long temp = 1; for (int i = 2; i <= n; i++) { temp *= i; } return temp; } public static void main(String[] args) { for (int n = 1; n < 21; n++) { System.out.println("n= " + n + " n! = " + factorial(n)); } } }

Check how the factorial method works.

In main, we use a variable n. We also use n as the name of the formal parameter in the factorial

method. Does it matter? Will the values of the two n's get mixed up? No.

The name of the actual parameter is n, same as the formal parameter. Does that matter? No.

Does a formal parameter have to have the same name as the actual parameter? No. Can it? Yes.

Exercise

A nth. triangular number is the sum of all integers from 1 to n. So the fourth is 1+2+3+4 =10.

Write a program which has a static method to find the nth triangular number, and which outputs the

first 10 triangular numbers.

The Math class

Suppose we want to use the sine function. How to do that? We could write our own static method,

calculating a sine as a power series expansion, but it might be tricky. We don't have to, its already

there.

The Math class has a collection of static methods for all the usual maths functions. We use it by

invoking Math.sin() (taking its argument=parameter in radians). The class also has Math.PI as a

constant. So for example

Page 63: Java

Java

Page 63 - Copyright © 2012 Walter Milner - all rights reserved

System.out.println(Math.PI); System.out.println(Math.sin(Math.PI/6)); double angle = 2.0; //radians double sin = Math.sin(angle); double cos = Math.cos(angle); System.out.println(sin*sin+cos*cos);

which outputs:

3.141592653589793

0.49999999999999994

1.0

Remember that floating point arithmetic is not totally accurate.

Exercise

Write a program which inputs the radius of a circle and outputs its area.

Page 64: Java

Java

Page 64 - Copyright © 2012 Walter Milner - all rights reserved

Scope

Instead of finding the average of x and y as (x+y)/2, we could calculate it as x/2+y/2. For example:

public class Test { static double average1(double x, double y) { double result = (x + y) / 2; return result; } static double average2(double x, double y) { double result = x / 2 + y / 2; return result; } public static void main(String args[]) { double x = 3; double y = 4; double z; z = average1(x, y); System.out.println(z); z = average2(x, y); System.out.println(z); } }

This works as expected.

But both methods declare a local variable 'result' with the same name. Will this name clash be a

problem? No. Why not? Because they are in different scope.

Suppose we go back to one method, and refer to 'result' in 'main':

public class Test { static double average1(double x, double y) { double result = (x + y) / 2; return result; } public static void main(String args[]) { double x = 3; double y = 4; double z; z = average1(x, y); System.err.println(result); } }

This is a problem - we get a compile-time error, and the compiler complains that 'it cannot find the

symbol result'.

Another example:

scope of 'result'

'result' is out of scope

Page 65: Java

Java

Page 65 - Copyright © 2012 Walter Milner - all rights reserved

static double average1(double x, double y) { if (x > 5) { double result = (x + y) / 2; } if (x > 7) { double result = (x + y) / 2; } return 3.5; }

Here we have declared 'result' twice in the same method. This is not a problem. We have two blocks,

enclosed in { }, and scope is limited to that block. The two 'result's are in different scope.

Why was Java (and Pascal and C and C++ and most versions of Basic and many other languages)

designed like this? It means that when choosing a local variable name, you do not need to worry if

you have used the same name elsewhere. With an application with many thousand lines of code,

written by a team, and using variable names like x and y and result and count and sum, that would

otherwise be a big problem. With local variables having limited scope it is not a problem.

Page 66: Java

Java

Page 66 - Copyright © 2012 Walter Milner - all rights reserved

Recursion

Recursion is a programming technique in which a method invokes itself.

Recursive factorial

Recall that n factorial n! = 1 x 2 x 3 x..n

An equivalent way of defining this is to say that

if n==1, n!=1

else n! = n x (n-1)!

Look at that carefully.

Here it is in Java:

static long factorial(int n) { if (n == 1) { return 1; } else { return n * factorial(n - 1); } }

This is recursive, since the factorial method refers to the factorial method.

Exercise

Use this to output 2! to 10!

About recursion

Recursive methods are often very short, very elegant and very close to a mathematical definition (as

in this case).

Once you get the idea, they are very easy to write.

A recursive method can always be 'unrolled' into an iterative (looping) method. The previous section

had a factorial method with a loop.

They are sometimes highly inefficient.

Fibonacci sequence

The famous Fibonacci sequence is 1,1,2,3,5,8,13.. We start off 1,1 then add the last two numbers.

So the definition is

if n=1 or 2, fib(n)=1

else fib(n)=fib(n-1)+fib(n-2)

and in Java:

Page 67: Java

Java

Page 67 - Copyright © 2012 Walter Milner - all rights reserved

class Test { static long fib(int n) { if (n == 1 || n == 2) { return 1; } else { return fib(n - 1) + fib(n - 2); } } public static void main(String[] args) { for (int i = 1; i < 20; i++) { System.out.print(fib(i)+" "); } } }

which outputs

1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181

There is a large and significant branch of mathematics related to the Fibonacci sequence. Google it.

An entire research journal is devoted to it.

The time complexity of recursive methods

When we compare different algorithms, we look at how much memory they use (space complexity)

and how much time (time complexity). Ideally we want algorithms which are small and fast.

For our recursive Fibonacci - if we work out fib(20), how many times will the method be invoked?

Spend some time trying to work that out.

We can modify the code to count it for us:

class Test { static int count = 0; static long fib(int n) { count++; if (n == 1 || n == 2) { return 1; } else { return fib(n - 1) + fib(n - 2); } } public static void main(String[] args) { fib(20); System.out.println(count); } }

The answer is 13529. Why?

fib 20 -> fib 19+ fib 18

fib 17 + fib 16

fib 15 + fib 14

fib 16 + fib 15

fib 18 + fib 17

fib 16 + fib 15

fib 17 + fib 16

So this, just the beginning, shows fib 18 is called twice, fib 17 3 times, fib 16 4 times and so on. There is a large amount of repeated calculation, and we end up with 13529 calls.

Page 68: Java

Java

Page 68 - Copyright © 2012 Walter Milner - all rights reserved

Iterative Fibonacci

Here is an iterative version:

class Test { static int count = 0; static long fib(int n) { count++; long last1 = 1, last2 = 0, next = 0; for (int i = 0; i < n; i++) { next = last1 + last2; last2 = last1; last1 = next; } return next; } public static void main(String[] args) { fib(20); System.out.println(count); } }

In this, fib is invoked just once. So this algorithm is 13000 times faster when n=20. This is a good

illustration of the fact that the choice of a different algorithm can sometimes produce code whichis

very much faster.

It can be proved that any recursive procedure can be re-written as an iterative one.

But sometimes recursion is efficient. Remember it!

Page 69: Java

Java

Page 69 - Copyright © 2012 Walter Milner - all rights reserved

When it does not work

What do you do when a Java program goes wrong? There are three case

1. It won't compile. This is easy to fix.

2. It compiles and runs, but crashes. In Java this will involve 'thowing an exception'. This is fairly easy

to fix.

3. It compiles and runs, but does the wrong thing, or outputs the wrong result. This is a problem.

We will look at each case

Compile error

These are easy to fix, because the compiler will tell you the line where the error is, and some clue as

to what the error is. In NetBeans and Eclipse, the IDE will flag the error with an ugly red line before

you run it. For example in NetBeans:

The light bulbs at lines 9 and 10 mean information. The red exclamation marks mean an error. The

red wavy line under d means there is some problem with it.

Hover the mouse over the information, and it tells you the error message:

The phrase 'cannot find symbol - symbol variable: d' means the compiler cannot work out what 'd' is.

This usually means you have forgotten to declare it, which is the problem here. It says it three times

because d occurs three times in that line. The compiler is telling you what the problem is and where

it is - its easy to fix. Just declare d.

Page 70: Java

Java

Page 70 - Copyright © 2012 Walter Milner - all rights reserved

Run-time exception

The first version of Java was developed for the software in TV remotes. If a TV remote crashes, the

user is going to be quite annoyed. So Java was developed to handle run-time errors in a controlled

way.

These events are called exceptions. For example:

There is no red waviness so no compile-time errors. But when we run it:

we get an exception. Read the message carefully. The type of exception is

java.lang.ArithmeticException. So its something to do with arithmetic. / by zero is divide by zero.

Then it tells us where - at Main.main - in other words, in the method called main, in the class called

Main. And Main.java:8 means it is at line 8 in the file called Main.java. Pretty easy to fix.

In practice exception messages are a lot more tricky to read than this. Here we just have one

method, called main. What often happens is that we have one method which uses another, which

uses another, which uses another, maybe to a depth of ten, and the exception occurs at the tenth

level, causing one at the ninth, and so on, each of which are reported. So many of the exceptions are

not in code you have written. But you have caused it, indirectly. Look towards the top at files you

have written, and look in them at the line numbers indicated.

Incorrect programs

In formal software development, you start with a specification - a statement of what the program

should do, in terms of possible input and required output. A program which performs according to

this specification is correct. Otherwise its incorrect.

In other words the program runs, but it does the wrong thing and produces the wrong output. This is

hard to fix. In effect it is a detective novel, a whodunnit, and you have to find the guilty party.

Usually this is done by a combination of hunch and logical deduction.

Here are some suggestions

1. One piece of evidence is the output - what it actually does. Can you make sense of that? How

could the actual output have been caused?

Page 71: Java

Java

Page 71 - Copyright © 2012 Walter Milner - all rights reserved

2. Can you work out which piece of code is causing the error? You should write and test code in very

short pieces. Do not write code like an essay, 2000 words at a time. Write at most 10 lines, and test

it. This means you can be fairly confident (does not always work) that what you have written is

correct. Or if it goes wrong, look in the last ten lines you have written.

If you have written 2000 lines of code since you last tested it, the bug is anywhere in those 2000

lines. You might as well start again, this time 10 lines at a time.

3. Use comment debugging. This means enclosing some lines of code in comments. If you still get the

error, those lines are correct, and you can uncomment them. This avoids deleting and re-writing

correct code.

4. Use print debugging. Use System.out.println to output the value of a variable in suspicious code.

Do you get the value you think it should be? The prize is when you find an incorrect value. You can

then work backwards from there - how could it have got that value? You are close to the solution.

5. Check the algorithm. Is the method of solution actually correct? This might involve paper and

pencil calculation. Chose an easy case.

6. Use a debugger. IDEs usually have a built-in debugger, which lets you step through the code one

statement at a time, and set up 'watch variables' so you can see the values they take on step by step.

You also have options like 'run to cursor', 'step into' and 'step over'. Because it takes time to set the

debugger up, avoid this if possible. Sometimes it isn't possible.

Page 72: Java

Java

Page 72 - Copyright © 2012 Walter Milner - all rights reserved

OOP

Java is an OOP language - it uses object-oriented programming. This is a different approach to

programming from structured programming. The code we have seen up till now has not been typical

Java.

This section introduces the key ideas of class and object.

It provides some examples of using common Java classes

Page 73: Java

Java

Page 73 - Copyright © 2012 Walter Milner - all rights reserved

Classes and objects

Objects

Variables like ints or doubles can be thought of in two ways - data storage in memory, or as

representing quantities in the real world. Similarly we can think of objects in two ways. We can think

of what they actually are in memory, and what the idea is, in terms of what they represent.

Objects in Java represent things. Here are some examples of objects

Objects Context

Buttons, windows, scroll bars, drop-down lists, combo boxes

GUI programming

Employees, managers, departments HR - personnel management Aliens, demons from hell, monsters Video game Accounts, cheques, direct debits Banking Goods for sale, customers, orders Sales management Files, directories, drives, computers File management Aircraft, flights, runways, air lines Air traffic control

Some objects represent real physical objects in the real world, such as aircraft. Others are in the

virtual world of the computer, such as a file.

All objects are things. Objects are nouns.

Exercise

What objects would you expect to have in a program used to manage a veterinary clinic?

Objects in memory

As a Java program runs, objects are created and sometimes destroyed. They are held in memory.

The information held in each object is held in a block of memory.

Sometimes objects are made to persist by storing them in a file, so that they can be accessed again

the next time the application runs.

What is in an object?

Objects have two kinds of members:

Fields. Sometiems called data members. These are pieces of data about the object needed by the

program. For example, an employee would have a payroll number. A window has a title and a

background colour. Data members might be primitive types like ints, or they might be objects

themselves.

Methods. These are pieces of code which are blocks of instructions appropriate when an object does

something. For example an employee might have a method called changeDepartment, which does

what is needed when an employee moves to a different department. A window might have a

method for dealing with a button click. Methods are verbs - doing words.

There is also have a third kind of item:

Constructors. These are pieces of code which do what is needed when a new object is created. This

might involve initialising values for data members, or constructing some other objects.

Page 74: Java

Java

Page 74 - Copyright © 2012 Walter Milner - all rights reserved

Classes

Imagine a window in a GUI program. The window might have four buttons on it. That's four objects.

But they are all buttons. They are all the same type. A class is a type of object.

Or:

Class Objects

Cat - The cat (Felis catus), also known as the domestic cat or housecat to distinguish it from other felines and felids, is a small furry domesticated carnivorous mammal that is valued by humans for its companionship and for its ability to hunt vermin and household pests. From Wikipedia, the free encyclopedia

A class is a type of object.

When a Java program creates an object belonging to a class, we say the object instantiates the class.

Or, the object is an instance of the class.

Class names start with a capital letter. Objects do not. So we might have a class called Cat, and an

object, an instance of the Cat class, called tufty.

Classes objects and code

A Java application will use existing classes,

creating objects which are instances of them.

But an application will also set up new

classes. The programmer needs to specify

what fields, methods and constructors the

class has - in a class definition. Each class

definition is in a different source code file,

which has the same filename as the name of

the class. So if we define a class called Cat, it

must be in the file called Cat.java.

One of those class definitions must have a method called public static void main. This method is the

point where the application will start execution :

Encapsulation

One aspect of OOP is the idea of encapsulation. The point of this is to 'seal up' the contents of an

object, in order to ensure that the data in it cannot be corrupted by program bugs. The problem we

are trying to fix is the possibility that bugs in a program might corrupt the data in an object and

render it invalid. The solution is to ensure that wherever possible, the data members cannot be

accessed from outside the class.

Page 75: Java

Java

Page 75 - Copyright © 2012 Walter Milner - all rights reserved

The solution is implemented by two ideas - access control and accessor methods.

Access control is achieved by the use of the keywords public and private (plus others). If a member is

public, it can be accessed from anywhere. If it is private, it can only be accessed from inside the

class. Most members, especially data fields, should be private. Sometimes they cannot be - for

example

public static void main(String[] args)

has to be public, since it must be executed by the runtime system, outside the class.

However, we often need to be able to 'read' the values of data members - for example, finding out

the width of a window. Sometimes we want to 'write' a new value - such as changing the width of a

window. And we want to do this and still keep the data members private.

This is achieved by having public accessor methods. A getter method allows data members to be

read from outside the class. These usually start with 'get' - such as getWidth. They are very simple.

To 'write' a new value to a private data field, we use a public setter method. An example would be

setWidth. Such methods should include checks to ensure that the value being set is valid. For

example, attempts to make the width of a window negative are ignored.

Exercise

1. What is an object?

2. Objects have three kinds of things - what are they?

3. How are classes and objects related?

4. How are classes and the source code files making up an application related?

5. What is the purpose of encapsulation?

Page 76: Java

Java

Page 76 - Copyright © 2012 Walter Milner - all rights reserved

Characters and Strings

The char type is a primitive - a simple value, not an object. A char literal is enclosed in single quotes

like 'x' (not double quotes like "x" which is a string). So

char myChar='a'; System.out.println(myChar);

A char is internally represented as a 16 bit number, being the Unicode (Google) code for a character.

The first of these are the same as the older 7 bit ASCII code set. For example, 65 to 90 are the letters

A to Z:

char c; for (int code=65; code<91; code++) { c=(char)code; // type cast the number to the equivalent char System.out.print(code+" "+c+" : "); }

outputs: 65 A : 66 B : 67 C : 68 D : 69 E : 70 F : 71 G : 72 H : 73 I : 74 J : 75 K : 76 L : 77 M : 78 N : 79 O : 80 P : 81 Q : 82 R : 83 S : 84 T : 85 U : 86 V : 87 W : 88 X : 89 Y : 90 Z : We can also have a char literal as its Unicode value, in hex, directly:

char uniChar = '\u0030'; // hex 30 = decimal 48 = digit zero

The visual appearance will depend on which character it is, and which font is currently being used. Some (most) fonts cannot display all 65000 Unicode characters. On Windows, the CharMap utility is useful for finding characters and their codes. The first 32 ASCII characters are usually treated as 'control characters' in the sense of controlling the output rather then displaying normal symbols. These are mostly historical, being used to control the position of the head of a teletype machine. But some are still useful:

char uniChar = 10; // line feed System.out.println(uniChar); // produces 2 new lines

The line feed can also be represented as an 'escape sequence':

char uniChar = '\n'; // new line System.out.println(uniChar);

Strings

A char is a primitive type representing one character. A String in Java is a sequence of zero or more characters. Strings are objects, instances of the class String. For example:

String s = "Hello from Java"; // make a string System.out.println(s); // output it s="line one \n line two"; // two lines s="one "+"two"; // + concatenates = joins, strings int x=4; s="x = "+x; // s is 'x = 4' s=""; // s is a string with no characters s=null; // s is null - not the same as ""

Page 77: Java

Java

Page 77 - Copyright © 2012 Walter Milner - all rights reserved

The String class has many useful methods. We can invoke a method (make it happen) on an object by using the syntax <object name>.<method>() Some methods take parameters, others do not. Here are a few examples

String s = "Hello from Java"; // make a string int n = s.length(); // length of string = 15 // getting parts of a string char c=s.charAt(1); // 'e'. Character at some position - first char is position 0 String s1=s.substring(1, 3); // s1 is "el". Part of a string s.contains("from"); // true. Does it contain another string s.equals("Hello from Leicester"); // false. Compares two strings s.indexOf("from"); // 6. Location of one string in the other. -1 if not there s.startsWith("Hello"); // true s.replace("Java", "C++"); // returns "Hello from C++" String[] words= s.split(" "); // words is an array of 3 strings "Hello", "from" and "Java"

Exercise

Try this out.

There are several ways to convert between numbers and strings. For example:

int i; double d; String s3 = Integer.toString(i); String s4 = Double.toString(d);

and the other way round:

String s1="28"; String s2="1.24"; int i = Integer.parseInt(s1); double d=Double.parseDouble(s2);

When a string is changed into a number, there is the chance that the string is not a valid number - such as 1.2.3. In this case a NumberFormatException will be thrown, which you can catch:

String s="1.2.3"; double d; try{ d=Double.parseDouble(s); } catch (NumberFormatException nfe) { System.out.println("Its gone horribly wrong"); // put code here to fix things }

But in Java strings are unusual objects, in that Strings are immutable

This means a String object, once created, cannot be changed. It often looks like we are changing a

string object, when in fact we are creating a new one and setting a reference to it. For example

String s="One"; // make a String object, and set s to refer to it s="Two"; // Do NOT change the "One" string - make a new string, "Two", and set // s to refer to it

or

Page 78: Java

Java

Page 78 - Copyright © 2012 Walter Milner - all rights reserved

String s="ABC"; s = s+"DEF"; // makes a new string, from ABC and DEF

Sometimes this does not matter much. Sometimes it does - for example:

String s = "A"; for (int i=0; i<1000; i++) s+="A";

This creates 1001 String objects. It loses all but 1 reference to them, so it creates 1000 garbage

objects.

Consequently it is sometimes better to use some alternatives.

Arrays of char

An array of char is the same as an array of anything else - we can certainly change its elements. The

String class has a method toCharArray which creates an array of the chars from a String, and there is

a String constructor which takes a char array as argument. For example, the following turns a String

to an array of chars, then swaps characters to reverse the array:

String s = "What a fine mess"; char[] array = s.toCharArray(); int size = array.length; for (int i = 0; i < size/2; i++) { char temp = array[i]; array[i] = array[size - i - 1]; array[size - i - 1] = temp; } String reverse = new String(array); System.out.println(reverse); // ssem enif a tahW

The point of this is avoiding creating a large number of intermediate String objects.

StringBuilder and StringBuffer

A StringBuilder is in effect a mutable String. The class has a reverse() method, so this is even easier

than with a char array:

String s = "What a fine mess"; StringBuilder sb = new StringBuilder(s); sb = sb.reverse(); String reverse = new String(sb); System.out.println(reverse);

StringBuffer is the same as a StringBuilder, except that it is thread-safe - wich means that your

program is running several threads which might access the same data at the same time, StringBuffer

will ensure it will work correctly - while StringBuilder will not. On the other hand, it will be slightly

slower.

So, no threads => use StringBuilder. Threads, use StringBuffer.

Exercise

Write a static recursive method which reverses a String. The header should be

static String reverse(String s)

It should follow this pseudo-code:

if the length of s is one, return s

else return reverse(s with first char omitted) + first char of s

Test it works.

Page 79: Java

Java

Page 79 - Copyright © 2012 Walter Milner - all rights reserved

How efficient is this?

Re-write it using StringBuilder instead.

Page 80: Java

Java

Page 80 - Copyright © 2012 Walter Milner - all rights reserved

A first look at Swing

Swing is a set of packages which provide the programmer with what is needed to write GUIs

(graphical user interfaces). We will use them to provide examples the idea of classes and objects.

Hello World - in a GUI

Our first Java program outputted the String "Hello World!". Here it is again, as a GUI:

import javax.swing.JFrame; public class Main { public static void main(String[] args) { JFrame myWindow = new JFrame("Hello world!"); myWindow.setBounds(50, 50, 300, 200); myWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); myWindow.setVisible(true); } }

This outputs:

We will take this one line at a time. The important point is how we are using concepts about classes

and objects.

Swing contains a class called JFrame which is a GUI 'window'. A class is a type of object.

The line

JFrame myWindow = new JFrame("Hello world!");

does two things. Firstly it declares a variable, named myWindow, which is of type JFrame. Secondly it

actually makes a new object, and sets myWindow to refer to it.

Constructing a new object is done using the keyword new. Classes have a constructor, which does

what is needed to create a new object - a new instance of the class. The fragment

.. = new JFrame("Hello world!");

invokes the constructor of the JFrame class, making a new object - a JFrame object.

We still have a little work to do. We have to tell that window object to do various things, using setter

methods :

myWindow.setBounds(50, 50, 300, 200);

tells the window object to have a position and size. These are determined by the 50,50,300,200. The

first two numbers fix the position of the top left of the window, relative to the top left of the screen.

Page 81: Java

Java

Page 81 - Copyright © 2012 Walter Milner - all rights reserved

So this window appears 50 pixels in from the left, and 50 pixels down from the top. The next two

numbers fix the width (300 pixels) and height (200 pixels).

Something like setBounds is a method. A method is a process which an object can perform. This has

been programmed into the definition of the class.

Note the syntax. The pattern is to say

<name of the object>.<method to do>

We send a message to the object telling it to do the method. We might also supply parameters (as in

this case) to specify what we want.

The next statement has the same pattern:

myWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

This is about what happens when the top right 'close' button on the window is clicked. Unless we tell

it otherwise, this closes the window, but does not exit the application. This is because an application

might have several windows which open and close as the user uses it. For most of these, they would

not want to close the application when they closed the window. This would only be true for the 'top-

level' main window. This statement changes that, so that when the window is closed, the

application stops.

While it follows the

object.method

pattern, the argument is slightly different. JFrame.EXIT_ON_CLOSE is a constant - it is a name for a

number. We know it is a constant because it is in capital letters. The value of it is 3. The

setDefaultCloseOperation method expects to be given a number, which is used as a code for what

should happen when the window closes. A 3 means to end the application.

So why not say

myWindow.setDefaultCloseOperation(3);

which is a lot shorter? Three reasons

1. This version does not say what it means. Anyone reading the program - probably a programmer

tasked with maintaining it - would have to work out - why 3? This would be an example of a magic

number, to be avoided.

2. When writing it, you would have to remember that 3 is the value for exiting on close - and all the

other constant values for thousands of classes.

3. If the coding alters, and it is no longer 3, this version would no longer work. But because the value

of the name EXIT_ON_CLOSE would also change, a version using the symbol would still work.

The form JFrame.EXIT_ON_CLOSE shows that we are referring to the value EXIT_ON_CLOSE which is a

member of the JFrame class. If other classes also use EXIT_ON_CLOSE there will not be a clash.

The final statement

Page 82: Java

Java

Page 82 - Copyright © 2012 Walter Milner - all rights reserved

myWindow.setVisible(true);

is simple. When a new JFrame object is constructed, it is not displayed. Only when we send it the

setVisible message, with an argument of true, does it become visible.

In a Swing GUI, there is a choice - create and close new windows as they are needed, or create them

as invisible windows and switch on and off their visibility as required.

Exercise

Run this program.

Alter it so that the size and position of the window changes.

Change the window title.

Make it so that two JFrame objects appear.

Page 83: Java

Java

Page 83 - Copyright © 2012 Walter Milner - all rights reserved

The Java API

How does the programmer know all this stuff? How do we know what classes there are and what

they can do? By referring to the API - the application program interface. This is the documentation of

the standard Java classes. It is online, currently at

http://download.oracle.com/javase/7/docs/api/

It is a good idea to find it and bookmark it. It is very consistent, because the documentation is

generated automatically by a tool called javadoc.

The API looks like this:

The top left frame shows a choice of packages - groups of classes. The bottom left shows a list of

classes. The main panel on the right shows information on the selected class, including its

constructors, methods and other information. It may provide some notes on how to use the class,

but you often need to look elsewhere for this. The API is primarily for reference. It contains several

concepts which we have not yet covered.

Do not be put off by the very large number of classes. This is good news, not bad, in that it

represents a lot of programming already done and which you can re-use.

Page 84: Java

Java

Page 84 - Copyright © 2012 Walter Milner - all rights reserved

Subclassing

As well as just using existing classes out of the box, we can also make our own classes by modifying

existing ones. Here is a different approach to our windows program:

import javax.swing.JFrame; public class Main extends JFrame { public Main() { super("Hello world!"); setBounds(50, 50, 300, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { Main main = new Main(); } }

Try this program out.

There are three differences here.

1. Our Main class now extends JFrame

2. We have written a constructor for our class

3. The main method now instantiates our Main class

We will examine each of these in more detail:

Extending a class

The line

public class Main extends JFrame {

means that the class called Main IS the class called JFrame, but with features changed or added on.

In other words, everything in the JFrame class is in the Main class. Consequently, everything a

JFrame can do, our class can do as well. But we can add extra parts. We will add a constructor and a

method called main.

Main is now a subclass of JFrame. Jframe is a base class or superclass of Main.

Writing a constructor

The line

public Main() {

starts the constructor. Remember that a constructor does what is needed to create an object, an

instance of the class.

How do we know it is the constructor? Because its name matches the name of the class. Take note -

a constructor is not a method, and does not have a return type, not even void.

The statements in the constructor are not very different from what we had before:

super("Hello world!");

Page 85: Java

Java

Page 85 - Copyright © 2012 Walter Milner - all rights reserved

This invokes the constructor of the superclass, which is JFrame. In other words it makes a basic

JFrame with the given title.

The next line

setBounds(50, 50, 300, 200);

is very similar to what we had before:

myWindow.setBounds(50, 50, 300, 200);

except that we are no longer referring to the object myWindow. So which object are we referring

to? The answer is this object being constructed.

Similarly for the rest:

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

set up the properties of the object we are constructing.

Instantiating the class

Remember the main method is where execution starts. This now says:

Main myWindow = new Main();

This declares a variable called myWindow, which will be an object of class Main. The part:

.. = new Main();

invokes the constructor of Main, which we have just written, and will actually make such an object.

Definitions do not execute sequentially

Here is our definition of the Main class:

import javax.swing.JFrame; public class Main extends JFrame { public Main() { .. the constructor.. } public static void main(String[] args) { .. start execution here .. } }

Suppose we had written the parts in a different sequence, like:

Page 86: Java

Java

Page 86 - Copyright © 2012 Walter Milner - all rights reserved

import javax.swing.JFrame; public class Main extends JFrame { public static void main(String[] args) { .. start execution here .. } public Main() { .. the constructor.. } }

Does this make any difference? No. Why not? Because the class definition is just a definition, not a

program to be executed sequentially. When execution needs to start, the system looks for main(). If

it needs to instantiate the class, it looks for the constructor. The order of these definitions makes no

difference.

Exercise

Suppose we had two lines in main:

Main myWindow1 = new Main();

Main myWindow2 = new Main();

What would happen?

Try it.

Explain it (try moving the window).

Page 87: Java

Java

Page 87 - Copyright © 2012 Walter Milner - all rights reserved

Variables and values

Primitive and Reference Types

Primitive types are for example ints and doubles and chars. These are not objects. They have single

values.

Reference types are objects.

So for example

int x = 3; // x is a primitive type String text = new String("Click me"); // text is a reference type

In fact there are significant differences in the way these are stored. If we have three int variables x y

and z, with values 1 2 and 3, we might think of them as being held in memory like this:

It is more effective to think of this as a symbol table:

But if we have say

String a = new String("One"); String b = new String("Two");

we can think of memory like this:

Here object 'a' is held in memory starting at address 21. Object 'b' starts at address 25. In the symbol

table, next to 'a' it says 21, the start address of the object. Next to 'b' it says 25, the start address of

the object. In the symbol table therefore we have pointers to where the object is in memory. A

pointer to something is the address of it. This is what a reference is.

Page 88: Java

Java

Page 88 - Copyright © 2012 Walter Milner - all rights reserved

In a Java program we do not know, and cannot find out, the actual numeric address of these things.

But we do not need to know. It is more useful to think of this situation like this:

Here we have pointers as arrows. In reality they are numeric addresses, but they can be thought of

as actual pointers to different memory locations.

References and taking out the garbage

Suppose we have this code:

String a = new String("One"); String b = new String("Two"); b = a;

What happens? After the first two statements the situation is as in the previous diagram. After the

third statement, we have

b=a means that b now points to the same object as 'a' points to. Both a and b reference the same

object.

It does NOT mean this:

it does not make b point to a - it makes b point to what a points to.

But what now of object b? Nothing refers to it. This means that our Java program can no longer use

that object, since we have effectively lost track of where it is.

It has become garbage - data in memory which is no longer needed. What will happen is that the

garbage collector , part of the runtime software, will return this memory block to free memory, from

where it can be re-used.

Page 89: Java

Java

Page 89 - Copyright © 2012 Walter Milner - all rights reserved

More precisely, the garbage collector might do that. It takes time to do a garbage collection, and if

there is plenty of free memory already, it is a waste of time. So the garbage collector has an

algorithm which means it will only do it if it is worthwhile.

null

The special value null is a 'pointer to nowhere'. We will see some uses for it later.

A common problem relates to null. This code:

String s="cat"; System.out.println(s);

executes as expected. But

String s="cat"; s=null; System.out.println(s);

results in a run-time exception:

Exception in thread "main" java.lang.NullPointerException

at Main.main(Main.java:12)

Line 12 is the println statement. This error usually arises when we try to invoke a method on an

object reference which is null - so in effect the object does not exist. Typically the program is trying

to access uninitialised data. Sometimes the compiler can detect this - but not always.

The println method invokes the toString() method of its argument. toString is a method which all

objects have, which converts the object to an equivalent string. So this println statement is in effect

System.out.println(s.toString());

so we are invoking a method on s.

The line s=null; means that s points to nowhere - it does not point to an object, so we cannot invoke

a method call on it. If we do, we get a NullPointerException.

Swapping reference type variables

We saw that to exchange the values of primitive types, we needed to use a third temporary

location, like:

int x=1; int y=2; int temp; temp=x; x=y; y=temp;

Will the same pattern work for reference types? Strings are objects - how about

Page 90: Java

Java

Page 90 - Copyright © 2012 Walter Milner - all rights reserved

String s1 =new String("One"); String s2 = new String("Two"); String temp; temp=s1; s1=s2; s2=temp;

After the first three statements, we have:

After temp=s1; this changes to

After s1=s2;

and after s2=temp;

so this has done what we wanted.

Exercise

For Strings, a statement like:

s2=s2+"ne";

constructs a new string object, containing the text in s2 joined at the front to 'ne'. It then makes s2

refer to this new object.

What do you think the following code will do?

Page 91: Java

Java

Page 91 - Copyright © 2012 Walter Milner - all rights reserved

String s1="One"; String s2="O"; s2=s2+"ne"; System.out.println(s1); System.out.println(s2); if (s1==s2) System.out.println("Equal");

Try it.

Explain what happens.

Look at the String API and look at the equals() method.

Parameter passing

Suppose we have a method which finds the average of two values:

double average(double x, double y) { double result; result=(x+y)/2.0; return result; }

and we invoke this method by:

double a; double b; a=2.0; b=3.0; double c = average(a,b);

How exactly does this work?

The items x and y, or a and b, are called

parameters or arguments. The x and y in the

definition of the method are sometimes

called formal parameters, while the ones

used in the invocation of the method (in

this example, a and b) are actual

parameters. Actual parameters can be

constants, variables or expressions.

The way this works varies between

different languages. In Java, the values of

actual parameters are copied, and these are passed to the formal parameters. This is sometimes

called "pass by value".

Which parameter is copied to which depends on the order - that is, the first (a) is copied to the first

(x), the second (b) to the second (y) and so on. The process involves a stack - the actual parameter

copies are pushed onto a stack, then in the start of the method the values are popped back off the

stack and assigned to the formal parameters.

Suppose a method changes a parameter value? For example,

Page 92: Java

Java

Page 92 - Copyright © 2012 Walter Milner - all rights reserved

double average(double x, double y) { double result; result=(x+y)/2.0; x+=1.0; return result; }

Does changing x affect a?

The answer is no, because x is a copy of a. Changing the copy will not affect the original.

Reference types as parameters

Does it make any difference if the parameter is a reference type - an object? In one sense no, since

the parameter is still copied. But for a reference type, this is a pointer to the object. The pointer is

copied, not the object.

For example, suppose we want a method to find which day of the week it is:

int getDay(GregorianCalendar formalDate) { int result = formalDate.get(GregorianCalendar.DAY_OF_WEEK); return result; }

This uses the class GregorianCalendar, which does what we want. We could use this by:

GregorianCalendar date=new GregorianCalendar(); System.out.println("Day (sunday =1) "+getDay(date));

But suppose the method changes the formal parameter:

int getDay(GregorianCalendar formalDate) { int result = formalDate.get(GregorianCalendar.DAY_OF_WEEK); // make it Sunday formalDate.set(GregorianCalendar.DAY_OF_WEEK, 1); return result; }

and see what happens:

GregorianCalendar date=new GregorianCalendar(); System.out.println("Day (sunday =1) "+getDay(date)); System.out.println(date.getDisplayName(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.LONG, Locale.ENGLISH));

The output of this (run on a Thursday) is:

Day (sunday =1) 5

Sunday

So it correctly tells us it is Thursday - but then changing the formal parameter has made it Sunday.

How come a reference type can be changed?

The rule is the same - parameters are copied then the copy is passed into the method. But a

reference type parameter is a pointer to an object. Changing the pointer, such as by

Page 93: Java

Java

Page 93 - Copyright © 2012 Walter Milner - all rights reserved

formalDate=null;

would not affect the actual parameter, since it changes a copy. But if the method alters the object

being pointed at, that change will be seen in the invoking code.

Another way of looking at this is to count the objects. In the code above, the keyword new is only

used once. There is only one GregorianCalendar object. A pointer to it is copied and passed into the

method - and the method uses the pointer to change the object pointed to.

Arrays are objects, so this is applicable for arrays as parameters.

Exercise

What do you think this code would do?

static void swap(int[] one, int[] two) { int temp; for (int i = 0; i < one.length; i++) { temp = one[i]; one[i] = two[i]; two[i] = temp; } } public static void main(String[] args) { int[] a = {1, 2, 3}; int[] b = {4, 5, 6}; swap(a, b); for (int i = 0; i < a.length; i++) { System.out.println(a[i]); } for (int i = 0; i < b.length; i++) { System.out.println(b[i]); } }

Write a method called zero, which takes an array of ints as parameters, and makes every element

zero. Test it.

Page 94: Java

Java

Page 94 - Copyright © 2012 Walter Milner - all rights reserved

Wrapper Classes

The primitive types, int double char and so on, are simple values. They are not objects and they have

no methods.

Sometimes it is convenient to have an object which is 'like' a primitive. For example, we might have a

class called Integer which is like an int, but is a class with constructors are methods. Such a class is

called a wrapper class, because it wraps a primitive, as a data member.

Most of the useful methods are static:

Integer i = new Integer(3); System.out.println(i); System.out.println(i.intValue()); // back to where we started // some static methods System.out.println("Biggest int is "+Integer.MAX_VALUE); // 2147483647 System.out.println("Smallest int is "+Integer.MIN_VALUE); //-2147483648 System.out.println("386 in binary is "+Integer.toBinaryString(386)); //110000010

Remember that ints are primitives, and Integers are not - they are objects. Be careful about:

Integer i = 3; System.out.println(i);

This is an unfortunate feature called autoboxing. It is the same as

Integer i = new Integer(3);

The first version is less typing, but deceptive, because it really looks like i is an int, when it is not.

Similarly

Integer i = new Integer(3); int i2 = i+1;

This is called unboxing - it is the same as

Integer i = new Integer(3); int i2 = i.intValue()+1;

This is more typing, but you are clear that i is not an int.

There are corresponding wrapper classes for the other primitives - Byte, Short, Long, Float, Double,

Character and Boolean.

These are the standard wrapper classes. The idea can be used more generally, writing your own

classes which wrap objects. This idea is related to inheritance by composition.

Page 95: Java

Java

Page 95 - Copyright © 2012 Walter Milner - all rights reserved

Overloading

Overloading means having the same name or symbol have several different meanings.

In Java, some operators (like + and / ) are overloaded. Unlike C++, we cannot programmatically

overload operators.

In Java, constructors and methods are very often overloaded.

Operator overloading

We can use + on Strings:

String hello = "Good" + "day";

and it concatenates them.

And we can use + on ints:

int x = 2 + 2;

and it carries out arithmetic addition. So + is overloaded.

More subtly, / is overloaded:

int x = 11/5; // integer division : x is 2

double y = 11.0/5.0; // double division : y is 2.2

What decides which / is used is decided by the operand type, not the left hand side type. So

double y = 11/5; // y = 2.0

What happens here is that first the compiler parses 11/5 and sees / applied to two ints, so it

generates code which will do int division which would give the result 2. Then a typecast is generated

to change int 2 to double 2.0.

But we cannot write Java code to make + (or any other operator) perform differently.

For example you might define a class Vector to model vectors in 3d space. It would be nice if you

could overload + so you could say

Vector a = ..

Vector b = ..

Vector c = a + b;

as you can in maths. You can do this in C++, but not in Java. Instead you must define an add()

method, and say

Vector c = a.add(b);

This works just as well but does not look as neat. It makes the compiler a lot simpler, but it loses

some 'syntactic sugar'.

Page 96: Java

Java

Page 96 - Copyright © 2012 Walter Milner - all rights reserved

Constructor overloading

Classes often have several constructors. The different versions must differ in the number or type of

arguments. For example the Integer wrapper class has two constructors, one taking an int and the

other a String:

Integer int1 = new Integer(3); Integer int2 = new Integer("1000");

The JFrame class, the Swing model of a GUI window, has 4 constructors. The API shows them as:

So we can say

JFrame win1 = new JFrame(); // window with no title Jframe win2 = new JFrame("My window"); // window with title;

Method overloading

This is the same idea - several versions of a method, all with the same name but with differing

numbers or types of parameters. For example, the String class has several method called 'indexOf':

For example:

String str = "barbara"; int pos; pos=str.indexOf('a'); // 1 pos=str.indexOf('a', 2); // 4 pos=str.indexOf("bar"); // 0 pos=str.indexOf("bar", 2); // 3

Exercise

How would you expain to someone what overloading means in Java?

Page 97: Java

Java

Page 97 - Copyright © 2012 Walter Milner - all rights reserved

Page 98: Java

Java

Page 98 - Copyright © 2012 Walter Milner - all rights reserved

Inheritance

We have seen that we can extend a class to create a new, modified class. This is called subclassing.

The original class is called the base class.

Suppose we say

class C extends B ...

This defines a new class C, as a modification or sub-class of class B. This means C objects will have

1. All the data fields of B (they are inherited )

2. Possibly extra data fields

3. All the methods of B (inherited)

4. The inherited methods can be modified so they work differently. The modified methods override

the inherited ones.

5. C objects might have extra methods.

This means a sub-class has everything the base class has, plus extra, and the inherited methods may

be over-ridden to work differently.

Constructors are not inherited.

What is the point of inheritance?

Inheritance allows us to re-use existing code in order to achieve something similar but slightly

different. We can avoid having to start again from scratch.

Example of sub-classing

Suppose we want a GUI application, where all the windows should have a yellow background.

We could start by coding a window class. But there is already a class for a window, named JFrame.

We can re-use that code, and extend JFrame so that we fix its background colour to be yellow:

public class YellowWindow extends JFrame { YellowWindow(String title) { super(title); // invoke JFrame constructor getContentPane().setBackground(Color.yellow); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String args[]) { YellowWindow one = new YellowWindow("One"); one.setBounds(10, 10, 200, 200); YellowWindow two = new YellowWindow("Two"); two.setBounds(300, 10, 200, 200); } }

Page 99: Java

Java

Page 99 - Copyright © 2012 Walter Milner - all rights reserved

Class hierarchies

A subclass can be the base class for another sub-class. In other words

we can say

class B extends A.. .. class C extends B..

This means we have a class hierarchy:

Exercise

Subclass YellowWindow so you have a JFrame with a yellow background and a fixed initial size of 100

by 100 pixels

Page 100: Java

Java

Page 100 - Copyright © 2012 Walter Milner - all rights reserved

The Object class

We have seen that we can subclass a base class to create a modified new class.

In fact there is a special class named Object, which is the ultimate base class of all other classes.

If we have:

class A... .. class B extends A.. .. class C extends B.. ..

then in fact class A extends class Object, automatically without saying so, and the hierarchy is

Object has just a few methods, which are inherited by all other classes. For example:

Object one = new Object(); System.out.println(one.toString()); // toString() produces a String somehow representing the object // This produces 'java.lang.Object@55c4d594' - not very useful System.out.println(one.getClass()); // getClass() returns an object of type Class. System.out.println calls toString() on // this, outputting 'class java.lang.Object' Object two = new Object(); System.out.println(one.equals(two)); // .equals is true if 2 objects are 'equal' - see below // here we get 'false'

So all classes inherit a toString() method, which is supposed to generate a String which can identify

or give useful info on an object.

When an object reference is passed to System.out.println(), the toString() method of the object is

called, and the resulting String outputted. So in fact the following are equivalent:

System.out.println(one.toString()); System.out.println(one);

Page 101: Java

Java

Page 101 - Copyright © 2012 Walter Milner - all rights reserved

The equals() method returns true if the calling object is 'equal to' the parameter object. Object's

version of this only gives true if they are the same object - for example

Object one = new Object() Object two = one; System.out.println(one.equals(two));

outputs true since 'one' and 'two' both refer to the same object.

Over-riding toString and equals

Normally we have to over-ride toString and equals to give useful versions. For example:

class MyClass extends Object { int x; MyClass(int y) { x=y; } public String toString() { return super.toString()+" x = "+x; } public boolean equals(MyClass other) { return x==other.x; } }

This says MyClass extends Object - this is not needed. All classes ultimately extend Object.

In the definition of toString, we say super.toString(). This calls the toString of the superclass Object.

We then use + to concatenate this with 'x = whatever', so

MyClass one = new MyClass(1); System.out.println(one);

outputs ' test.MyClass@3479404a x = 1'

In equals, we just compare the value of x with the value of the x field of the other object. We say

'x==other.x'. This will be a boolean value, true or false, and we just return that value. So

MyClass one = new MyClass(1); MyClass two = new MyClass(1); MyClass three = new MyClass(2); System.out.println(one.equals(two)); // gives true System.out.println(one.equals(three)); // gives false

How you write .equals() depends on the nature of the object. Some fields will be 'key' identifying

values, while others may be not relevant to identifying the object.

Exercise

What is the difference between an object and Object?

Page 102: Java

Java

Page 102 - Copyright © 2012 Walter Milner - all rights reserved

Overloading and overriding

Overloading means having two or more methods defined in a class with the same name. Their

numbers or types of parameters must differ. Similarly we can have overloaded constructors.

Overriding is when we have a method in a base class, and a definition of a method with the same

name in a subclass. The subclass method overrides the base class method.

An example

class Test { public static void main(String args[]) { Base b = new Base(); b.method1(); Sub sub = new Sub(); sub.method1(); sub.method2(1); sub.method2('x'); } } class Base { void method1() { System.out.println("In method1 in Base"); } void method2(int x) { System.out.println("Overloaded Base method2 with an int"); } void method2(char x) { System.out.println("Overloaded Base method2 with a char"); } } class Sub extends Base { void method1() { System.out.println("Overriding method1 in Sub"); } }

The output is: In method1 in Base Overriding method1 in Sub Overloaded Base method2 with an int Overloaded Base method2 with a char

Remember that constructors are not inherited.

Page 103: Java

Java

Page 103 - Copyright © 2012 Walter Milner - all rights reserved

super

'super' is a Java keyword which can be used in several contexts. In general it refers from a subclass to

the base class.

super in method calls

A method in a base class can be invoked from a subclass by using the syntax super.methodName().

For example

class Test { public static void main(String args[]) { Sub sub = new Sub(); sub.method1(); } } class Base { void method1() { System.out.println("In method1 in Base"); } } class Sub extends Base { void method1() { super.method1(); System.out.println("Overriding method1 in Sub"); } }

which outputs In method1 in Base Overriding method1 in Sub You might do this if a subclass method needs to execute the code in the base class, plus extra code.

super and data fields

super can be used to refer to data members in a base class from a subclass, if the subclass

introduces a new field with the same name. The following example is followed by a health warning:

Page 104: Java

Java

Page 104 - Copyright © 2012 Walter Milner - all rights reserved

class Test { public static void main(String args[]) { Sub sub = new Sub(); sub.method(); } } class Base { int x = 3; } class Sub extends Base { int x = 4; void method() { System.out.println(super.x); System.out.println(x); } }

This outputs 3 then 4.

Note carefully - this code fragment is unusual and not normally good practice. A subclass inherits the

data members of the base class, so in this case Sub already has a data member called x. When Sub

declares it again, the 'x' hides the base class 'x'. A reference to x in the subclass is not to the x in the

base class - we have to say super.x to get to it.Now x was probably declared in the base class for

some reason or purpose, and its now hidden in the subclass, so the sublass may not work properly.

You might well do this accidentally, declaring x in the subclass because you forgot it was a field

already in the base class. For this reason most IDEs will warn you if you do this.

super in constructors

Remember that constructors are not inherited.

In a subclass, you can invoke the constructor of the base class by saying super(). This must be the

first line in the constructor. For example:

Page 105: Java

Java

Page 105 - Copyright © 2012 Walter Milner - all rights reserved

class Test { public static void main(String args[]) { Sub sub = new Sub(); System.out.println(sub.x+ " "+ sub.y); } } class Base { int x; Base() { x=3; } } class Sub extends Base { int y; Sub() { super(); y=4; } }

This outputs 3 4.

This is a typical example (but see later) - the subclass constructor first invokes the base class

constructor, then does further work.

Constructors with arguments

If the base class has a constructor which takes arguments, we can invoke it with super and an

argument value:

class Test { public static void main(String args[]) { Sub sub = new Sub(); System.out.println(sub.x + " " + sub.y); } } class Base { int x; Base(int val) { x = val; } } class Sub extends Base { int y; Sub() { super(3); y = 4; } }

which outputs 3 4 as expected.

The no-arg constructor

If you do not write super() as the first line of the subclass constructor, the compiler generates one

for you. For example:

Page 106: Java

Java

Page 106 - Copyright © 2012 Walter Milner - all rights reserved

class Test { public static void main(String args[]) { Sub sub = new Sub(); System.out.println(sub.x + " " + sub.y); } } class Base { int x; Base() { x = 3; } } class Sub extends Base { int y; Sub() { y = 4; } }

which again outputs 3 4. Note Sub() does not call super(), but x became 3 anyway. The compiler

inserts the super call.

But what if the base class does not have a no-args constructor?

class Test { public static void main(String args[]) { Sub sub = new Sub(); System.out.println(sub.x + " " + sub.y); } } class Base { int x; Base(int val) { x = 3; } } class Sub extends Base { int y; Sub() { y = 4; } }

This is a compile-time error. The compiler would call Base(), but there is no no-arg constuctor in

Base.

You would fix this either by writing one, or by an explicit use of super with arguments:

Page 107: Java

Java

Page 107 - Copyright © 2012 Walter Milner - all rights reserved

class Test { public static void main(String args[]) { Sub sub = new Sub(); System.out.println(sub.x + " " + sub.y); } } class Base { int x; Base(int val) { x = val; } } class Sub extends Base { int y; Sub() { super(3); y = 4; } }

Exercise

Add comments to the last example saying what is happening.

Page 108: Java

Java

Page 108 - Copyright © 2012 Walter Milner - all rights reserved

this

In Java 'this' is a keyword. Inside a method, it is a reference to the object executing the method.

Inside a constructor, it is a reference to the object being constructed.

Example - this.x = x

Suppose we are defining a class Circle, which might have data members for radius and colour:

class Circle { double radius; Color color; .. }

We would need to pass values for the radius and colour in the constructor:

Circle(double... , Color ...) { radius =.. color=.. }

What to name the arguments? The sensible names are color and radius, but then how to tell the

difference between the arguments and the data members if they have the same name? The usual

solution is to use 'this':

Circle(double radius, Color color) { this.radius = radius; this.color = color; }

Now this.radius is the object data member, while radius is the argument.

Example in Swing

We will expand this example later, but this is a start. When using Swing to program a GUI, we might

subclass a JFrame to make a window:

class MyFrame extends JFrame { MyFrame() // the constructor { .. } }

Suppose we want a button on our window. This is what a JButton is. We have to make one, then

'add' it to the window:

class MyFrame extends JFrame { MyFrame() // the constructor { JButton myButton = new JButton("Click here"); add(myButton); } }

Page 109: Java

Java

Page 109 - Copyright © 2012 Walter Milner - all rights reserved

But to make the button work, we have to say what object will 'listen' for button clicks. This is done

by the addActionListener method. This could be the window itself. But how to refer to the window

being constructed? Use 'this':

class MyFrame extends JFrame { MyFrame() // the constructor { JButton myButton = new JButton("Click here"); add(myButton); myButton.addActionListener(this); } }

We will expand this to fully working code later.

Exercise

If you use 'this' in a method - what does it mean?

Page 110: Java

Java

Page 110 - Copyright © 2012 Walter Milner - all rights reserved

static

Data members and methods can be declared to be 'static'. That means they are per class not per

object.

Despite its name, static does not mean constant. To make a data member constant, use the keyword

'final'.

Example

Suppose we were defining some different types of animals:

class Test { public static void main(String args[]) { Mammal dog = new Mammal("Rover",4,0.8); Insect bee = new Insect("Buzzy", 6, 0.01); } } class Animal { double height, weight; Color color; String name; } class Mammal extends Animal { int numberOfLegs; Mammal(String name, int numberOfLegs, double height) { this.name=name; this.numberOfLegs=numberOfLegs; this.height=height; } } class Insect extends Animal { int numberOfLegs; Insect(String name, int numberOfLegs, double height) { this.name=name; this.numberOfLegs=numberOfLegs; this.height=height; } }

But - all Mammals have four legs, and all Insects have six legs. The number of legs is not a

characteristic of the individual mammal - the object. It is a characteristic of the class. We can capture

that idea by making numberOfLegs to be static - per class not per object:

Page 111: Java

Java

Page 111 - Copyright © 2012 Walter Milner - all rights reserved

class Test { public static void main(String args[]) { Mammal dog = new Mammal("Rover",0.8); Insect bee = new Insect("Buzzy", 0.01); } } class Animal { double height, weight; Color color; String name; } class Mammal extends Animal { static int numberOfLegs; Mammal(String name, double height) { this.name=name; numberOfLegs=4; this.height=height; } } class Insect extends Animal { static int numberOfLegs; Insect(String name, double height) { this.name=name; numberOfLegs=6; this.height=height; } }

Methods as well as data members can be static. The idea is the same - per class not per object.

Example - the Math class

We often need to use maths functions like sine and cosine, and constants like π. These are bundled

together in the Math class. This has a set of static methods, which are used like:

double val = Math.sin(0.6);

The method is invoked with the syntax <class>.<method>(), instead of <object>.<method>() used for

non-static methods.

If the methods had not been static, we would have to have said

Math math = new Math(); double val = math.sin(0.6);

In fact you cannot say this, because the Math constructor is private. All classes have a constructor -

even if just the compiler-generated no-args one. A common way of preventing a class being

instantiated is to make the constructor private.

Example - the Singleton design pattern

Design patterns are patterns of class use. A very common one is the singleton pattern, which is

where you want to be sure you have one, and only one, instance of a class. For example you might

have a class for the main window of a GUI application. You want to have precisely one main window.

So the singleton pattern is appropriate.

Page 112: Java

Java

Page 112 - Copyright © 2012 Walter Milner - all rights reserved

How to do it? The usual method is to have the constructor private, so it cannot be called from

outside the class. You have a static method called getInstance. This checks whether there is already

an instance, and if so, it returns a reference to it. Otherwise it creates one instance:

class Test { public static void main(String args[]) { MySingleton one = MySingleton.getInstance(); MySingleton two = MySingleton.getInstance(); if (one == two) { System.out.println("Only got one"); } } } class MySingleton { static MySingleton instance = null; private MySingleton() { } static MySingleton getInstance() { if (instance == null) { instance = new MySingleton(); } return instance; } }

Example - autonumber

We often want to have a set of objects each having a unique key field to identify it. For example a

bank account needs a unique account number. This is achieved in databases by having an

'autonumber' field which automatically increases every time a new record is added. We can achieve

the same thing in Java if the class maintains a static field which 'remembers' how many objects have

been created:

Page 113: Java

Java

Page 113 - Copyright © 2012 Walter Milner - all rights reserved

class Test { public static void main(String args[]) { BankAccount b1 = new BankAccount("Tom"); BankAccount b2 = new BankAccount("Dick"); BankAccount b3 = new BankAccount("Harry"); BankAccount b4 = new BankAccount("Tom"); b1.display(); b2.display(); b3.display(); b4.display(); } } class BankAccount { static int counter=0; int accountNumber; String owner; BankAccount(String owner) { this.owner=owner; accountNumber=counter; counter++; } void display() { System.out.println("Owner: "+owner+ " Account number: "+accountNumber); } }

which outputs:

Owner: Tom Account number: 0 Owner: Dick Account number: 1 Owner: Harry Account number: 2 Owner: Tom Account number: 3

Example - main

main is static. It has to be. The key point about main is that execution starts there. If it had been non-static, the class would have first to have been instantiated, and then main invoked on that object. But calling main by definition is the first thing that happens.

cannot be referenced from a static context

Beginners often get this

compile-time error:

They will often get rid of the error message by making the method to be static. But then no objects are instantiated and there is no OO programming. 'Static context' means the code is in a static method, so there is no object, so a non-static method cannot be invoked.

Page 114: Java

Java

Page 114 - Copyright © 2012 Walter Milner - all rights reserved

The solution is to construct an object, then invoke the method on it:

class Test { void someMethod() { System.out.println("hello"); } public static void main(String args[]) { Test test = new Test(); test.someMethod(); } }

Exercise

Describe three situations where the use of 'static' is appropriate.

Page 115: Java

Java

Page 115 - Copyright © 2012 Walter Milner - all rights reserved

Date and Time in Java

This section illustrates more uses of OOP, in the context of dates and time.

Timing

Timing a process is simple. The System class has a static method called currentTimeMillis(), which

returns the current system time in milliseconds. This can be used by storing the current time in a

variable, running the process, finding the new time, and finding the difference.

For example, this outputs in seconds how long it takes to count to one billion:

long start = System.currentTimeMillis(); for (long i=0; i<1000000000; i++); long end=System.currentTimeMillis(); System.out.println((end-start)/1000.0);

The for loop has no body - we just count. The return type of currentTimeMillis is a long, since an int

does not have sufficient range.

If you run this several times, you get different answers. This is because the computer multitasks, and

is doing other activity as well as running this program.

Exercise

Use this method to time how long it takes to bubble sort an array of random integers. Do this for

various array sizes from 1000 to 1000000. Does this agree with the theory?

The Date class

The fundamental way that Java treats points in time is as a long integer, being the number of

milliseconds since January 1, 1970, 00:00:00 GMT. The number can be negative, so we can represent

times before 1970. A Date object, an instance of the Date class, represents a point in time. Inside a

Date object there is a long integer, which fixes the time. We say Date wraps a long integer.

Here is a simple start:

Date now = new Date(); System.out.println(now);

which will output something like:

Mon Oct 17 16:45:00 BST 2011

There are two Date classes. The one in java.sql is about dates in databases. This Date is in java.util.

The no-args constructor Date(); returns a Date object set to the current time and date. The println

invokes the toString() method of Date, which by default will format it as shown.

Deprecated methods

When the Date class was first designed (in JDK 1.0) the idea was that as well as representing a

moment in time, it would also handle notions like what month it is, what year, the day of the week

and so on. But it was then realized that these were about a calendar, not a moment in time, and that

there were many possible structures for a calendar, used in different parts of the world. So the

Calendar class was set up, in JDK1.1.

Page 116: Java

Java

Page 116 - Copyright © 2012 Walter Milner - all rights reserved

So many of the methods in Date were better handled by Calendar. Those methods in Date were said

to be deprecated. That means they are still available - otherwise old Java code might stop working.

But it signals that there is a better way of doing it, and that in future deprecated methods may

disappear. You should not write Java using a deprecated method.

As an example, Date has another constructor which takes a year (after 1900), month (January=0) and

day as arguments:

Date inThePast = new Date(10,2,4); System.out.println(inThePast);

which outputs

Fri Mar 04 00:00:00 GMT 1910

but this constructor is deprecated.

The imporant thing about Date is that it wraps a long integer which marks a moment in time. We will

see how this is useful later.

Exercise

Date has a method getTime() which returns the underlying time point. Use this to find out how many

milliseconds after midnight on 1 January 1970 you were born (use the deprecated constructor).

Date Formats

If you just output a Date, you get the default formatting as shown above. If you want to specify the

format yourself, you can use an instance of SimpleDateFormat, which is a subclass of the

DateFormat class.

The format is specified by a format string - see the API for all the details. For example:

Date now = new Date(); String s = "'sometime in' MMMM 'in the year' yyyy"); SimpleDateFormat vagueFormat = new SimpleDateFormat(s); System.out.println(vagueFormat.format(now)); s=("yyyy.MM.dd G 'at' HH:mm:ss z"; SimpleDateFormat exactFormat = new SimpleDateFormat(s); System.out.println(exactFormat.format(now));

which outputs:

sometime in October in the year 2011

2011.10.18 AD at 11:41:11 BST

SimpleDateFormat also deals with different time zones. This needs a little thought. It is the same

moment in time no matter where you are. But it is expressed in different ways in different time

zones. Date represents the number of milliseconds since Jan.1,1970 which is the same wherever you

are (in UTC). But you can set a SimpleDateFormat to different time zones and see that moment in

different places:

Page 117: Java

Java

Page 117 - Copyright © 2012 Walter Milner - all rights reserved

Date now = new Date(); String s = "yyyy.MM.dd G 'at' HH:mm:ss z"; SimpleDateFormat exactFormat = new SimpleDateFormat(s); System.out.println("In London, " + exactFormat.format(now)); TimeZone est = TimeZone.getTimeZone("EST"); exactFormat.setTimeZone(est); System.out.println("In New York, " + exactFormat.format(now)); TimeZone japan = TimeZone.getTimeZone("Japan"); exactFormat.setTimeZone(japan); System.out.println("In Tokyo, " + exactFormat.format(now));

which outputs:

In London, 2011.10.18 AD at 11:57:53 BST In New York, 2011.10.18 AD at 05:57:53 EST In Tokyo, 2011.10.18 AD at 19:57:53 JST

Exercise

Output what time it is in Honolulu (unless you are in Honolulu, in which case, what time it is in

London).

The GregorianCalendar class

The whole problem with Date is that there are several different calendars in use across the world.

That situation is modelled in OOP by having a class hierarchy, with a base class that establishes the

common features which all calendars would have, and sub-classes which model actual calendars.

This is how it works. Calendar is the base class, and offers common features but it is abstract, so you

cannot instantiate it. The standard subclass is GregorianCalendar, which models the most common

calendar in use across the world today. The no-args constructor creates an object modelling the

current time in the current locale. getTime() retrieves the underlying moment, as a Date:

GregorianCalendar gc = new GregorianCalendar(); System.out.println(gc.getTime());

A GregorianCalendar object again represents a moment in time, but unlike Date (which in effect it

wraps) it also has fields for day, month, year and so on. When these are changed, it recalculates the

underlying time instant (when it needs to).

There are three kinds of methods on these fields - set, add and roll. Set is simplest - it sets the given

field to the given value:

GregorianCalendar gc = new GregorianCalendar(); System.out.println(gc.getTime()); gc.set(Calendar.MONTH, 0); System.out.println(gc.getTime()); gc.set(Calendar.MONTH, 13); System.out.println(gc.getTime());

Tue Oct 18 15:15:16 BST 2011 Tue Jan 18 15:15:16 GMT 2011 Sat Feb 18 15:15:16 GMT 2012 As the above shows, in 'lenient mode', if you try to set an invalid date, it fixes it, so month 13 is

month 2 in the following year.

The add functions add the given amount to the given field. If for example you are adding days, and

you go beyond the end of the month, it goes into the next month:

Page 118: Java

Java

Page 118 - Copyright © 2012 Walter Milner - all rights reserved

GregorianCalendar gc = new GregorianCalendar(); // Tue Oct 18 15:20:21 BST 2011 gc.add(Calendar.DAY_OF_MONTH, 1); // Wed Oct 19 15:20:21 BST 2011 gc.add(Calendar.DAY_OF_MONTH, 13); // Tue Nov 01 15:20:21 GMT 2011

The roll functions are like add, but you don't roll forward:

GregorianCalendar gc = new GregorianCalendar(); // Tue Oct 18 15:24:31 BST 2011 gc.roll(Calendar.DAY_OF_MONTH, 1); // Wed Oct 19 15:24:31 BST 2011 gc.roll(Calendar.DAY_OF_MONTH, 13); // Sat Oct 01 15:24:31 BST 2011

Exercise

Check the Calendar API for changing the lenient mode. Use it to validate a date.

Date Calculations

Suppose we want to work out something like the point in time three fifths of the way between 1 Jan

1900 and 12 August 1973. Why? Maybe because you are drawing a graph with time as the x axis.

One way to do it is

1. Make Calendar objects of those two dates. 2. Extract the Date, then the underlying long

integer, from those two 3. Do arithmetic on the longs 4. Convert the result back into a Date, then a

Calendar:

GregorianCalendar gc1 = new GregorianCalendar(1900,0,0 ); GregorianCalendar gc2 = new GregorianCalendar(1973,7,11 ); Date date1 = gc1.getTime(); Date date2 = gc2.getTime(); long point1=date1.getTime(); long point2=date2.getTime(); long answer = point1 + (point2-point1)*3L/5L; Date d =new Date(); d.setTime(answer); GregorianCalendar gc3= new GregorianCalendar(); gc3.setTime(d); System.out.println(gc3.getTime()); // Wed Mar 01 14:48:00 BST 1944

Exercise

Find out when you were half your current age.

Page 119: Java

Java

Page 119 - Copyright © 2012 Walter Milner - all rights reserved

Interfaces

The idea of an interface is abstract and subtle - you might want to read this now, and again later.

A class can implement an interface. This means that the class can do the things the interface says it

can. Interface is a Java keyword.

An interface is a set of method signatures (headers, declarations) without method bodies. The class

'implements' an interface by providing a body for each of the methods.

What is the point of that? We often give an object the role of performing some task involving a set

of actions. This enables the compiler to check whether the object belongs to a class which can

actually do those actions.

As an example, we might want something which will respond to mouse actions on a GUI component

like a window. The MouseListener interface has methods for the mouse entering the component,

leaving, a mouse button depression, release and click. We might program a class called

MyMouseListener which implements that interface - in other words, actually defines those five

methods. Then we code the window that an instance of MyMouseListener will deal with mouse

actions. The compiler can check that MyMouseListener actually does implement MouseListener.

We can also think of an interface as a contract. This is like a contract of employemnt - it says the

employee will do certain things. It does not say how they will be done, it simply lists the tasks. It is

up to the employee to actually do it. The MouseListener is a contract of five tasks. Any class which

gets this job must fulfill that contract.

Example - the Comparable Interface

Suppose we have a class of objects consisting of a pair of integers, x and y, and we want to sort an

array of such objects. We will name the class Pair. The class Arrays (in the java.util package) has a

method called sort which will do that for us. But it can only sort objects which implement the

Comparable interface. This is because it is often not obvious what it means for one object to be

'more than' another. We will say that a Pair object is more than another if the sum of x and y is

more than the sum of the other objects x and y.

The Comparable interface has just one method, compareTo. This should return a positive int if the

object is more than the other, zero if it is equal, and a negative int if it is less.

So we must code our Pair class to do this method:

Page 120: Java

Java

Page 120 - Copyright © 2012 Walter Milner - all rights reserved

class Pair implements Comparable { int x, y; // a pair of ints Pair(int a, int b) { // the constructor x = a; y = b; } void show() { // display values System.out.println(x + " " + y); } public int compareTo(Object ob) { // implements the Comparable method Pair other = (Pair) ob; if ((x + y) > (other.x + other.y)) { return 1; } if ((x + y) == (other.x + other.y)) { return 0; } return -1; }

Code to create and sort the array is:

Pair[] data = new Pair[3]; // make an array data[0] = new Pair(3, 2); // put 3 elements in data[1] = new Pair(2, 2); data[2] = new Pair(1, 2); Arrays.sort(data); // sort // see what we've got for (int i = 0; i < data.length; i++) { data[i].show(); }

The output is:

1 2 2 2 3 2

Exercise

Change the compareTo implementation so that one Pair is more than another if the average of x and

y is greater. Test it.

Page 121: Java

Java

Page 121 - Copyright © 2012 Walter Milner - all rights reserved

Event handling

This section shows more examples of using classes and objects, and the event-handling mechanism

in Swing.

This makes a window with a button:

import javax.swing.JButton; import javax.swing.JFrame; public class Main extends JFrame { JButton myButton; public Main() { super("Hello world!"); setBounds(50, 50, 300, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); setLayout(null); myButton=new JButton("Click me"); add(myButton); myButton.setBounds(10,10,100,30); } public static void main(String[] args) { Main myWindow = new Main(); } }

This produces:

JButton is the Swing class modelling a button on the screen.

The line

JButton myButton;

declares a reference to a JButton object. This means every Main window object will have a JButton

object in it.

In the constructor, it says

myButton=new JButton("Click me");

Because of the word new, this invokes the constructor of JButton. In other words, this actually

makes a JButton object.

add(myButton);

This places the button on the window we are constructing.

myButton.setBounds(10,10,100,30);

This sends a message to the myButton object telling it to do its setBounds method, to set its position

and size. This is just like the setBounds method of the window.

We have to say

Page 122: Java

Java

Page 122 - Copyright © 2012 Walter Milner - all rights reserved

setLayout(null);

to tell the window to not use a layout manager. This allows us to control the position of the button

directly.

As yet, the new button does nothing when clicked. We need an event handler.

Event handling

The next version is:

import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; public class Main extends JFrame implements ActionListener { JButton myButton; public Main() { super("Hello world!"); setBounds(50, 50, 300, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); setLayout(null); myButton=new JButton("Click me"); add(myButton); myButton.setBounds(10,10,100,30); myButton.addActionListener(this); } public static void main(String[] args) { Main myWindow = new Main(); } public void actionPerformed(ActionEvent e) { System.exit(0); } }

Now when the button has been constructed, we say

myButton.addActionListener(this);

This tells the button that when it is clicked, it should send a message to this - that is the window we

are constructing. We have to program the window to respond as we want.

The compiler will only allow that if the window is programmed with the correct method, which is the

actionPerformed method. It checks this by checking if the class implements the ActionListener

interface:

public class Main extends JFrame implements ActionListener

This interface has only one method - actionPerformed. We program this as:

public void actionPerformed(ActionEvent e) { System.exit(0); }

This method is executed when the button is clicked. It is an event handler - it handles the event of

the button being clicked. In this example, we tell the System to exit - in other words we tell the Java

runtime to end.

Page 123: Java

Java

Page 123 - Copyright © 2012 Walter Milner - all rights reserved

Exercise

Try this out.

Replace the System.exit with code so that

when the button is clicked a new window is

constructed. This will be on top of the first so

you'll have to move it. You should be able to

get something like this.

Page 124: Java

Java

Page 124 - Copyright © 2012 Walter Milner - all rights reserved

Defining a new class

We have seen how we can create new classes by extending existing classes.

We can also define new classes which do not extend others (except Object).

As an example we will start a stock control system as might be used in a shop. The things for sale are

modelled as StockItem objects. We want to be able set up new stock items, sell them, deliver new

stock, and find out the current stock level. Here is some code:

class Test { public static void main(String args[]) { StockItem item1 = new StockItem(20, "Tins of Beans"); item1.sell(10); item1.deliver(5); item1.show(); StockItem item2 = new StockItem(10, "Bags of flour"); item2.sell(2); item2.deliver(5); item2.show(); } } class StockItem { int stockLevel; String description; StockItem(int s, String d) { stockLevel = s; description = d; } void deliver(int howMany) { stockLevel += howMany; } void sell(int howMany) { stockLevel -= howMany; } void show() { System.out.println(description + " : Stock level = " + stockLevel); } }

Firstly, we have defined two classes, Test and StockItem, like this:

class Test { public static void main(String args[]) { .. } } class StockItem { .. }

This is all in one file, called Test.java. The only purpose of the Test class is for main, where execution

starts. This is not a typical way to do it, but it works.

The class which models stock items is named StockItem. Classes should start with a capital letter.

Page 125: Java

Java

Page 125 - Copyright © 2012 Walter Milner - all rights reserved

The definition begins with the declaration of two data members:

class StockItem { int stockLevel; String description; .. }

That means each StockItem object (every instance of the StockItem class) will have a stocklevel and a

description.

We then have the constructor:

class StockItem { .. StockItem(int s, String d) { stockLevel = s; description = d; } .. }

We know it is the constructor because it has the same name as the class. This is not a method, an dit

has no return type. It takes two parameters which are used to initialise the stock level an

description. We would use this like

StockItem item1 = new StockItem(20, "Tins of Beans");

Then there are three methods:

void deliver(int howMany) { stockLevel += howMany; } void sell(int howMany) { stockLevel -= howMany; } void show() { System.out.println(description + " : Stock level = " + stockLevel); }

In main we test this out:

StockItem item1 = new StockItem(20, "Tins of Beans"); item1.sell(10); item1.deliver(5); item1.show(); StockItem item2 = new StockItem(10, "Bags of flour"); item2.sell(2); item2.deliver(5); item2.show();

which outputs

Tins of Beans : Stock level = 15 Bags of flour : Stock level = 13

Exercise

Add attributes for price in StockItem, and modify the constructor and show() to correspond.

Page 126: Java

Java

Page 126 - Copyright © 2012 Walter Milner - all rights reserved

Projects and Packages

A Java application usually consists of several new class definitions. Each new class is usually defined

in a separate file with a corresponding filename. For example a class named MyClass is defined in a

file named MyClass.java.

One of those classes will contain a 'public static void main(String[] args)' method, and so this will be

where execution starts.

These several class definition files are called a 'project'. This is not a Java keyword, but IDEs invite

you to start a new 'project' and organises files and directories for you. As well as class definitions, a

project may include resources such as image and sound files.

NetBeans (and other IDEs) allows you to have several projects open at the same time, and have one

set as the 'main' project. When you hit Run, it is the main project which is compiled and executed.

This shows the stages of creating a new project in NetBeans 7.01:

Create a simple Java application Call it Demo Project parts

If we then do Run.. Clean and Build Main Project, the following folders are produced. Folder src

contains the source code .java files which

we write. The build folder contains the

.class files which the compiler produces.

The dist folder contains jar files for

distribution - jars are described later. And

the nbproject folder contains metadata

about the project itself.

Packages

A project might have a considerable number of class definition files. It might be appropriate to group

those classes into sections which are about the same activity, and it might be useful to re-use some

of those sections in other projects.

Page 127: Java

Java

Page 127 - Copyright © 2012 Walter Milner - all rights reserved

These ideas are supported by the Java keyword 'package'. A

package is simply a group of related classes. For example, the

project JCartes2 draws graphs of mathematical functions. It has

two packages, in addition to the default package which contains

documentation. The package 'parsing' contains classes which

handle calculations, and the package 'gui' handles the graphical

user interface.

Syntactically, this is done using

the keyword 'package' at the start

of each class definition. For

example to place a class in the

package 'gui', simply have

package gui;

as the first line of the class file.

Packages also fix the problem of

the same name being chosen for different classes. As an example, there are two Date classes. One

deals with dates in general, and the other is for dates in databases. The first is in the package

java.util, whilst the other is in java.sql. If we just want to use the first, we can use an import

import java.util.Date;

and then through the code just refer to Date, like

Date someDate = new Date();

If we want to use both in the same file, we must use the fully-qualified class name, including the

package name - for example

java.util.Date someDate = new java.util.Date();

Page 128: Java

Java

Page 128 - Copyright © 2012 Walter Milner - all rights reserved

Encapsulation

The only way for errors to occur in a program is by being put there by the author. No other mechanisms are

known. Programs can't acquire bugs by sitting around with other buggy programs. ~Harlan Mills

One of the key concepts of OOP is encapsulation. The motivation is to prevent bugs which result

from pieces of software corrupting data. As Dr. Mills' quote points out, all bugs are written by

programmers. Encapsulation is an attempt to make the language make it hard for the programmer

to write a bug.

Structured programming organised code into global shared data and sets of functions (in Java,

methods) which processed that shared data. But there was no way to ensure that the global data

could not be accidentally accessed, and unintentionally corrupted, by a function. In other words

there was no way of saying that some data should only be accessible by certain functions.

The idea of an object by itself helps with this, since it links the data members with the methods

which are supposed to process that data. But there needs to be a mechansim to prevent other code

accidentally corrupting the data in the object. This is the purpose of encapsulation and access

control. It is not intended for security purposes.

There are two parts to the mechanism - access modifiers and get/set methods.

public

There is a keyword 'public' which can be applied both to data members and methods. For example,

the main method must be named as

public static void main(String[] args)

Here 'public' is an access modifier. It means that this method can be invoked from anywhere

(instead of just from this class or from the package it is in). The method has to be public, since Java

runtime must call this method to start the application, and the runtime is outside your package.

So methods which you want 'the world' to be able to call should be made public.

Data members should not normally be made public, since that would usually mean any code can

change them to any value. An exception is if the data member is final, so it cannot be changed. A

commonly used example is Math.PI. This is a member of the Math class, representing the value of π,

so is constant. Math.PI is static (which means it is per class, not that it is constant) .

private

Data members and methods which are declared as 'private' can only be accessed from within their

class. That means that methods which are only concerned with the internal operation of the class

should be private.

no access modifier - default

Members can be declared with no access modifier. In that case, the default, they are package-

private. That means they can be accessed within their package, only, and not from outside.

Page 129: Java

Java

Page 129 - Copyright © 2012 Walter Milner - all rights reserved

protected

This is like package-private, except that it can be accessed by sub-classes, which might be in other

packages.

This table tries to summarise which one to use:

data methods

private yes - use get/set methods class-internal only

default package-private constant data only if needed by package

protected constant data only if to be used in sub-class in different package

public constant data only if needed outside package

Getter/setter methods

A getter method enables the value of a private data member to be read from outside the class or

package. The idea is to make the data be private, and provide a non-private method so that there is

read-only access to it. These methods are usually named getSomething - they do not have to be.

For example, a JFrame has a getBackground() which returns the colour of the window background.

Similarly a setter method allows a field to be given a value. A JFrame has a setBackground() method

to set the background color. Setter methods are usually public.

Why make the data members private and write setter methods? Why not make the data public so

they can be set directly? Because the setter method can validate the value being set, with an if, so

that it will only allow suitable values to be given. This does not mean bugs are impossible, but it

makes it more unlikely that the programmer will accidentally set invalid values.

Class level access modifiers

The access modifiers described above apply for individual data members and methods. We can also

give an access modifier to a class as a whole. But only 'public' or the default package-private is

allowed.

In other words if you say

public class ClassA..

then ClassA can be used anywhere. But

class ClassB..

can only be accessed from within its own package. You would do this if the class was needed for the

internal operation of a package, but was not intended to be directly accessed.

Page 130: Java

Java

Page 130 - Copyright © 2012 Walter Milner - all rights reserved

Writing new classes - a personnel system

As an example of how new classes are written, we will set up a personnel system. To make things

clear it will be very simple, and just handle employees and departments.

Code structure

Recall that Java code is split into separate source code files, with each public class defined in each

file. Also there will be a method called

main somewhere where execution will

start:

In an IDE this will be a new project which

we will call 'personnel'. Classes are

grouped into packages, but this simple

example only needs one package, also

called personnel. Each class definition will

start with

package personnel;

which tells the compiler which package the class is in.

Class design

In this application we will have just 3 classes:

Start - to contain main

Department - to model a department

Employee - to model an employee

The department class

The code for this is

package personnel; class Department { private String name; Department(String n) { name=n; } void display() { System.out.println("Department : "+name); } String getName() { return name; } }

We will go through this first class in a lot of detail. The overall structure of this is

Page 131: Java

Java

Page 131 - Copyright © 2012 Walter Milner - all rights reserved

package.. class Department { ..data members .. constructors and methods }

The package statement must come as the first line. That is where the compiler will look for it.

Then we have the class definition, which starts class Whatever { and ends with the matching } .

Within that we have the data members, constructors and methods. The order of these does not

matter. These will not be executed in sequence, so the order does not matter. It is a definition of

what is in the class, not a program.

After the class header we have

private String name;

This is the only data member in the class - the name of the department. This is a String, and String is

a class, hence the capital letter. It does not say what the name is, since this will be different for each

Department object - each instance of the class. It just states that each Department object will have a

name.

Then we have the constructor:

Department(String n) { name=n; }

We know it is a constructor because it has the same name as the class. It has one String argument, n,

and a single statement, which assigns the field 'name' to this argument.

For example, a department is created by

dep1 = new Department("Production");

Here the argument value "Production" is passed into the constructor as the argument n, and this is

assigned to the department's name field, so it becomes "Production". Distinguish between teh name

of the variable which referencs the object (dep1), and the name field of teh object (Production).

Next we have a method definition

void display() { System.out.println("Department : "+name); }

The fragment display() means the method name is 'display', and the empty bracket shows it takes

no arguments. The void means this method does not return a value - it sends nothing back to where

it was invoked from - it just does something. What it does is to simply output the department name.

The only other method is

Page 132: Java

Java

Page 132 - Copyright © 2012 Walter Milner - all rights reserved

String getName() { return name; }

This does return a value, of type String. It returns the name of the department. This is an accessor

method, a get, which is needed because of access control.

Encapsulation and access control

Remember that encapsulation means sealing up data within objects so that they cannot be

corrupted by bugs. Three access levels are:

private - accessible only from this class

nothing - the default, accessible from this package.

public - accessible from anywhere

The data member is private - it is encapsulated within the class and cannot be accidentally changed

from out of it.

The constructor and method are nothing - that is, package access level. That is what we need.

The data member is private - but sometimes we need to know what the department name is, from

outside the class. We achieve this with an accessor method, a getter,

String getName()

Effectively this makes 'name' to be read-only - we can read it from the package outside the class, but

nothing outside the class can change it.

The Employee class

This is

package personnel; class Employee { private String name; private int salary; private Department department; Employee(String name, int salary, Department department) { this.name=name; this.salary=salary; this.department = department; } void setSalary(int salary) { this.salary=salary; } void display() { System.out.println("Name: "+name + " department: "+department.getName()+" Salary: "+salary); } }

Most of this is similar to Department - we just pick out the differences.

Page 133: Java

Java

Page 133 - Copyright © 2012 Walter Milner - all rights reserved

The constructor has three argument, which are values for the data members. But their names are

the same as the names of the data members - which in one sense is logical, but might be confusing.

The resolution is to use the keyword this:

this.salary=salary;

this.salary means we are referring to the salary field of this object we are constructing. The other

one, just 'salary', is the value of the argument with that name. This technique means we can avoid

having to use argument names different from what they mean, such as

Employee(String n, int s, Department d) { name=n; salary=s; department = d; }

In the display method, we say

+.." department: "+department.getName()+..

We cannot say

+ " department: "+department.name+"

and access the department name directly, because the name field is private. We have to use the

accessor method.

Counting the objects

The Employee class has a data field for a Department. Does that mean that when we create an

Employee object, we also create a new Department object?

No. The keyword new does not appear in the class definition, so no new objects are being created.

The data field 'department' is a reference to another object which already exists, not a newly

created one. The code to use these classes is like:

Department dep1 = new Department("Marketing"); .. Employee emp1 = new Employee("John Smith", 20000, dep1);

The first line creates a new Department object. Then we create a new Employee object, passing to it

a reference to the already existing object called dep1.

Do not be confused by the idea of 'name'. In the line

Employee emp1 = new Employee("John Smith", 20000, dep1);

the name of the object is emp1. Objects of that class have a data field called name. In this instance,

the value of that is "John Smith". But the object is called emp1, not "John Smith".

The Start class

This is:

Page 134: Java

Java

Page 134 - Copyright © 2012 Walter Milner - all rights reserved

package personnel; public class Start { public static void main(String[] args) { Department dep1 = new Department("Marketing"); Department dep2 = new Department("Production"); Department dep3 = new Department("R & D"); dep1.display(); dep2.display(); dep3.display(); Employee emp1 = new Employee("John Smith", 20000, dep1); Employee emp2 = new Employee("Jane Jones", 22000, dep1); Employee emp3 = new Employee("Joe Jeffs", 19000, dep2); emp1.display(); emp2.display(); emp3.display(); emp1.setSalary(22000); emp1.display(); } }

This class is public, as is the main method. This has to be so, since main must be accessible from

outside the package, when the runtime system calls it to start the application.

The main method just makes some Department and Employee objects, displays them, changes

someone's salary and displays them again. The output is:

Department : Marketing Department : Production Department : R & D Name: John Smith Department: Marketing Salary: 20000 Name: Jane Jones Department: Marketing Salary: 22000 Name: Joe Jeffs Department: Production Salary: 19000 Name: John Smith Department: Marketing Salary: 22000

Static and non-static

What does 'static'mean?

Static means per class

Non-static is per object

Most data fields are per object. That means, there is a separate value for each object. For example,

Employee object has a non-static field called 'name'. This is because each employee has their own

name. Similarly for the non-static field salary - each employee has their own salary.

We refer to non-static fields as

<object>.<field>

We have to say which object, since different objects have different values. For example

emp1.name

is the name field of the emp1 object.

Page 135: Java

Java

Page 135 - Copyright © 2012 Walter Milner - all rights reserved

But sometimes it is useful to have some value which belongs to the class, as a whole, not to

individual objects. This is what static means. It is per class, not per object. We refer to a static field

by

<Class>.<field>

All of this applies to methods as well as data fields.

Examples of static - 1

The purpose of the main method is to provide a starting point for the application. Obviously we can

only have one starting point. We can achieve this by making main to be static. Then it is per class. It

is only in one class, so we just have one of it. If it was non-static, then we would have a main method

for each instance of the class, which does not make sense.

In our example, main is in the Start class. The full name of it is

Start.main

We have now explained all of the qualifiers of main:

public static void main(String[] args)

public so it can be accessed from outside the package, by the runtime system. static because it is per

class, so there is just one of it. void because it does not return a result, just does something.

Static example 2 - object arrays

As we have the application at the moment, we make department and employee objects, but they

just 'lie around' in main, where they are declared, one at a time. It would be better if we could refer

to all the departments, or all the employees. We could do this if we put them into arrays. But where

to put the arrays? We could declare them in main, like

static void main(String[] args) { Department[] departments = new Department[10]; ..

but this would mean the array was local to main, and could not be referred to anywhere else, which

we might want to do.

If we declare it like

package personnel; public class Start { Department[] departments = new Department[10]; public static void main(String[] args) { ..

that means the array is non-static - that is there will be a different copy for each instance of the Start

class. But in this version we do not instantiate the Start class - we nowhere say

..=new Start();

But if we say

Page 136: Java

Java

Page 136 - Copyright © 2012 Walter Milner - all rights reserved

package personnel; public class Start { static Department[] departments = new Department[10]; public static void main(String[] args) { ..

then the array is per-class - we have one version of it, linked to the class. The full name of the array

is

Start.departments.

We will do this, for employees as well, and in their constructors put the new object into the correct

array. Then we can have methods to output all departments and all employees. We need to keep

track of how many departments and employees we have:

So now Start is:

package personnel; public class Start { static Department[] departments = new Department[10]; static int departmentCount = 0; static Employee[] employees = new Employee[10]; static int employeeCount = 0; public static void main(String[] args) { Department dep1 = new Department("Marketing"); Department dep2 = new Department("Production"); Department dep3 = new Department("R & D"); Department.displayAll(); Employee emp1 = new Employee("John Smith", 20000, dep1); Employee emp2 = new Employee("Jane Jones", 22000, dep1); Employee emp3 = new Employee("Joe Jeffs", 19000, dep2); Employee.displayAll(); } }

Employee, with a modified constructor and displayAll, is:

Page 137: Java

Java

Page 137 - Copyright © 2012 Walter Milner - all rights reserved

package personnel; class Employee { private String name; private int salary; private Department department; Employee(String name, int salary, Department department) { this.name=name; this.salary=salary; this.department = department; Start.employees[Start.employeeCount]=this; Start.employeeCount++; } static void displayAll() { for (int i=0; i<Start.employeeCount; i++) Start.employees[i].display(); } void setSalary(int salary) { this.salary=salary; } void display() { System.out.println("Name: "+name + " Department: "+department.getName()+" Salary: "+salary); } }

and similarly with Department:

package personnel; class Department { private String name; Department(String n) { name=n; Start.departments[Start.departmentCount]=this; Start.departmentCount++; } void display() { System.out.println("Department : "+name); } String getName() { return name; } static void displayAll() { for (int i=0; i<Start.departmentCount; i++) Start.departments[i].display(); } }

In the displayAll methods, the syntax of

Start.employees[i].display();

refers to Start.employees[i] , then tells that object to do its display() method.

Page 138: Java

Java

Page 138 - Copyright © 2012 Walter Milner - all rights reserved

Static example 3 - class design

As much as possible, we want to 'de-couple' classes, which is to make them as independent as

possible. This makes it easier to re-use them in other situatuions, and lets us develop and debug

them in one place, not in a tangled web across the application.

In our example code, both Start and Employee deal to some extent with employee objects. It would

be better if Employee dealt with all aspects of the employee objects, and similarly for Departments.

We can do this by switching the arrays to their appropriate classes. Now Start looks a lot tidier:

package personnel; public class Start { public static void main(String[] args) { Department dep1 = new Department("Marketing"); Department dep2 = new Department("Production"); Department dep3 = new Department("R & D"); Department.displayAll(); Employee emp1 = new Employee("John Smith", 20000, dep1); Employee emp2 = new Employee("Jane Jones", 22000, dep1); Employee emp3 = new Employee("Joe Jeffs", 19000, dep2); Employee.displayAll(); } }

Employees is:

package personnel; class Employee { private String name; private int salary; private Department department; static Employee[] employees = new Employee[10]; static int employeeCount = 0; Employee(String name, int salary, Department department) { this.name = name; this.salary = salary; this.department = department; employees[employeeCount] = this; employeeCount++; } static void displayAll() { for (int i = 0; i < employeeCount; i++) { employees[i].display(); } } void setSalary(int salary) { this.salary = salary; } void display() { System.out.println("Name: " + name + " Department: " + department.getName() + " Salary: " + salary); } }

We no longer say, for example

Start.employees[i].display();

because the employees array is no longer a static member of Start. We could say

Page 139: Java

Java

Page 139 - Copyright © 2012 Walter Milner - all rights reserved

Employee.employees[i].display();

but because this code is in the Employee class, we can miss out the Employee.

Similarly Department is

package personnel; class Department { private String name; static Department[] departments = new Department[10]; static int departmentCount = 0; Department(String n) { name = n; departments[departmentCount] = this; departmentCount++; } static void displayAll() { for (int i = 0; i < departmentCount; i++) { departments[i].display(); } } void display() { System.out.println("Department : " + name); } String getName() { return name; } }

Remember that

static is per class

non-static is per object

Exercise

Write an application to do stock control (inventory control) in a supermarket. Do NOT write it all in

one go them test it! Write a small section at a time and test as you go along. You should have

different Sections (like tinned fruit, frozen and household) and Goods (like peaches, peas and

dishwasher tablets). Each of the goods needs a price and a current stock level.

You should be able to -

Set up new sections and goods.

Display all sections and all goods.

Sell some items, and so reduce the stock level.

Reduce the price of all items in a given section by 10%

Page 140: Java

Java

Page 140 - Copyright © 2012 Walter Milner - all rights reserved

Writing New Classes - Tic Tac Toe

This section shows how new classes can be designed and written. This will be done using the

example of the game Noughts and Crosses, also known as Tic Tac Toe. We will write this as a

character-based game, then in the next section adapt it to a GUI.

Designing new classes

We first have to identify what classes would be involved in the game. That is, we must identify the

things in the game. One way to do this is to look for the nouns in a description of the context. This is

how wiki describes it:

Tic-tac-toe, also rendered wick wack woe (in some Asian countries), or noughts and

crosses/Xs and Os as it is known in the UK, Australia and New Zealand, is a pencil-and-paper

game for two players, X and O, who take turns marking the spaces in a 3×3 grid. The X player

usually goes first. The player who succeeds in placing three respective marks in a horizontal,

vertical, or diagonal row wins the game.

In our version, one player will be the user, and the computer will be the other player. Here is a set of

classes:

Game. There would only be one instance of this class - just one game object. This is an example of a

singleton class. The Game class would need to let the two players alternate turns, check if someone

had won after each go, and end the game if they had. This class could contain the main method,

since we start by starting the game.

Board. This would need to have a 3X3 grid, and be able to show it. Again a singleton.

Human player. This singleton would represent the human player. It would have to provide for a

human turn, where the board was shown and the user allowed to chose where to go.

Computer player. This singleton represents the human's opponent. The key method would be to

decide where to go.

Projects and packages

An application like this, containing several classes, is a project. The source code (the class definitions)

is organised into one or more packages.

In this case our project could be called ttt, for tic tac toe, and it needs just one package, also called

ttt. We might have done this differently - say one package for the visual content, and another for the

game logic. But this is a pretty simple project so we do not.

The class definitions are now listed. Note they were not written like this and then tested. They were

written small sections at a time, and tested after each small step. This is the end result:

Page 141: Java

Java

Page 141 - Copyright © 2012 Walter Milner - all rights reserved

package ttt; public class Game { // data fields private Board board; private Human human; private Computer computer; // play the game: private void play() { while (true) { // loop forever human.go(); // human's turn // check if they've won if (board.checkWin('X')) { break; // leave loop if so } computer.go(); // computer's turn if (board.checkWin('O')) { break; // leave loop if computer has won } board.display(); // show board and loop } // if leave loop, somebody's won: System.out.println("Game over:"); board.display(); } // constructor private Game() { // create the 3 objects which are part of a Game object board = new Board(); //pass a reference to the board to the constructors of the human and computer // this lets them refer to the board human = new Human(board); computer = new Computer(board); } public static void main(String[] args) { Game game = new Game(); //make a game game.play(); // play it } }

Then the board. It needs to be able to tell if someone has won, and it does this by brute force. There

are only 8 winning configurations - three rows, three columns and two diagonals - and it simply tests

them all.

Page 142: Java

Java

Page 142 - Copyright © 2012 Walter Milner - all rights reserved

package ttt; class Board { // data member - an array of characters private char cells[][] = new char[3][3]; // construct a board Board() { // fill the array with space characters for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { cells[i][j] = ' '; } } } // mark an 'X' or 'O' void set(int i, int j, char c) { // check is valid if (i > -1 && i < 3 && j > -1 && j < 3 && (c == 'O' || c == 'X')) { cells[i][j] = c; } } char getCell(int r, int c) { return cells[r][c]; } // return true if someone's won, otherwise return false boolean checkWin(char c) { boolean result = false; //check rows if (cells[0][0] == c && cells[0][1] == c && cells[0][2] == c) { result = true; } if (cells[1][0] == c && cells[1][1] == c && cells[1][2] == c) { result = true; } if (cells[2][0] == c && cells[2][1] == c && cells[2][2] == c) { result = true; } //check columns if (cells[0][0] == c && cells[1][0] == c && cells[2][0] == c) { result = true; } if (cells[0][1] == c && cells[1][1] == c && cells[2][2] == c) { result = true; } if (cells[0][2] == c && cells[1][2] == c && cells[2][2] == c) { result = true; } // leading diagonal if (cells[0][0] == c && cells[1][1] == c && cells[2][2] == c) { result = true; } //other diagonal if (cells[0][2] == c && cells[1][1] == c && cells[2][0] == c) { result = true; } return result; } // display the board void display() { for (int i = 0; i < 3; i++) { // display a row for (int j = 0; j < 3; j++) { System.out.print("| " + cells[i][j] + " "); } // new line at end of row: System.out.println("|"); } } }

Page 143: Java

Java

Page 143 - Copyright © 2012 Walter Milner - all rights reserved

The human player:

package ttt; import java.util.Scanner; class Human { private Scanner scanner=new Scanner(System.in); private Board board; Human(Board b) { board=b; } void go() { System.out.println("Enter row, column);"); int row= scanner.nextInt(); int column = scanner.nextInt(); board.set(row, column,'X'); } }

and the computer

package ttt; class Computer { private Board board; Computer(Board b) { board = b; } void go() { // at random, find a space int row = (int) (Math.random() * 3); int col = (int) (Math.random() * 3); while (board.getCell(row, col) != ' ') { row = (int) (Math.random() * 3); col = (int) (Math.random() * 3); } // and put an O there board.set(row, col, 'O'); } }

The computer is not too bright. It chooses cells at random until it finds one which is empty, and goes

there.

Page 144: Java

Java

Page 144 - Copyright © 2012 Walter Milner - all rights reserved

Objects in the application

This shows the four main objects which exist when this application is running. Execution starts at

main, and this constructs the game object. That also constructs the human, computer and board

objects.

The arrows show which objects contain references to others. The game has references to the human

and computer objects, so that it can tell them to do their go methods. It also has a reference to the

board object, so that it can tell it to do its display and checkwin methods.

The human and computer objects also have references to the board. This is possible because that

reference was passed to them in their constructors. They need it so that their go methods can use its

get method to find out what is on the board.

Access levels - encapsulation

Recall that encapsulation means sealing objects as much as possible to prevent their corruption by

bugs. This application uses 3 access modifiers

public - can be accessed from anywhere.

no keyword - access restricted to the package.

private - accessible only from that class.

These can be applied to classes or class members. Access levels are chosen here as follows

Game - the class is public. This is because it contains main, which is itself public. The runtime system

must have access to this to start everything off. All other members of game, data fields and

methods, are private. This is the 'best' - members should be private unless there is a reason why

they cannot be.

Board - the class has no access keyword, so access is restricted to the package. There is no reason

why wider access is needed. The same is true of the methods - they are needed to be accessed from

other classes in the package. But the data member, the two D array, is private. But we have get and

set methods which prvide access through them. The set method checks that the row and columns

are possible, and that the character being set if either X or O.

Page 145: Java

Java

Page 145 - Copyright © 2012 Walter Milner - all rights reserved

Human - the class, constructor and go method have no keyword, so are visible to the package, as

needed. The data fields, the scanner and the reference to the board, are private, since that is

enough. The computer object is similar.

Exercise

Try this application out.

Make sure you can understand every line of it.

The computer is dumb - it always loses unless you try hard to let it win. Devise and implement a

better 'go' algorithm for the computer. This is not easy.

Page 146: Java

Java

Page 146 - Copyright © 2012 Walter Milner - all rights reserved

Binary Trees

The subject of data structures and algorithms is a central part of Computer Science, and it is a large

topic - enough to fill several books, with on-going research to fill several journals. This section will

cover some key ideas, by looking at one structure - a tree.

Binary tree

Data structures are composed of elements called nodes. A node contains some data, together with

other parts, especially pointers (in Java, references) to other nodes. The data typically has a key field

to identify it, together with other fields

which we need to store and recall.

A tree data structure is named

metaphorically after a biological tree,

but it is upside down - the root is at the

'top'. Each node carries some data,

and pointers to left and right nodes. Some pointers are

null, if there are no left or right nodes.

From the root, the left node, and the nodes beneath it,

form a structure which is itself a tree. This is the left sub-

tree. Similarly we have a right sub-tree. Since trees are

made of trees, we might expect to be able to treat them recursively. The depth of a tree is how far

down from the root to the bottom.

This is a binary tree, because each node has at most 2 sub-nodes.

Trees do not have to be binary.

What would an empty tree be like? The root would be null - it has

no nodes in it.

When data is added to a tree - where to put it? One algorithm would

be to put the first item at the node, the next 2 on the second 'row',

the next 4 on the third row and so on, in the sequence shown.

Another way is for each value inserted, we start by comparing it

with the root. If it is less, we move to the left node, else (equal

or more) to the right. We do the same again, moving left if less,

and right if more or equal, until we reach a null. And we put the

data in a new node there. For example, suppose we put the

following into the tree: 50,25,75,12,80,30, 50, 51 - we get the

structure as shown.

Page 147: Java

Java

Page 147 - Copyright © 2012 Walter Milner - all rights reserved

A Java implementation

To start with, we can have a class representing one of the nodes in the tree. The data at each node is

an int, but we could have any type:

class TreeNode { int data; TreeNode left; TreeNode right; TreeNode(int n) { data = n; right = left = null; } }

Then for a tree:

class BinaryTree { TreeNode root; BinaryTree() { root = null; } … }

So the tree just has a reference to its root. When we make a new (empty) tree, we just make the

root null.

How to put something in the tree? We have to

1. Make a new node

2. Work out where to put it

3. Put the node there

This will be done so the tree is left-right

ordered. So start at the root. If the value is

less, go left, otherwise go right. Repeat until

the left or right is null, and link it there. In

the following code, 'where' is the current

node, and we loop until this is null. But then

we have lost where to put it. So we also have 'lastWhere', which is the node whose left or right is

null, and we link the new node to lastNode.

We have to check the special case of an empty tree. We just point the root to a new node:

Page 148: Java

Java

Page 148 - Copyright © 2012 Walter Milner - all rights reserved

void add(int n) { TreeNode newNode = new TreeNode(n); if (root == null) { root = newNode; return; } TreeNode where = root; TreeNode lastWhere = where; while (where != null) { lastWhere = where; // where we were if (where.data > n) { // now go left or right where = where.left; } else { where = where.right; } } if (lastWhere.data > n) { lastWhere.left = newNode; } else { lastWhere.right = newNode; } }

How to go through the nodes in the tree? In other words, how to traverse it?

A method which will retrieve the data in order is an in-order traversal. This is a recursive process, as

follows:

if there is a left sub-tree (left is not null), traverse it process the data at the node if there is a right sub-tree (right is not null), traverse it

We start this off at the root node. 'process the data' could be anything - in our case, we will just

output it.

This is recursive - so the node will not be processed until the entire left sub-tree has been traversed.

In code:

void inOrderTraverse(TreeNode where) { if (where.left != null) { inOrderTraverse(where.left); } System.out.print(where.data + " "); if (where.right != null) { inOrderTraverse(where.right); } }

Typically for recursive procedures, this looks very simple, but needs close examination.

The other two standard types of traversal are pre-order:

process the data at the node if there is a left sub-tree (left is not null), traverse it if there is a right sub-tree (right is not null), traverse it

and post-order

if there is a left sub-tree (left is not null), traverse it if there is a right sub-tree (right is not null), traverse it process the data at the node

Page 149: Java

Java

Page 149 - Copyright © 2012 Walter Milner - all rights reserved

Code to make a new tree, insert numbers into it, and traverse it, is:

int[] data = {50, 25, 75, 12, 80, 30, 50, 51}; BinaryTree tree = new BinaryTree(); for (int i = 0; i < data.length; i++) { tree.add(data[i]); } tree.inOrderTraverse(tree.root);

which outputs 12 25 30 50 50 51 75 80

So in fact we have a new type of sort. How fast is it?

final int SIZE=100000; int[] data = new int[SIZE]; Random randomGenerator = new Random(); for (int i=0; i<SIZE; i++) data[i]=randomGenerator.nextInt(SIZE*2); BinaryTree tree=new BinaryTree(); for (int i = 0; i < data.length; i++) { tree.add(data[i]); } tree.inOrderTraverse(tree.root);

output 1 1 1 5 7 10 13 14 14 14 14 18 19 20 22 25 28 31 32 33 34 34 37 39 39 42 ..

It takes less than two seconds to generate and sort 100,000 ints.

Why is it so fast? To insert a value, it starts at the root and goes left or right until it hits 'the bottom'

where the link is null - the depth of the tree. How deep is that? The answer is roughly how many

times you can halve 10000 - or log 2 10000 ≈ 16.6. So to insert each value, we only have to make up

to 16 comparisons. In general for n values we can sort them in n log n time.

This is for random values. What if the numbers are already in order?

final int SIZE=100000; int[] data = new int[SIZE]; for (int i=0; i<SIZE; i++) data[i]=i;

The output (after about 20 seconds) is

Exception in thread "main"

java.lang.StackOverflowError.

The tree looks as shown, and the depth of

the recursive calls to traverse it is 100,000

- too large for the usual stack space.

So this tree insertion sort is excellent for

mixed up data, but terrible on ordered

data.

Page 150: Java

Java

Page 150 - Copyright © 2012 Walter Milner - all rights reserved

Exercise

1. Try this out

2. Predict what order the numbers would come out in for a pre-order traversal, then try out. The try

post-order.

3. To 'prettyprint' a tree means to print it out formatted so it looks like our diagrams. The root is at

the top in the centre. The left and right nodes are below and to each side, and so on.

Prettyprint the tree. This could be using System.out.println, or in Swing using Graphics2D and

drawString. Either way you need to add attributes to a node showing the depth of the node and how

far 'across' it is.

One approach would be to traverse the tree putting the information into an array, with the root in

the first element, the two nodes below in element 2, and so on, then go through the array to print it.

Page 151: Java

Java

Page 151 - Copyright © 2012 Walter Milner - all rights reserved

Hash tables

For most data structures data is stored in it, and then some kind of search is needed to find it again.

The search may be slow.

For a hash table structure, a calculation is made to find where to store the data. When it is needed

to find it, the calculation is repeated, and located immediately. This should be fast.

The data is treated as having a key, to identify it, and associated values. We want to store key-value

pairs in the structure. Then given a key, we should be able to retrieve the value quickly.

The calculation is called a hash function. The input to this is a key value, and the output is a location

where the data is stored.

The underlying data store might be an array, and the 'location' is the index of the element in the

array.

This is a simple version of the basic idea. Various problems arise which must be handled.

Hash table in Java

The data will be a key which is an integer, and a value which is a String. The key and value types

could be anything.

The underlying data store is an array with 20 elements. Real hash tables are much bigger than this,

but we use this so we can output the whole table in a readable form.

The hashing function is (2 X key ) mod 20. So key 1 is stored at index 2. key 4 is stored at 8. We use

mod 20 so we wrap around the array.For example key 12 is stored at 4.

We need methods to insert a key-value pair, retrieve a key and its value, and remove a key.

Page 152: Java

Java

Page 152 - Copyright © 2012 Walter Milner - all rights reserved

class HashTable { final int SIZE = 20; Record[] table; HashTable() { table = new Record[SIZE]; for (int i = 0; i < SIZE; i++) { table[i] = null; } } void put(Record record) { int where = hash(record.key); table[where] = record; } Record get(int key) { int where = hash(key); return table[where]; } void showTable() { System.out.println("Table"); for (int i=0; i<SIZE; i++) { if (table[i]==null) System.out.println(i+" null entry"); else System.out.println(i+" Key:"+table[i].key+" Value:"+table[i].value); } System.out.println("-------------------"); } private int hash(int n) { return (n * 2) % SIZE; } } class Record { Integer key; String value; Record(Integer key, String value) { this.key = key; this.value = value; } }

We could use this like:

HashTable hashTable = new HashTable(); hashTable.put(new Record(1,"John")); hashTable.put(new Record(3,"June")); hashTable.put(new Record(6,"Jane")); hashTable.showTable(); Record r = hashTable.get(1); System.out.println(r.value);

which outputs:

Table 0 null entry 1 null entry 2 Key:1 Value:John 3 null entry 4 null entry 5 null entry 6 Key:3 Value:June 7 null entry 8 null entry 9 null entry 10 null entry

Page 153: Java

Java

Page 153 - Copyright © 2012 Walter Milner - all rights reserved

11 null entry 12 Key:6 Value:Jane 13 null entry 14 null entry 15 null entry 16 null entry 17 null entry 18 null entry 19 null entry ------------------- John // getting key 1

So key 1 went in at 2, 3 at 6, and 6 at 12.

The first problem is collisions. This is when two different keys hash to the same location. For

example, 1 goes to 2, but 11 would hash to 2 as well. Different keys would go in the same slot.

We could try to use a different hashing function - the one here is very simple but defective. But that

would never fully solve the problem. It would only be fixed if every different key went to a different

slot. That would need over 2 billion entries in the array - too much memory required.

An alternative is to store it in the next available free slot. We change to put algorithm to

1. Calculate the hash position

2. Store the data there, or in the next available free slot

We need to change put, and also the get:

void put(Record record) { int where = hash(record.key); while (table[where] != null) { where = (where + 1) % SIZE; } table[where] = record; } Record get(int key) { int where = hash(key); while (table[where]!=null && table[where].key != key) where = (where + 1) % SIZE; return table[where]; }

Test use:

HashTable hashTable = new HashTable(); hashTable.put(new Record(1,"John")); hashTable.put(new Record(11,"First collision")); hashTable.put(new Record(21,"Second collision")); hashTable.put(new Record(31,"Third collision")); hashTable.put(new Record(3,"June")); hashTable.put(new Record(6,"Jane")); hashTable.showTable(); Record r = hashTable.get(21); System.out.println(r.value);

Outputs Table 0 null entry 1 null entry 2 Key:1 Value:John 3 Key:11 Value:First collision 4 Key:21 Value:Second collision 5 Key:31 Value:Third collision 6 Key:3 Value:June 7 null entry ..

Page 154: Java

Java

Page 154 - Copyright © 2012 Walter Milner - all rights reserved

19 null entry ------------------- Second collision // getting key 21

This works, but we are starting to get a sequence of entries which we have to search through,

making insertion and retrieval slower. A different probe sequence would help. Even then, as the

array becomes more full (increased load factor), it will become slower. One approach would be to

monitor the load factor, and if it exceeds say 0.7, copy the data to a larger array (and modify the

hash function.

Exercise

1. Try this out

2. What happens if we ask to 'get' a key which is not in the table?

3. Write a remove method which takes a key and removes the corresponding key-value pair. This is

not as simple as replacing the entry with null (this is the 'second problem'). This is because it might

make a hole in a chain, and then a 'get' might conclude data was absent when it was not. For

example if we have 0 null entry 1 null entry 2 Key:1 Value:John 3 Key:11 Value:First collision 4 Key:21 Value:Second collision 5 Key:31 Value:Third collision 6 Key:3 Value:June 7 null entry

and we delete 11, to get 0 null entry 1 null entry 2 Key:1 Value:John 3 null entry 4 Key:21 Value:Second collision 5 Key:31 Value:Third collision 6 Key:3 Value:June 7 null entry

then when we get 21, we will go to 2, find a null at 3, and think 21 is absent. One solution is to have

a special 'deleted record'.

4. Maintain a 'load factor' and double the underlying array when it exceeds 0.7.

Page 155: Java

Java

Page 155 - Copyright © 2012 Walter Milner - all rights reserved

Swing

The Swing toolkit is a group of packages which are used for creating GUI interfaces. With Swing you

can create windows, labels, text boxes, radio buttons, scroll bars and so on.

An alternative to Swing is the Abstract Windowing Toolkit, or AWT. This is abstract in the sense that

you use ideas like buttons, which are an abstract version of the actual buttons present on native

GUIs in Windows, Solaris and other OS's. The AWT started with JDK 1.0

AWT used OS native code to draw its widgets. Swing uses Java to do a lot of the drawing. AWT is said

to be 'heavy-weight' whereas most classes in Swing are lightweight. Swing started in JDK 1.2. In

most versions of the JDK, you cannot mix AWT and Swing.

These brief notes are intended to explain what Swing is all about, and to provide brief code snippets

to enable you to quickly write GUI interfaces which work in typical ways.They are not a complete

reference - for that, look at the online API.

Useful Link

The Oracle Swing tutorials:

http://docs.oracle.com/javase/tutorial/ui/index.html

Page 156: Java

Java

Page 156 - Copyright © 2012 Walter Milner - all rights reserved

Starting a Swing application

Since Swing controls the user interface, it needs to handle keystrokes, mouse clicks and drags and so

on. These are treated as events, and you write pieces of code called event handlers to control what

happens when the user clicks a button and so on. This is described in detail later on.

When an application which uses Swing starts, an additional thread is started which receives and

dispatches events to the appropriate handler. This event dispatching thread is additional to the

initial application thread which runs main.

However Swing code is not threadsafe. This means the thread of main and the event-dispatching

thread are not synchronised, and deadlock between them is possible. This problem is solved if all

code to create and run the UI is done in the event dispatching thread. A class calledSwingUtilities has

a static method for doing this, which can be used like this, in code you would probably have in main:

SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } });

This defines an anonymous inner class which implements the Runnable interface, and passes an

instance of that to the invokeLater method. The createAndShowGUI is a method that you write,

possibly in the class that has main. For example:

class Test { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } static void createAndShowGUI() { MyFrame frame = new MyFrame("A Window"); } } class MyFrame extends JFrame { MyFrame(String title) { super(title); setBounds(0, 0, 400, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } }

In the listings which follow, we are mostly concerned with the frame constructor, and sometimes

extra methods in the MyFrame class for event-handling.

Exercise

Try this out.

Modify the frame's size and position.

Keep this as a template for Swing apps which follow.

Page 157: Java

Java

Page 157 - Copyright © 2012 Walter Milner - all rights reserved

Swing event handling

A GUI is not simply appearance - it has to react to user actions. For example, we need to supply code

so that something happens when a button is clicked. This is called event handling.

We will first see how this is done for button clicks, then look at events in general.

When a button is clicked, it generates an ActionEvent object. This is dealt with as follows:

1. When we create the button, we tell it where it should send its ActionEvent objects when it is

clicked. This is done using the addActionListener method.

2. The object which receives the ActionEvents must implement the ActionListener interface.

3. That interface has just one method, called actionPerformed. The actionPerformed method will be

executed when the button is clicked, so you write there what you want to happen when the button

is clicked.

This plan can be carried out in different ways - in particular, different choices of object for step 2.

This is often done using anonymous inner classes, which is rather obscure syntax. A simpler

approach is to have the container object - the JFrame - receive the ActionEvent clicks. As follows:

class MyFrame extends JFrame implements ActionListener { MyFrame(String title) { .. as before.. JButton button = new JButton("OK"); add(button); button.setBounds(5, 30, 80, 20); button.addActionListener(this); } public void actionPerformed(ActionEvent e) { System.out.println("You clicked"); } }

Now our frame implements the ActionListener interface, which is the actionPerformed method. We

have told the button to addActionListener this - so its ActionEvents will be sent to the frame object,

and its actionPerformed method is called.

Which Button?

Suppose we have more than one button - which is usually the case. They will often call the same

actionPerformed method. How do we tell which button was clicked? The ActionEvent class has a

getSource() method to tell us who produced the event. We need to make the buttons data

members, not local:

Page 158: Java

Java

Page 158 - Copyright © 2012 Walter Milner - all rights reserved

class MyFrame extends JFrame implements ActionListener { JButton okButton, cancelButton; MyFrame(String title) { .. as before .. okButton = new JButton("OK"); add(okButton); okButton.setBounds(5, 30, 80, 20); okButton.addActionListener(this); cancelButton = new JButton("Cancel"); add(cancelButton); cancelButton.setBounds(90, 30, 80, 20); cancelButton.addActionListener(this); } public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == okButton) { System.out.println("OK"); } if (source == cancelButton) { System.out.println("Cancel"); } } }

Event handling in general

ActionEvent is a subclass of AWTEvent. This is a superclass with classes of types of events of

different kinds - for example, a MouseEvent, a MouseWheelEvent, a KeyEvent and a WindowEvent,

the latter happening when a window is closed, resized, restored and so on. These are all handled in a

similar way. Their events are passed to an object which implements the appropriate Listener

interface. A getSource() can distinguish events coming from different widgets.

Widgets actually maintain a list of objects to notify. So when a button is clicked, it can notify a set of

objects. This is why the method is addActionListener rather than setActionListener.

Two examples follow. The first outputs the x and y pixel positions of the mouse as it moves over the

frame:

class MyFrame extends JFrame implements MouseMotionListener { MyFrame(String title) { .. as before.. addMouseMotionListener(this); } public void mouseDragged(MouseEvent e) { } public void mouseMoved(MouseEvent e) { System.out.println(e.getX()+ " "+e.getY()); } }

Second example - when the window close button is clicked, the user must enter q to quit. This is a

useful approach, checking if the user really wants to quit, save work and so on:

Page 159: Java

Java

Page 159 - Copyright © 2012 Walter Milner - all rights reserved

class MyFrame extends JFrame implements WindowListener { MyFrame(String title) { ..as before.. setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); .. as before.. addWindowListener(this); } public void windowOpened(WindowEvent e) { } public void windowClosing(WindowEvent e) { System.out.println("Enter q to quit"); Scanner scanner=new Scanner(System.in); String s = scanner.nextLine(); if (s.equals("q")) System.exit(0); } public void windowClosed(WindowEvent e) { } public void windowIconified(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowActivated(WindowEvent e) { } public void windowDeactivated(WindowEvent e) { } }

Using adapter classes

In the last example, the WindowListener interface has seven methods, and we are only doing

something in one of them. To make for less typing, we can use an instance of a sub-class of the

abstract WindowAdapter, just implementing the methods we want to. This is often done by making

the object to be an instance of an anonymous inner class - like this:

addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.out.println("Enter q to quit"); Scanner scanner = new Scanner(System.in); String s = scanner.nextLine(); if (s.equals("q")) { System.exit(0); } } });

This is in place of addWindowListener(this); and the frame no longer implements WindowListener.

Instead ..new WindowAdapter().. defines an anonymous sub-class of WindowAdapter, and creates

an instance of it to deal with the WindowEvents.

Page 160: Java

Java

Page 160 - Copyright © 2012 Walter Milner - all rights reserved

Exercise

Program a JFrame with a JButton. When the button is clicked, the application should end.

Page 161: Java

Java

Page 161 - Copyright © 2012 Walter Milner - all rights reserved

Swing containers

Swing provides various features to enable you to organise components in a frame as you want. We

look at JPanels as a basic building block, borders, the idea of a containment hierarchy, the top-level

containers, layout managers, tabbed panes and split panes.

JPanels and Borders

A JPanel is a rectangular area which can be used to divide a frame by adding the panels to the frame.

We can also add panels to panels, making the layout structure as intricate as is needed. We need to

take the layout manager into account - this is software which controls the size and position of

components. The default for a JFrame is BorderLayout, and for a JPanel, FlowLayout, which adds

components in rows. But this can be changed by setLayout().

Borders can also be added to JPanels - and most components. To get a border, use a method from

the static BorderFactory class. The idea is that if you use three thin blue borders in your application,

in fact only one will be constructed by the BorderFactory, and you will share the instances.

The example shows the use of a compound border, with the outer border being empty. This can be

used to establish 'padding' around components:

MyFrame(String title) { super(title); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); // make panels top = new JPanel(); bottom = new JPanel(); // set sizes top.setPreferredSize(new Dimension(100, 100)); bottom.setPreferredSize(new Dimension(100, 100)); // add to frame add(top, BorderLayout.NORTH); add(bottom, BorderLayout.SOUTH); // put labels in panels top.add(new JLabel("Top")); bottom.add(new JLabel("Bottom")); // make and set borders Border redBorder=BorderFactory.createLineBorder(Color.red, 1); Border blankBorder=BorderFactory.createEmptyBorder(5,5,5,5); Border joint = BorderFactory.createCompoundBorder(blankBorder, redBorder); top.setBorder(joint); pack(); }

Adding components to a JPanel

We can create a JPanel and add it to the window. Then we can create components and add them to

the panel (not the window):

Page 162: Java

Java

Page 162 - Copyright © 2012 Walter Milner - all rights reserved

MyFrame(String title) { .. as before.. // set up a panel on the left JPanel yellow = new JPanel(); add(yellow); yellow.setBounds(0,0,125,100); yellow.setBackground(Color.YELLOW); // add a label to it JLabel label = new JLabel("Enter a number"); label.setBounds(5, 5, 100, 20); yellow.add(label); // set up a panel on the right JPanel red = new JPanel(); add(red); red.setBounds(125,0,125,100); red.setBackground(Color.RED); // add a textfield to it JTextField textField = new JTextField("1234"); red.add(textField); textField.setBounds(110, 5, 100, 20); }

The Containment Hierarchy

In the above example, the JFrame contains two JPanels, because we have

added them. In turn, the left JPanel contains a JLabel, and the right

contains a JTextField.

Swing uses this concept in general, with all components being contained

in other components. Only at the top of each containment tree do we

find a top level container, which in this case is a JFrame.

Top level containers

There are three useful top level containers JFrame, JDialog and JApplet. The first we have already

seen. A JDialog is suitable for use as a dialog box and is described later . A JApplet will contain an

applet, normally inside a browser window.

There is a fourth, but it is usually excluded from the useful list. This is a

JWindow. This is a plain rectangle, with no title bar, re-sizing handles, nor

close minimize restore buttons. So not very useful.

On JDK 7, on some platforms, you can have translucent and non-

rectangular windows.

JRootPane and components

JFrame and the other top-level containers is actually slightly more

complicated than it appears. In detail,

A JFrame has a JRootPane

A JRootPane has glassPane and a Layered Pane

A LayeredPane has a contentPane, and maybe a MenuBar

Usually we are only interested in the contentPane -the area inside the window where things will be

shown. When we place a JLabel in a JFrame, it is added to the contentPane:

Containment hierarchy

JRootPane and elements

Page 163: Java

Java

Page 163 - Copyright © 2012 Walter Milner - all rights reserved

frame.getContentPane().add(label);

Since this is so common, the add method of JFrame does this for you, so you can just say

frame.add(label);

with the same effect.

Menu bars are easy to use - they are described elsewhere.

The glassPane usually does nothing. It can be used to intercept mouse events before they reach the

frame components, and you can draw on the glassPane (and therefore over frame components),

provided you make it visible.

Using the glassPane

For example, the following gets the glassPane, and makes it intercept

mouse movements. In response it draws on the glassPane tracking

the mouse. The mouse events interception only works if the

glassPane is setVisible(); which might not be expected:

class MyFrame extends JFrame implements MouseMotionListener { Component glassPane; MyFrame(String title) { ..as before.. glassPane = getGlassPane(); glassPane.setVisible(true); glassPane.addMouseMotionListener(this); } public void mouseDragged(MouseEvent e) { } int lastMouseX = -1; int lastMouseY = -1; public void mouseMoved(MouseEvent e) { int mouseX = e.getX(); // where's the mouse int mouseY = e.getY(); if (lastMouseX == -1) { // if first time, last mouse is here as well lastMouseX = mouseX; } if (lastMouseY == -1) { lastMouseY = mouseY; } Graphics g = glassPane.getGraphics(); // get a graphics context g.drawLine(lastMouseX, lastMouseY, mouseX, mouseY); lastMouseX = mouseX; //ready for next time lastMouseY = mouseY; } }

This consumes the mouse event, and the underlying button does not receive it. If you want to pass it

on, you have to work out if the mouse is over the button, and if so, construct a suitable event and

send it on. See

http://download.oracle.com/javase/tutorial/uiswing/components/rootpane.html

Drawing on the glassPane

Page 164: Java

Java

Page 164 - Copyright © 2012 Walter Milner - all rights reserved

Layout Managers

Previously we have used setBounds() to position components with pixel co-ordinates and sizes. This

is not recommended. The size of a pixel depends on the resolution of the display, and so your

components will be smaller on a higher resolution screen. Instead it is better to use a

LayoutManager. There is a choice of these, and they place components in different patterns - or you

can write your own. We will just look at two.

BorderLayout

This is the default for a JFrame. Components can be placed in one of five

positions, named north south east west and center. For example:

class MyFrame extends JFrame { MyFrame(String title) { super(title); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); JButton okButton = new JButton("OK"); add(okButton, BorderLayout.WEST); JButton cancelButton = new JButton("Cancel"); add(cancelButton, BorderLayout.EAST); pack(); } }

We have not set a layout manager, so we get the default BorderLayout. We have not sized the frame

or the components, but we have called pack(). This calculates the "preferred sizes" of the

components, sizes them to that, positions them, and calculates the minimum size of the frame.

The five locations may seem to be limiting. But you can add panels to the frame, then components

to the panels, and so on.

GridBagLayout

Some say GridBagLayout is one of the more complicated layout managers,

but it is very flexible and effective. Components are placed in cells in rows

and columns. You use an instance of GridBagConstraints when you add a

component. This has fields gridx and gridy which fix which column and row

it goes in - top left cell is (0,0). You can fix the alignment with .anchor EAST or WEST and so on. For a

large component, you can make it use more than one row or column using gridWidth or gridHeight.

And you can space out components using insets. For example:

setLayout(new GridBagLayout()); GridBagConstraints gc = new GridBagConstraints(); gc.insets = new Insets(5, 5, 5, 5);// everything has a 5 pixel border JLabel label1 = new JLabel("Name"); gc.gridx = 0; // top left gc.gridy = 0; gc.anchor = GridBagConstraints.EAST; // aligned right add(label1, gc); // add it

The whole thing is:

Using BorderLayout

GridBagLayout

Page 165: Java

Java

Page 165 - Copyright © 2012 Walter Milner - all rights reserved

MyFrame(String title) { super(title); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); setLayout(new GridBagLayout()); GridBagConstraints gc = new GridBagConstraints(); gc.insets = new Insets(5, 5, 5, 5); // top row JLabel label1 = new JLabel("Name"); gc.gridx = 0; gc.gridy = 0; gc.anchor = GridBagConstraints.EAST; add(label1, gc); JTextField name = new JTextField(""); name.setPreferredSize(new Dimension(100, 20)); gc.gridx = 1; gc.gridy = 0; gc.anchor = GridBagConstraints.WEST; add(name, gc); // row 2 JLabel label2 = new JLabel("Date of birth"); gc.gridx = 0; gc.gridy = 1; gc.anchor = GridBagConstraints.EAST; add(label2, gc); JTextField dob = new JTextField(""); dob.setPreferredSize(new Dimension(100, 20)); gc.gridx = 1; gc.gridy = 1; gc.anchor = GridBagConstraints.WEST; add(dob, gc); JButton okButton = new JButton("OK"); gc.gridx = 0; gc.gridy = 2; // row 3 gc.anchor = GridBagConstraints.CENTER; add(okButton, gc); JButton cancelButton = new JButton("Cancel"); gc.gridx = 1; gc.gridy = 2; gc.anchor = GridBagConstraints.CENTER; add(cancelButton, gc); pack(); }

JTabbedPane

A tabbed pane produces a set of panes accessible via a 'tab'. This

means that a lot of interface can be there in a small area - though

you can't see more than one at a time.

The sequence is simply:

1. Construct a JTabbedPane

2. Construct components, and add them as tabs to the tabbed pane. These might be JPanels

3. Add the Tabbed pane to the outer container.

For example:

JTabbedPane

Page 166: Java

Java

Page 166 - Copyright © 2012 Walter Milner - all rights reserved

JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); JPanel panel1 = new JPanel(); tabbedPane.addTab("One", panel1); JPanel panel2 = new JPanel(); tabbedPane.addTab("Two", panel2); .. add(tabbedPane);

and of course you would add components to the panels.

As well as text labels for tabs, you can have icons as well. So if 'one' is an

ImageIcon, you can say

tabbedPane.addTab("",one, panel1);

and so on.

JSplitPane

A JSplitPane object does what the name suggests - it splits a container

into two parts, and has the functionality to allow the user to control the

split. You would typically:

1. Make the things which would be the left and right components -

typically, JPanels. You would probably add components to those two

panels.

2. Construct the JSplitPane, with the two panels as arguments.

3. Add the JSplitPane to the enclosing container - the one you are splitting.

For example - the left component will be a scroll pane enclosing a JList

JScrollPane listScroller = new JScrollPane(list);

and the right is just a JPanel:

JPanel rightPane = new JPanel(); rightPane.setBackground(Color.yellow); JLabel lab1= new JLabel("Right pane"); rightPane.add(lab1);

Then make the split pane:

JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, listScroller, rightPane);

and add it - this is in the constructor of a subclassed JFrame:

add(splitPane);

Some code configures this, with obvious meaning:

Icons for tab labels

JSplitPane

Page 167: Java

Java

Page 167 - Copyright © 2012 Walter Milner - all rights reserved

splitPane.setOneTouchExpandable(true); splitPane.setDividerLocation(150); Dimension minimumSize = new Dimension(100, 50); listScroller.setMinimumSize(minimumSize); rightPane.setMinimumSize(minimumSize);

For a three-way split, nest them. For example, you might split a frame vertically, then split the top

pane horizontally.

Exercise

Program a JFrame which has 2 panels, left and right. Use MouseMotionListener so the user can draw

freehand lines on the right panel. The left panel should have a JButton saying 'Clear', which when

clicked will remove the drawing on the right.

Page 168: Java

Java

Page 168 - Copyright © 2012 Walter Milner - all rights reserved

Swing widgets

These are the things which are placed on the containers, and most of them react to user actions.

They include

JLabel A label - text (or image) which the user cannot change

JTextField A box in which the user can type text input

JTextArea Like a JTextField with more than one row

JButton A clickable button

JCheckBox A small box for yes or no

JRadioButton These come in groups - only one out of the group is selected

JList, JComboBox, JTable

See later.

JLabel

For example

class MyFrame extends JFrame { JLabel label = new JLabel("Label here"); MyFrame(String title) { .. setLayout(null); add(label); label.setBounds(5, 5, 100, 20); label.setForeground(Color.red); } }

JTextField and JButton

class MyFrame extends JFrame implements ActionListener { JTextField textField = new JTextField("Type here"); JButton button = new JButton("Click me"); MyFrame(String title) { .. setLayout(null); add(textField); textField.setBounds(5, 5, 100, 20); add(button); button.setBounds(5,30,100,20); button.addActionListener(this); } public void actionPerformed(ActionEvent e) { String text = textField.getText(); JOptionPane.showMessageDialog(null, text,"You typed..", JOptionPane.INFORMATION_MESSAGE); } }

This repeats how you use ActionListener and actionPerformed to respond to button clicks. Use

getText() to retrieve the text from a JTextField. JOptionPane displays a message in a dialog box.

Page 169: Java

Java

Page 169 - Copyright © 2012 Walter Milner - all rights reserved

JCheckBox

For example:

class MyFrame extends JFrame implements ActionListener { JCheckBox check = new JCheckBox("Check"); MyFrame(String title) { .. setLayout(null); add(check); check.setBounds(5, 30, 100, 20); check.addActionListener(this); } public void actionPerformed(ActionEvent e) { boolean state = check.isSelected(); JOptionPane.showMessageDialog(null, "" + state, "CheckBox selected?", JOptionPane.INFORMATION_MESSAGE); } }

JRadioButton

This is slightly different in that you have to add them to a ButtonGroup:

class MyFrame extends JFrame implements ActionListener { JRadioButton but1 = new JRadioButton("One"); JRadioButton but2 = new JRadioButton("Two"); JRadioButton but3 = new JRadioButton("Three"); MyFrame(String title) { .. setLayout(null); add(but1); but1.setBounds(5, 5, 100, 20); but1.addActionListener(this); add(but2); but2.setBounds(5, 30, 100, 20); but2.addActionListener(this); add(but3); but3.setBounds(5, 55, 100, 20); but3.addActionListener(this); ButtonGroup group = new ButtonGroup(); group.add(but1); group.add(but2); group.add(but3); } public void actionPerformed(ActionEvent e) { JRadioButton but = (JRadioButton) e.getSource(); JOptionPane.showMessageDialog(null, but.getText(), "You chose..", JOptionPane.INFORMATION_MESSAGE); } }

Page 170: Java

Java

Page 170 - Copyright © 2012 Walter Milner - all rights reserved

Images

Swing has a class called ImageIcon which can be used to place images on

labels and other components. For example:

MyFrame(String title) { super(title); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); ImageIcon icon = new ImageIcon("c:/temp/baby.jpg"); JLabel label = new JLabel(icon); add(label); pack(); }

This is very simple, but there is a problem in that an absolute pathname to the image file is given.

The code above works if the file is in the folder called temp on drive c - but in a typical deployment

of an application, you cannot place a file in a fixed folder on the user's

computer. We need to be able to somehow place the file in the application

and refer to it there.

There are three steps to this:

1. Place the image file in a suitable folder within the folder holding the

source code .java files for the relevant package. For example, this is in a

package called test, so we could place the image in a sub-folder of test called images.

2. Use a classloader to get the location relative to where the class files will be loaded from:

package test; import .. class Test { public static void main(String[] args) { .. } .. } class MyFrame extends JFrame { JPanel top, bottom; MyFrame(String title) { super(title); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); ClassLoader cldr = this.getClass().getClassLoader(); java.net.URL imageURL = cldr.getResource("test/images/baby.jpg"); ImageIcon icon = new ImageIcon(imageURL); JLabel label = new JLabel(icon); add(label); pack(); } }

Here, cldr is the class loader which will load the MyFrame class file. Its getResource method gets a

location URL for the file named baby.jpg, in the folder called images in the package called test.

Image on label

Source code image placement in NetBeans

Folders after compiling

Page 171: Java

Java

Page 171 - Copyright © 2012 Walter Milner - all rights reserved

3. When this is compiled (or Run in NetBeans), in the classes folder of the build folder, there will be

a folder named test to hold the package, and it will contain the class file, and a sub-folder called

image with the image file in it.

If this is jar'd (in NetBeans, Run Clean and Build) this produces a .jar file (in NetBeans, in the dist

folder) which contains the image file.

Images from the net

Alternatively, image files can be downloaded from the net, very simply:

class MyFrame extends JFrame { MyFrame(String title) { .. try { URL imageURL = new URL("http://p.ebaystatic.com/aw/pics/logos/logoEbay_x45.gif"); ImageIcon icon = new ImageIcon(imageURL); JLabel label = new JLabel(icon); add(label); } catch (MalformedURLException ex) { } pack(); } }

Exercise

Extend this to a small 'image gallery' with 3 or 4 images. One solution would be to have a

corresponding set of JLabels. 'Next' and 'Previous' buttons would change the setBounds of the labels

so the appropriate one was visible.

Image from the net

Page 172: Java

Java

Page 172 - Copyright © 2012 Walter Milner - all rights reserved

Color

Color is a class, with objects representing colours. We can

construct a new colour by supplying red, green and blue

components as floats in the range 0 to 1, like

Color c = new Color(1.0f, 0.5f, 0.1f);

1.0f is a float constant, while 1.0 is type double.

Or there are a set of constant named colours, like

Color c = Color.GREEN;

Swing components have methods setBackground and setForeground to set the colours (not all

components have backgrounds and foregrounds). For example:

class MyFrame extends JFrame { MyFrame(String title) { .. as before .. JLabel label = new JLabel("Enter a number"); add(label); Color c1 = new Color(1.0f, 0.5f, 0.1f); label.setForeground(c1); label.setBounds(5, 5, 100, 20); JTextField textField = new JTextField("1234"); Color c2 = Color.GREEN; textField.setBackground(c2); add(textField); textField.setBounds(110, 5, 100, 20); } }

Exercise

A JFrame can be translucent provided-

1. The underlying OS allows it

2. The window is setUndecorated(true); before being made visible.

3. It is not full-screen

Then the opacity is set by setOpacity(float);

Try this out.

Using Color

Page 173: Java

Java

Page 173 - Copyright © 2012 Walter Milner - all rights reserved

Fonts

An instance of the Font class represents a font. The main issue is that fonts are installed locally, so

there is no guarantee that a specific font will be available. This is addressed by having two kinds -

'logical' and 'physical'. The logical fonts are a basic set of generic fonts - Dialog, DialogInput,

Monospaced, Serif and SansSerif, while the physical fonts are actual fonts installed on the user's

machine. You can instantiate one of the logical fonts as in this example:

Font font = new Font("Dialog", Font.PLAIN, 12);

and then use the setFont method to apply it to a component, such as

label.setFont(font);

The same is true of the physical fonts, but you have to ensure that the font you want is actually

available. A reasonable approach is to have a set of fonts which you would prefer to use, in order,

and use a logical font as the fallback if none are present - as usual in a style sheet on a web page. For

example:

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); String fontName = "SansSerif"; String f[] = ge.getAvailableFontFamilyNames(); String[] wantedFonts = {"Code2000","Linux Libertine","DejaVu Sans" }; boolean gotFont = false; for (int j = 0; j < wantedFonts.length; j++) { for (int i = 0; i < f.length; i++) { if (f[i].equals(wantedFonts[j])) { fontName = wantedFonts[j]; gotFont = true; break; } } if (gotFont) break; } Font font = new Font(fontName, Font.PLAIN, 16); JLabel label = new JLabel("αβγδεζگڳڳڳڳڱڱ in " + fontName); label.setFont(font); add(label);

This example shows two other points. Firstly, since Java uses Unicode for characters and strings, it

can display a very large set of characters - although the range of displayable characters depends on

the font.

Secondly, such characters can be used in source code for identifiers and string constants. Whether

you can see them depends on which font your editor uses in your IDE - which will be an option you

can change. Otherwise you can represent Unicode characters as constants like \u0061 for lower case

'a'.

Exercise

Try this out.

Try different fonts.

Unicode font

Page 174: Java

Java

Page 174 - Copyright © 2012 Walter Milner - all rights reserved

Menus, Popups andToolbars

Making a basic menu

Follow these steps

1. Make a menubar, and add it to the frame (or whatever)

2. Make a menu, and add it to the menubar

3. Make menu items, and add them to the menu

Repeat steps two and three for as many menus as you want.

For example:

JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); JMenu menu1 = new JMenu("Menu One"); menuBar.add(menu1); JMenuItem item1 = new JMenuItem("Option One"); menu1.add(item1); JMenuItem item2 = new JMenuItem("Option Two"); menu1.add(item2); JMenu menu2 = new JMenu("Menu Two"); menuBar.add(menu2); JMenuItem item3 = new JMenuItem("Option Three"); menu2.add(item3); JMenuItem item4 = new JMenuItem("Option Four"); menu2.add(item4);

Making the menu work

JMenuItems are in fact sub-classed JButtons, and so they use the ActionListener interface and you

can treat them like ordinary buttons. This means your JMenuItems would need to be data fields not

local to the constructor, so the actionPerformed can refer to them. So we modify the above:

.. item1 = new JMenuItem("Option One"); menu1.add(item1); item1.addActionListener(this); .. public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source==item1) .. whatever }

Elaborating Menus

You can add menuItems to menu bars. Or you can add menus to menus,

giving submenus.

You can have icons as well as text labels in menuItems.

You can have a menu separator.

Basic menu

Elaborated menu

Page 175: Java

Java

Page 175 - Copyright © 2012 Walter Milner - all rights reserved

You can have checkboxes and radio buttons in menus.

For example, where 'one' is an ImageIcon:

JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); JMenu menu1 = new JMenu("Menu One"); menuBar.add(menu1); item1 = new JMenuItem("Option One"); menu1.add(item1); item1.addActionListener(this); JMenuItem item2 = new JMenuItem("Option Two", two); menu1.addSeparator(); menu1.add(item2); JCheckBox cb = new JCheckBox("Yes or no"); menu1.add(cb);

Popup Menus

Popup menus, which appear floating somewhere in a frame (uually where the mouse was clicked)

are excellent. They involve less mouse movement than having to go up to the menu bar, and they

can be context-dependent - that is, if the user right-clicks on a particular thing, they get a menu just

relevant to that thing.

You make a popup menu and add items to it very simply:

popup = new JPopupMenu(); JMenuItem menuItem = new JMenuItem("A popup menu item"); popup.add(menuItem); JMenuItem menuItem2 = new JMenuItem("Another popup menu item"); popup.add(menuItem2);

To make it work, you have to do two things - get the menu to pop up, and get responses to menu

selections. The first is done using a mouse listener. For example:

addMouseListener(this); .. public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON3) { popup.show(e.getComponent(), e.getX(), e.getY()); } }

which means the popup appears if they right-click. The e.getX() and e.getY mean the menu will

appear where they clicked.

To make the menu work - the JMenuItems are subclassed JButtons, so use actionListener just as for

menu bars.

Menu design issues

Users often complain they cannot 'find' things. This happens when there is a large and complex

menu, with many levels, and items are not logically placed. For example, in Word 2003 and before

you inserted a header through View in the menu, which is hardly logical.

Some suggestions are:

Page 176: Java

Java

Page 176 - Copyright © 2012 Walter Milner - all rights reserved

1. Order top level items as expected - File Edit …..Help. In File have New, Open, Save, Save as, Close

and Exit. This obviously depends on the application, but keep it as close to this - which users will

expect - as possible.

2. Use separators to group items logically.

3. If your menus are four deep - find another way.

ToolBars

Toolbars are rows of buttons, which can 'float' in their own window, or will 'dock' at the edge of a

container. Instantiate a JToolBar, make and add JButtons to it, then add the toolbar to a container

using BorderLayout. The JButtons would normally show icons, but text is possible. The JButtons use

actionPerformed. For example:

ClassLoader cldr = this.getClass().getClassLoader(); java.net.URL imageURL = cldr.getResource("test/images/Edit24.gif"); ImageIcon one = new ImageIcon(imageURL); .. JToolBar toolBar = new JToolBar("Tools"); JButton butt1 = new JButton(one); .. toolBar.add(butt1); .. add(toolBar, BorderLayout.NORTH);

Initial toolbar Docked on the left Dragged to new window

Page 177: Java

Java

Page 177 - Copyright © 2012 Walter Milner - all rights reserved

Swing and MVC

Widgets hold data. For some, the data is very simple. For a JCheckBox, it is little more than whether

it has been checked. For a textfield, it is the text in it. But for others - such as lists, comboboxes and

tables - they hold an amount of structured data. How to deal with this?

One idea is MVC : model - view - controller. The model is the underlying data which the widget has -

as distinct from how it is seen on screen. The view is the screen appearance of the widget and its

data. The controller is the coding which determines how user input alters the data and view.

There is some debate about whether Swing widgets are MVC-based. This

article from Oracle:

http://java.sun.com/products/jfc/tsc/articles/architecture/

shows that the design started as MVC, and developed from there.

JLists

A JList displays a list of items from which a choice can be made. The list

shown was produced by this code:

setLayout(null); String[] data = {"one", "two", "three", "four", "five", "six"}; JList list = new JList(data); list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); list.setLayoutOrientation(JList.VERTICAL_WRAP); list.setVisibleRowCount(-1); JScrollPane listScroller = new JScrollPane(list); listScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); add(listScroller, BorderLayout.CENTER); listScroller.setBounds(20, 20, 100, 120);

There are three aspects to JLists:

1. How the data in the list is controlled : the model

2. How the list, and cells in it, are displayed : the view

3. How items are selected : view/controller

4. How events are handled

The JList models

It seems as if the data is somehow 'in' the list. In fact the data is held in a

separate object. If you construct the list with an array or Vector as constructor

argument, the JList makes the data model for you, as an instance of class

DefaultListModel. For example

Vector<Integer> numbers = new Vector<Integer>(); numbers.add(new Integer(1)); numbers.add(new Integer(41)); numbers.add(new Integer(1)); JList list = new JList(numbers);

A JList

Vector as model

Page 178: Java

Java

Page 178 - Copyright © 2012 Walter Milner - all rights reserved

However in this simple case the model is fixed - you cannot add or remove items

from the list.

An alternative is to construct an instance of DefaultListModel, and construct the

JList with that as parameter:

DefaultListModel<String> model = new DefaultListModel<String>(); model.addElement("One"); model.addElement("Two"); model.addElement("Three"); JList list = new JList(model); .. JScrollPane listScroller = new JScrollPane(list); add(listScroller); model.addElement("Four");

This shows how the data can be changed after the list is created, and the visual display is updated to

reflect the change.

Thirdly you can construct a JList based on an object which implements the ListModel interface. This

can be a sub-class of the AbstractListModel class, or your own class which implements ListModel.

For example, wrapping an ArrayList of Strings:

class MyListModel extends AbstractListModel { private ArrayList<String> data; MyListModel(ArrayList<String> data) { this.data=data; } void addElement(String s) { data.add(s); } @Override public int getSize() { return data.size(); } @Override public Object getElementAt(int index) { return data.get(index); } }

used as:

ArrayList<String> data = new ArrayList<String>(); data.add("One"); data.add("Two"); data.add("Three"); MyListModel model = new MyListModel(data); JList list = new JList(model); .. JScrollPane listScroller = new JScrollPane(list); .. model.addElement("Four");

JList appearance and CellRenderer

There are three possible ways in which cells are laid out in a JList. The default is a simple vertical list.

VERTICAL_WRAP means list vertically, and start a new colum to the right if needed.

HORIZONTAL_WRAP means list horizontally, and start a new row if needed. These are selected by

for example

DefaultListModel

A sub-classed AbstractListModel

Page 179: Java

Java

Page 179 - Copyright © 2012 Walter Milner - all rights reserved

list.setLayoutOrientation(JList.HORIZONTAL_WRAP);

VERTICAL VERTICAL_WRAP HORIZONTAL_WRAP

It is also possible to create a cell renderer to draw cells other than in the default way. This is done by

implementing the ListCellRenderer interface. An instance of this is called by the list when it needs to

draw a cell. The renderer must return a component suitable for use as a cell.

In the example, the component is a sub-classed JLabel. The method passes in

parameters for the value of the data in the cell, its index, and whether the cell

is selected or has the focus. This means the cell can get suitable formatting. In

the example screen shot, cells 2 and 3 are selected, and cell 3 has the focus:

.. list.setCellRenderer(new MyCellRenderer()); .. class MyCellRenderer extends JLabel implements ListCellRenderer { static Border b= BorderFactory.createLineBorder(Color.blue, 1); MyCellRenderer() { setOpaque(true); } @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { setText(value.toString()); setBackground(new Color(index*80%256,0,0)); if (isSelected) setBackground(Color.pink); if (cellHasFocus)setBorder(b); else setBorder(null); setForeground(Color.white); return this; } }

Just as the data in the list is held in a list model, those items which are selected are held by a

ListSelectionModel. You could write your own, but the interface has many methods. Instead the

default one will probably suffice. setSelectionMode controls whether the user can select one item, a

range, or several ranges. Get and setSelectedIndices allow you to get an array of indexes of items

which are selected, or to select such a set.

When the user changes the selection, a ListSelectionEvent is produced. The ListSelectionListener has

just one method, value changed. For example, to output on the console all selected items when

there is any change:

Cell renderer

Page 180: Java

Java

Page 180 - Copyright © 2012 Walter Milner - all rights reserved

.. list.addListSelectionListener(this); .. public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting() == false) { int[] selected = list.getSelectedIndices(); for (int i = 0; i < selected.length; i++) { System.out.println(list.getModel().getElementAt(selected[i])); } } }

To explain the println,

list.getModel(). gets the data in the list

.getElementAt gets one item from the data

(selected[i])); is the index of the ith. item selected

For example, if items 0,3 and 9 were selected, the select array would have elements 0 3 and 9.

Exercise

Code and test a basic JList containing Integers

Write a cell renderer so that cells containg 10 or more are in pink, and the selected cell is red.

JList as MVC

A Jlist actually has three associated objects

(which may be defaults or ones we have written)

- the list model, the selection model and the cell

renderer. There is also likely to be a

valueChanged method somewhere which

responds to selection changes. The diagram casts

these into the MVC architecture. There is no

precision about this. The important point is that

the model holds the 'real'

underlying data, and the view

shows this on screen

JList as MVC

Page 181: Java

Java

Page 181 - Copyright © 2012 Walter Milner - all rights reserved

Inheritance - a GUI Tic Tac Toe

Suppose we want to a game of Tic Tac Toe in a GUI context, like:

The user will click on a cell to 'go' there. So the cells are like buttons - but with extra, since each cell

somehow has to know which row and column it is in. The easiest way to program this is to start with

an existing class, in this case a JButton, and extend it by using the idea of inheritance. Similarly the

main window of the game will be an extension of the basic JFrame.

The idea of inheritance is to take an existing class, called the base class or super class, and extend or

subclass it to produce a modified class. The modified class inherits all members (fields and methods)

of the base class. However these can be altered, or we can add extra members. Constructors are not

inherited - we have to write our own constructor for the sub-class. However we can call super(); as

the first statement in the constructor, and this calls the constructor of the super class, doing most of

the work for us.

The idea of inheritance is to re-use code - existing code can easily be re-used and built upon.

Dynamics of GUI apps

The character-based Tic Tac Toe game illustrated how such applications execute. There is some

output, then the screen is refreshed. This loop is repeated until somehow it ends.

In a GUI app, the user expects a lot more freedom. In the middle of the game they might resize or

minimise it, or switch to a different application for a while.

This means a different approach is needed. The application needs to somehow set up an initial

screen (normally a window). It must then 'sit back' and wait for the user to do things, and respond

appropriately. In other words it must set up event-handlers to deal with user-initiated events.

Most of those (moving the window, re-sizing it, minimizing and restoring it) are handled by existing

methods in the base class (the JFrame). The event we do need to handle is a click on one of the cells.

Class design in a GUI context

The classes in this app can be a modification of those in the character-based version:

Game - to contain main, and start things off.

Board - to represent the board on which the game is played. This will be a sub-classed JFrame

Human - the human player

Computer - the computer player

Cell - a sub-classed JButton, one of the 9 cells in the game.

Page 182: Java

Java

Page 182 - Copyright © 2012 Walter Milner - all rights reserved

These are all singleton classes except for Cell, which will have 9 instances.

The Game class

package GUIttt; public class Game { // data fields private Board board; private Human human; private Computer computer; // constructor private Game() { // create the 3 objects which are part of a Game object human = new Human(); computer = new Computer(); board = new Board(human,computer); computer.setBoard(board); } public static void main(String[] args) { Game game = new Game(); //make a game } }

This instantiates a single Game object. This just creates the human, computer and board objects. The

board needs references to the human and the computer, so it can give them a go. The computer

needs a reference to the board so it can check which cells are free.

There is no turn-taking in this. That is effectively handled by the board.

The Board class

A key data field of the board class is a 3 by 3 array of TTTCells. These are sub-classed JButtons. When

the user clicks on one of these, the actionPerformed method is triggered. This makes one turn to

happen - the user's go is marked, we check if they've won, the computer goes, we check if they've

won. Then the turn ends.

Page 183: Java

Java

Page 183 - Copyright © 2012 Walter Milner - all rights reserved

package GUIttt; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JFrame; import javax.swing.JLabel; class Board extends JFrame implements ActionListener { // data members private TTTCell cells[][] = new TTTCell[3][3]; private Human human; private Computer computer; private JLabel label; private boolean gameOver; // construct a board Board(Human human, Computer computer) { // construct base class super("Tic Tac Toe"); setBounds(50, 50, 220, 230); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); this.human = human; this.computer = computer; gameOver = false; // create cell grid for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { cells[i][j] = new TTTCell(); cells[i][j].addActionListener(this); } } // add and position cells setLayout(null); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { add(cells[i][j]); cells[i][j].setBounds(50 * i, 50 * j, 50, 50); } } label = new JLabel(); add(label); label.setBounds(0, 150, 150, 20); } public void actionPerformed(ActionEvent e) { if (!gameOver) { human.go(e); checkWin('X'); computer.go(); checkWin('O'); } } // mark an 'X' or 'O' void set(int i, int j, char c) { // check is valid if (i > -1 && i < 3 && j > -1 && j < 3 && (c == 'O' || c == 'X')) { cells[i][j].setContents(c); } } char getCell(int r, int c) { return cells[r][c].getContents(); } // set gameOver if someone's won void checkWin(char c) { boolean result = false; //check rows

Page 184: Java

Java

Page 184 - Copyright © 2012 Walter Milner - all rights reserved

if (cells[0][0].getContents() == c && cells[0][1].getContents() == c && cells[0][2].getContents() == c) { result = true; } if (cells[1][0].getContents() == c && cells[1][1].getContents() == c && cells[1][2].getContents() == c) { result = true; } if (cells[2][0].getContents() == c && cells[2][1].getContents() == c && cells[2][2].getContents() == c) { result = true; } //check columns if (cells[0][0].getContents() == c && cells[1][0].getContents() == c && cells[2][0].getContents() == c) { result = true; } if (cells[0][1].getContents() == c && cells[1][1].getContents() == c && cells[2][2].getContents() == c) { result = true; } if (cells[0][2].getContents() == c && cells[1][2].getContents() == c && cells[2][2].getContents() == c) { result = true; } // leading diagonal if (cells[0][0].getContents() == c && cells[1][1].getContents() == c && cells[2][2].getContents() == c) { result = true; } //other diagonal if (cells[0][2].getContents() == c && cells[1][1].getContents() == c && cells[2][0].getContents() == c) { result = true; } if (result) { { gameOver = true; label.setText("Game over"); } } } }

The Human class

package GUIttt; import java.awt.event.ActionEvent; class Human { //invoked when human clicks a cell void go(ActionEvent e) { TTTCell whichCell = (TTTCell) (e.getSource()); whichCell.setContents('X'); } }

The single method in this, go, is called when a Cell is clicked. From that event-handler, an

ActionEvent object is passed. This has a getSource method - we can use it to find out which cell was

clicked. We then set that to an X. The board checks if we have won.

Page 185: Java

Java

Page 185 - Copyright © 2012 Walter Milner - all rights reserved

The Computer class

package GUIttt; class Computer { private Board board; void setBoard(Board board) { this.board = board; } void go() { // at random, find a space int row = (int) (Math.random() * 3); int col = (int) (Math.random() * 3); while (board.getCell(row, col) != ' ') { row = (int) (Math.random() * 3); col = (int) (Math.random() * 3); } // and put an O there board.set(row, col, 'O'); } }

This still uses the dumb method of going at random to a blank cell.

The Cell class

package GUIttt; import javax.swing.JButton; class TTTCell extends JButton { private char contents; void setContents(char c) { contents = c; setText("" + contents); } char getContents() { return contents; } TTTCell() { super(); contents = ' '; setText("" + contents); } }

This is a sub-classed JButton, with an extra field, contents, which is just a single character. The

setText metod of a JButton sets the text displayed on the button.

There is also a getText method. So we could have done without contents, and remembered the O or

X as the text on the button. However it is preferable to store that separately as the actual data, and

have the button text reflect that data, rather than being it.

Page 186: Java

Java

Page 186 - Copyright © 2012 Walter Milner - all rights reserved

Java 2D

This section is about the Java 2D classes providing support for basic graphics in 2 dimensions in a

Swing context. It also intriduces some basic graphics concepts.

Co-ordinates

Positions on a graph, or on a map, are located by co-

ordinates - how far across (x or East) and how far up (y or

North). Computer graphics usually measure x across and y

down, and this is the case for Java 2d graphics.

Care needs to be taken over where the origin (0,0) is. This

might be the top left of the screen (or printer, or in

general, device co-ordinates), or the top left of the

container you are drawing in. The units are usually pixels -

the size of which depends on the resolution.

Graphics Context

Graphics can be displayed in different colours, fonts, fill patterns, line styles and so on. One

approach would be to use parameters to specify each of these for each thing drawn. Alternatively a

data structure called a graphics context can hold the current values for these, and drawing

operations use these values. To draw a new object in a different colour, the colour of the graphics

context is used, which is applicable until it is changed again.

Because this approach is used by the underlying OS, Java also uses it. There is an abstract class called

Graphics, instances of which represent a graphics context. We will use the Graphics2D class, which is

a concrete class which extends Graphics to provide more facilities.

A First Graphics Program

public class Main extends JFrame { Main() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(50, 50, 200, 200); setVisible(true); } public void paint(Graphics g) { Graphics2D g2=(Graphics2D) g; Line2D.Double myLine = new Line2D.Double(0,0,100,100); g2.draw(myLine); } public static void main(String[] args) { Main main = new Main(); } }

main constructs an instance of Main, which is a sub-classed JFrame. The constructor sets the close

operation, the frame size and position (in screen co-ordinates), and makes it visible. The paint

method (described next) gets a Graphics2D instnce, makes a line object, and draws it. The result is

shown here. Note the top left (0,0) of the line is under the JFrame title bar.

Page 187: Java

Java

Page 187 - Copyright © 2012 Walter Milner - all rights reserved

Paint

Graphics on a window is usually divided into two parts - a static background and a changing

foreground. The static background has to be drawn when the window first appears, when it is

restored from minimisation, and when it is revealed after being obscured by an over-lapping

window. The changing foreground needs to be re-drawn (if ever) when the user does something, or

at short time intervals for animation.

Drawing the static background is done by the paint method, which the system invokes whenever it

needs to. Usually our program does not call paint - the system calls it when needed. This means it is

a call-back method.In the first program we have coded the paint method, so the line is drawn when,

for example, the window is restored.

Exercise

Run this program. See the line is re-drawn after a window restore.

Change it as follows

public class Main extends JFrame { Main() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(50, 50, 200, 200); setVisible(true); reDraw(); } void reDraw() { Graphics2D g2=(Graphics2D) getGraphics(); Line2D.Double myLine = new Line2D.Double(0,0,100,100); g2.draw(myLine); } public void paint(Graphics g) { } public static void main(String[] args) { Main main = new Main(); } }

Now what happens when the window is restored?

Why?

Simple animation

The other end of the spectrum of the paint idea, which is a fixed drawing, is animation. To do this,

we need to re-draw something at frequent intervals. This requires some kind of timer which will

repeatedly trigger the drawing - like the following. This has a draw method, which just draws a line,

then alters a data member called lineEnd which changes the end of the line. The Animator object has

the timer which invokes the draw method.

Page 188: Java

Java

Page 188 - Copyright © 2012 Walter Milner - all rights reserved

class Main extends JFrame { Animator animator; int lineEnd=50; Main() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(50, 50, 200, 200); setVisible(true); animator = new Animator(this); } void draw() { Graphics2D g2 = (Graphics2D)getGraphics(); Line2D.Double myLine = new Line2D.Double(0, 0, lineEnd, 100); g2.draw(myLine); lineEnd++; } public static void main(String[] args) { Main main = new Main(); } }

The Animator class is:

class Animator implements ActionListener { Main main; Animator(Main main) { this.main = main; Timer timer=new Timer(100, this); timer.start(); } public void actionPerformed(ActionEvent evt) { main.draw(); } }

This centers around the Timer class (part of Swing - there are other Timer classes). The constructor

of a Timer object takes two parameters. The first is a time delay in milliseconds, which is how often

the timer triggers. The second is a reference to an object which implements the ActionListener

interface - often used as a button event-listener. In this situation, the actionPerformed method is

called every time the timer triggers. Here that method just calls the draw method of the window

object.

Exercise

Run this program.

Experiment with the animation, including changing the time delay.

Can you add buttons to the window to start, stop and reset the animation? Main would need to

implement ActionListener as well.

The Java 2D API

The Java 2D API covers

Drawing graphics primitives such as points, lines, rectangles and ellipses, controlling the

outline and fill.

Displaying text

Displaying images

Page 189: Java

Java

Page 189 - Copyright © 2012 Walter Milner - all rights reserved

We will just look at some of the first set.

Firstly - the content pane of the JFrame. This is the part of a

JFrame that is normally used for content, and so excludes the

border and title bar. A JFrame has a method for obtaining a

reference to the content pane. If we get a graphics context on

that, we can draw with the origin (0,0) at the top left, and we do

not have to worry about adjusting for the title bar. For example:

void draw() { Container pane = getContentPane(); Graphics2D g2 = (Graphics2D) pane.getGraphics(); Line2D.Double myLine = new Line2D.Double(0, 0, 100, 100); g2.draw(myLine); }

Next, one primitive is a rectangle:

void draw() { Container pane = getContentPane(); Graphics2D g2 = (Graphics2D) pane.getGraphics(); Rectangle2D.Double myRect = new Rectangle2D.Double(10, 20, 200, 100); g2.setColor(Color.red); g2.draw(myRect); }

This also introduces the Color class. Instances of the Color class can be constructed by for example

new Color(50,100,255); where the three parameters are values for red, green and blue components

in the range 0 to 255. The class also has some standard colours like Color.red.

Next, the idea of stroke - how the line of the shape is drawn:

void draw() { Container pane = getContentPane(); Graphics2D g2 = (Graphics2D) pane.getGraphics(); Rectangle2D.Double myRect = new Rectangle2D.Double(10, 20, 50, 100); g2.setColor(new Color(50,100,200)); BasicStroke stroke=new BasicStroke(6); g2.setStroke(stroke); g2.draw(myRect); }

The parameter in the constructor of the stroke object is the line width in pixels.

Finally we can fill in the insides:

void draw() { Container pane = getContentPane(); Graphics2D g2 = (Graphics2D) pane.getGraphics(); Rectangle2D.Double myRect = new Rectangle2D.Double(10, 20, 50, 100); // draw outline BasicStroke stroke=new BasicStroke(6); g2.setStroke(stroke); g2.setColor(Color.green); g2.draw(myRect); // fill inside g2.setPaint(Color.blue); g2.fill(myRect); }

or we can fill it in with a color gradient instead of a solid colour:

Page 190: Java

Java

Page 190 - Copyright © 2012 Walter Milner - all rights reserved

void draw() { Container pane = getContentPane(); Graphics2D g2 = (Graphics2D) pane.getGraphics(); Rectangle2D.Double myRect = new Rectangle2D.Double(10, 20, 50, 100); GradientPaint gradient = new GradientPaint(10,20, Color.red, 50,100,Color.blue); g2.setPaint(gradient); g2.fill(myRect); }

Exercise

Try this stuff out.

Try using the Ellipse2D.Double to draw ovals.

Overloading

Overloading means having more than one version of a constructor or method. The different versions

have the same name, but different numbers or types of parameters.

For example, look at the BasicStroke class. We have seen one constructor:

void draw() { Container pane = getContentPane(); Graphics2D g2 = (Graphics2D) pane.getGraphics(); Rectangle2D.Double myRect = new Rectangle2D.Double(10, 20, 50, 100); BasicStroke stroke = new BasicStroke(6); g2.setStroke(stroke); g2.draw(myRect); }

The constructor with one argument takes that as the width of the stroke. But we could also use the

constructor with no arguments, which uses default values:

BasicStroke stroke = new BasicStroke();

Or one with three arguments which specify how lines end and join:

BasicStroke stroke = new BasicStroke(10, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);

Or one with six arguments for dashed lines:

float dash1[] = {10, 15, 5}; BasicStroke stroke = new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash1, 0f);

This is a matter of convenience - we can use the constructor which gives us the

degree of control we want. They must differ in argument number or type, or otherwise the compiler

cannot determine which one we want.

Page 191: Java

Java

Page 191 - Copyright © 2012 Walter Milner - all rights reserved

If you look through the Java API, you will see countless examples of oveloaded constructors and

methods.

Page 192: Java

Java

Page 192 - Copyright © 2012 Walter Milner - all rights reserved

More OOP

This part covers further aspects of object-oriented programming.

Page 193: Java

Java

Page 193 - Copyright © 2012 Walter Milner - all rights reserved

abstract

This section looks at inheritance and abstract in some depth. The basic idea is to reuse the code in a

base class or superclass and extend it to give more capabilities in a subclass.

Rules of inheritance

A subclass extends a superclass (base class)

The subclass inherits all the data fields and methods from the superclass.

Constructors are not inherited

The subclass can add more data fields and methods.

The subclass can have a different version of an inherited method with the same name. The

subclass method over-rides the superclass version.

The subclass can itself be extended to another level. This results in a class hierarchy.

At the top of all class hierarchies is the class Object. In other words all classes extend Object.

super

Constructors are not inherited - in the base class, constructors need to be written. However it is

possible for the base class constructor to invoke the super class constructor, by

super();

for the constructor with no arguments (the 'no-arg constructor') or something like

super(x,y,z);

to invoke a constructor with arguments.

If there is a call to super, it must be the first statement in the constructor.

If you do not call super, the compiler will in effect insert one. In other words the compiler will

generate bytecode so that the base constructor first calls the super constructor.

The super notation can also be used to refer to superclass fields and methods where they have been

over-ridden. For example suppose we have a base class Base with a method someMethod, and a

sub-class Sub has its own version of someMethod. This will over-ride the base class version, so inside

Sub,

someMethod();

invokes Sub's version. But if we need to we can say

super.someMethod();

and it will invoke the base class version.

Page 194: Java

Java

Page 194 - Copyright © 2012 Walter Milner - all rights reserved

Class hierarchy design

Much Java programming involves just using existing classes, or possibly sub-classing one class to give

an adapted version. However we may sometimes need to design a hierarchy with several levels. In

this case:

Common features go in the base class

Features which are logically required by all go in the base class

A specialisation is a subclass of a base class.

Classes towards the top of the hierarchy may be so general that they cannot logically be

instantiated. This can be controlled by declaring them to be abstract.

Example - a Shape hierarchy

We will use the Java 2D Graphics API to set up the following

What do all shape objects have in common? A position and size, a graphics context to be drawn in,

line and fill colours (ignoring gradients), and a method to draw it on the screen. These will therefore

go in the Shape class. A circle is a specialisation of an oval, with width and height equal, and a square

is a special oblong. We cannot actually draw a Shape, not knowing what shape it is. We can ensure

this by making Shape an abstract class.

Base classes do not have to be abstract. For example Oval is a base class for Circle, but it is not

abstract.

The definition of Shape is:

Page 195: Java

Java

Page 195 - Copyright © 2012 Walter Milner - all rights reserved

abstract class Shape { Color lineColor; Color fillColor; Graphics2D graphicsContext; int width; int height; int top; int left; Shape(Graphics2D g) { graphicsContext = g; } abstract void show(); }

Oval is:

class Oval extends Shape { Ellipse2D.Double oval; Oval(Graphics2D g) { super(g); width=50; height=70; top=0; left=0; oval=new Ellipse2D.Double(left,top, width, height); } Oval(Graphics2D g, int top, int left, int width, int height, Color lineColor, Color fillColor) { super(g); this.width=width; this.height=height; this.top=top; this.left=left; this.lineColor = lineColor; this.fillColor=fillColor; oval=new Ellipse2D.Double(left,top, width, height); } void show() { graphicsContext.setPaint(fillColor); graphicsContext.fill(oval); graphicsContext.setColor(lineColor); graphicsContext.draw(oval); } }

Circle is just:

class Circle extends Oval { Circle(Graphics2D g, int top, int left, int radius, Color lineColor, Color fillColor) { super(g, top, left, radius, radius, lineColor, fillColor); } }

Code to use these classes could be

Page 196: Java

Java

Page 196 - Copyright © 2012 Walter Milner - all rights reserved

Container pane = getContentPane(); Graphics2D g2 = (Graphics2D) pane.getGraphics(); Oval oval1 = new Oval(g2); oval1.show(); Oval oval2 = new Oval(g2, 50,50,80,30, Color.red, Color.blue); oval2.show(); Circle circle = new Circle(g2, 0, 80, 30, Color.green, Color.yellow); circle.show();

Shape has a simple constructor to establish the graphics context, and an abstract show method. This

means that all non-abstract sub-classes of Shape must implement the show() method, and that we

cannot accidentally instantiate a Shape object - the compiler will stop us.

The Oval class has two constructors - this is overloading. The one with just one argument calls the

constructor of Shape (through super) to establish the graphics context, and gives some default

values to the width and so on. The other constructor is similar, but also passes in values for width,

colour and so on. The Oval class defines show, so we can instantiate it and it is not abstract.

Why does Oval not declare top, left and the other fields? Because they are inherited from Shape.

The Circle class is very similar to Oval. The difference is worked by the constructor, whose radius

parameter is passed to the width and height parameters of the underlying Oval.

Why does Circle not have a show method defined? Because it inherits show from Oval.

Exercise

Run this application.

Accessor methods would be getHeight, setHeight, getTop, setTop and so on. In which class or classes

would you define them? Do it and use them.

Define the Oblong and Square classes and use them.

Multiple inheritance

Suppose we want a class to extend two base classes, because we want it to develop the functionality

of two classes. We could try

class MyClass extends ClassA, ClassB ..

but the compiler will not let you. Java does not allow multiple inheritance in this way (C++ does).

But you can do this by using inheritance by composition. This means having a data field in the class

which is an instance of the second class. This would be

class MyClass extends ClassA { ClassB bObject; ..

Now the bOject knows how to do ClassB methods, and so MyClass has both ClassA and ClassB

features.

The graphics classes show this. How can Oval actually draw an oval shape? We could have tried to

draw ovals 'from scratch' in the definition of Oval, but the Ellipse2D.Double class already knows how

to do this. So we started Oval with:

Page 197: Java

Java

Page 197 - Copyright © 2012 Walter Milner - all rights reserved

class Oval extends Shape { Ellipse2D.Double oval;

which means Oval inherits from Shape and knows how to do Ellipse2D.Double methods.

This is not full multiple inheritance, since we cannot over-ride the methods of the composed class.

For example, Oval cannot alter the methods of Ellipse2D.Double. But it can use them in different

ways, which is very close.

These example classes show another case of inheritance by composition, with the Shape class

containing a Graphics2D object. It is this which actually knows how to outline and fill an ellipse,

which we use in

void show() { graphicsContext.setPaint(fillColor); graphicsContext.fill(oval); graphicsContext.setColor(lineColor); graphicsContext.draw(oval); }

Check your understanding

What does inheritance mean?

What is the Object class?

What is the difference between overriding and overloading?

What is gained by declaring a class abstract?

What does 'inheritance by composition' mean?

Page 198: Java

Java

Page 198 - Copyright © 2012 Walter Milner - all rights reserved

Annotations

An annotation provides some information about the program - meta-data about the program.

Annotations do not directly influence execution, but they might indirectly. Annotations started to be

introduced in Java 5.

Three annotations are built-in to the language - Deprecated, SuppressWarnings and Override

@Deprecated

A method is said to be deprecated if it has

been replaced by better alternatives. This

might be just documented. But using the

@Deprecated annotation means the compiler

will also issue a warning if a deprecated

method is used.

In NetBeans, the editor will strike-through

methods which have this annotation, and if

this code is compiled, the output is :

Compiling 1 source file to C:\Users\walter\Documents\NetBeansProjects\Test\build\classes C:\Users\walter\Documents\NetBeansProjects\Test\src\test\Test.java:7: warning: [deprecation] someMethod() in Base has been deprecated b.someMethod(); 1 warning

In NetBeans, this only works if the 'compile on save' option is de-selected.

@SuppressWarnings

This is used to stop compiler warnings of a given type. For example

class Test { @SuppressWarnings("deprecation") public static void main(String[] args) { Base b = new Base(); b.someMethod(); } } class Base { @Deprecated void someMethod() { } }

does not generate the warning.

@Override

This signals that a method is intended to override a base class method. For example:

Page 199: Java

Java

Page 199 - Copyright © 2012 Walter Milner - all rights reserved

class Base { void someMethod() { } } class SubClass extends Base { @Override void someMethod() { } }

But what is the point? Because this might happen:

We thought we were overriding someMethod, but we spelt it somemethod. Using the @Override

annotation means the compiler can detect the error and tell us. This is another example of having a

language feature chosen so that the compiler can tell us about errors, rather than us having to figure

it out.

In addition to these built-in annotations, it is also possible to define your own, and to write

annotation processor tools which will deal with them - such as by inserting source code before

compilation.

Page 200: Java

Java

Page 200 - Copyright © 2012 Walter Milner - all rights reserved

Nested Classes

It is possible to define one class inside another class. These are called nested classes, and come in

several flavours:

An inner class, where a class is defined inside another class

A local class, defined inside a method

An anonymous class, which has no name

A static nested class

A static nested class is not an inner class.

Inner classes

For example:

class Test { public static void main(String[] args) { Outer outer = new Outer(); outer.x = 5; Outer.Inner inner = outer.new Inner(); inner.y = 5; } } class Outer { int x = 2; class Inner { int y = 3; } }

So here we have an Outer class enclosing an Inner class.

Here is a variation, where we add a method to the inner class to return a reference to the enclosing

class instance. We then instantiate two inner class objects, then set the outer class member from

one, and retrieve it from the other:

Page 201: Java

Java

Page 201 - Copyright © 2012 Walter Milner - all rights reserved

class Test { public static void main(String[] args) { Outer outer = new Outer(); outer.x = 5; Outer.Inner inner = outer.new Inner(); Outer.Inner inner2 = outer.new Inner(); inner.getOuter().x = 3; System.out.println(inner2.getOuter().x); } } class Outer { int x = 2; class Inner { int y = 3; Outer getOuter() { return Outer.this; } } }

This means the structure of the objects is as shown. So there is a difference between

The class definition structure - one class defined inside another (lexical structure)

The object structure - two inner instances inside one outer

Private inner classes

If we make the inner class private, it cannot be referenced from outside the outer class. For

example:

class Outer { Inner inner; Outer() { inner=new Inner(); } private class Inner { } }

This means we have a structure for the class definitions, and also for the objects created - each

Outer object will have just one Inner object in it. When we instantiate an Outer class, the

constructor instantiates just one Inner class. Because the class is private, it cannot be instantiated

from outside.

The main reason for making a class inner is if the functioning of the outer class requires another

class, and the other class is not useful elsewhere. So we have the other class as a private inner class.

This encapsulates things, and the inner is not visible from outside - it is part of the hidden

implementation of the outer class.

For example, suppose we want to implement a linked list. This will need something to represent a

node in the list - so as well as the LinkedList, we need a LinkNode. But LinkNode is unlikely to be

useful elsewhere, so make it a private inner class:

Page 202: Java

Java

Page 202 - Copyright © 2012 Walter Milner - all rights reserved

class LinkedList { private LinkNode head = null; private LinkNode last=null; void add(int n) { LinkNode node = new LinkNode(n); if (last==null)// empty list { head=last=node; } else { last.next=node; last=node; } } void traverse() { LinkNode where = head; while (where!=null) { System.out.println(where.data); where=where.next; } } private class LinkNode { int data; LinkNode next; LinkNode(int n) { data=n; next=null; } } }

used by for example:

LinkedList list = new LinkedList(); list.add(2); list.add(4); list.add(3); list.traverse(); // 2 4 3

Local classes

This is a class defined inside a method, rather than in a class outside a method. This is useful where

an inner class is needed, but is only relevant to one method.

For example, suppose we want to have a reverse() method on our linked list. One way to do this is

with a stack - go through the list pushing everything onto the stack, then replace the list with what

you get popping entries off the stack. But only the reverse method would use the stack class, so

make it local. So we add the following:

Page 203: Java

Java

Page 203 - Copyright © 2012 Walter Milner - all rights reserved

void reverse() { class Stack { // start definition of local class ArrayList<Integer> data = new ArrayList<>(); void push(int n) { data.add(n); } Integer pop() { if (data.isEmpty()) { return null; } else { return data.remove(data.size() - 1); } } } // end local class definition Stack stack = new Stack(); // make a stack LinkNode where = head; // starting from the head while (where != null) { // push everything onto the stack stack.push(where.data); where = where.next; } head = last = null; // re-start with nothing Integer i; while ((i = stack.pop()) != null) // and pop from stack into list add(i); } }

for example:

LinkedList list = new LinkedList(); list.add(2); list.add(4); list.add(3); list.traverse(); // 2 4 3 list.reverse(); list.traverse(); // 3 4 2

A local class is like a local variable, in that its scope is limited to that method. It therefore cannot be

made private or any other access modifier.

Anonymous classes

This is used like

new SomeClass() { someMethod(){..} }

This does two things:

1. It defines a new class, as a subclass of SomeClass, with someMethod() added or overridden.

The new class has no name.

2. It creates a new instance of that new class

These are commonly used for event listeners in Swing GUI apps. We want an object which will listen

and react to some user event. But it will only be useful for that individual event, so it would not be a

useful class defined in the usual way. So, for example:

Page 204: Java

Java

Page 204 - Copyright © 2012 Walter Milner - all rights reserved

JButton button=new JButton(); add(button) button.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e){ .. }} );

The last line is explained as follows:

ActionListener() { public void actionPerformed(ActionEvent e){.. }}

define an anonymous subclass of ActionListener, with actionPerformed overridden to do what we

want the button to do,

new ActionListener() { publi..

make an instance of this anonymous class,

button.addActionListener( new ActionListener() {..

tell the button that this object will listen for clicks.

Static nested classes

Like static elsewhere, this is per class not per object:

class Test { public static void main(String[] args) { Outer.StaticClass obj = new Outer.StaticClass(); obj.x = 3; } } class Outer { static class StaticClass { int x = 4; } }

A static nested class is not an inner class. This is because it does not have instance scope:

class Outer { int y; static class StaticClass { StaticClass() { y=2; // no good - OK if not static } } }

Exercise

1. There are four types of nested class - what are they?

2. Why does a static nested class not have instance scope?

Page 205: Java

Java

Page 205 - Copyright © 2012 Walter Milner - all rights reserved

Generics

Generics means using type parameters. Constructors and methods usually take formal parameters,

representing data passed into them which control what they do. A type parameter is similar, except

that it represents a type, not a data value. We can have generic types (classes and interfaces) and

generic methods.

The idea is that often the code handling different types - the class structure and algorithms used - is

the same, no matter what data type it uses. But Java is a strongly typed language - all variables and

expressions must have a type determined at run-time. Without generics, we would have to duplicate

code for different types.

Writing generic classes and methods is not simple, and neither is this section. But using the generics

in the Java Collections framework of data structures is very easy, as another section shows.

Useful Links

Angelika Langer Generics FAQ

http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html

Generics and type safety

Suppose you had a data structure containing Objects, and you use it to store Strings in. When you

recall an element, you need a typecast to tell the compiler that the Object is actually a String:

String string = (String) data.getOne();

You know this will work, since you know as the programmer that everything you put in the data

structure was really a String.

Having to put the cast there is annoying - but more importantly, there might be an error such that

objects are put in which cannot be cast to a String, which would result in a runtime

ClassCastException.

Generics ensures type safety. The compiler inserts type checks such that you can be sure only one

type can be placed in it, and no cast is needed on the retrieval.

A generic Linked List

For example, the data structure known as a linked list has the same structure, and the same

algorithms, no matter what data type it contains. So how can we model that in a strongly-typed

language?

In fact the Collections framework already has a linked list implemented for us. But it uses generics,

so we can better understand it if we first look at how generics works.

The class definition starts:

class LinkedList <T> {

Here the < > signals a type parameter - this will be a linked list containing data type T. Through the

class code we then use T as if it were a type. Like this:

Page 206: Java

Java

Page 206 - Copyright © 2012 Walter Milner - all rights reserved

class LinkedList <T> { private LinkNode head = null; private LinkNode last=null; void add(T n) // n is type T { LinkNode node = new LinkNode(n); if (last==null)// empty list { head=last=node; } else { last.next=node; last=node; } } ..

LinkNode is an inner class which uses the type parameter:

.. private class LinkNode { T data; // data is type T LinkNode next; LinkNode(T n) // type T in constructor { data=n; next=null; } } }

Some of the methods do not need to refer to the type:

.. void traverse() { LinkNode where = head; while (where!=null) { System.out.println(where.data); where=where.next; } } ..

When we use this class, we must supply an actual type:

LinkedList<String> strings = new LinkedList<>(); strings.add("One"); strings.add("Two"); strings.add("Three"); strings.traverse(); // One Two Three LinkedList<Integer> numbers = new LinkedList<>(); numbers.add(1); / autoboxing - really numbers.add(new Integer(1)); numbers.add(2); numbers.add(3); numbers.traverse(); // 1 2 3

Sub-classes and generics

If we say

LinkedList<String> strings = new LinkedList<>(); LinkedList<Object> objects = strings;

the second line is a compile error.

Page 207: Java

Java

Page 207 - Copyright © 2012 Walter Milner - all rights reserved

It might be thought that since a String is an Object, a list of Strings would be a list of Objects. But it is

not.

The reason is that otherwise, we could add an Object to 'objects', then get it back from 'strings', and

find that it was an Object, not a String. We must be sure that the elements of 'strings' are actually

Strings, or type safety is lost.

In general, a generic class of a base class is not a supertype of a generic class of a subclass.

Generic methods

As well as generic classes, we can have methods which take a type parameter.

Suppose we want something to transfer the elements of an array into a linked list. The type of the

array elements could be anything - we should get a linked list containing the same type. Here it is:

static <E> LinkedList<E> arrayToLinkedList(E[] array) { LinkedList<E> list = new LinkedList<>(); for (int i = 0; i < array.length; i++) { list.add(array[i]); } return list; }

The first line is parsed as:

This is used as

String[] stringArray = {"one", "two", "three"}; LinkedList<String> strings = LinkedList.arrayToLinkedList(stringArray); strings.traverse();

Wildcards

Suppose we want a static method to traverse and output the elements of a list passed as a

parameter. The method code would be:

LinkNode where= list.head; while (where != null) { System.out.println(where.data); where = where.next; }

This does not mention the type of the elements in the list. So how would the method header be

written?

Page 208: Java

Java

Page 208 - Copyright © 2012 Walter Milner - all rights reserved

static void printAll(LinkedList< what goes here? > list) {..

The type is 'any' or 'unknown'. We can use the ? wildcard for this:

static void printAll(LinkedList<?> list) { LinkNode where = list.head; while (where != null) { System.out.println(where.data); where = where.next; } }

Generic interfaces

An interface can also have type parameters.

Suppose we want a method to add up arrays. Not all arrays contain elements which can be 'added

up'. The first step would be to define what that means. The elements would need to belong to a

class which implemented a suitable interface:

interface Addable<T> { T add(T other); }

So an addable class has a method where you add the instance to another instance of the class, and

the result is a third instance. Such as:

class MyInt implements Addable<MyInt> { int val; // it wraps an int MyInt(int i) { val = i; } public MyInt add(MyInt other) { // Addable implementation return new MyInt(val + other.val); } public String toString() { return "" + val; } }

We could use this class like

MyInt n1 = new MyInt(5); MyInt n2 = new MyInt(6); MyInt n3 = n1.add(n2);

then a method to add up an array would be:

static <T extends Addable<T>> void addUp(T[] values) { T t = values[0]; for (int i = 1; i < values.length; i++) { t = t.add(values[i]); } System.out.println(t); } }

The header says that this method has a type parameter T, and that T is a type which is or extends a

class which implements the Addable interface on the type T. The method takes as formal parameter

an array of type T elements.

Page 209: Java

Java

Page 209 - Copyright © 2012 Walter Milner - all rights reserved

To show the power of this - we could add an array of vectors. A vector in physics has 3 components,

usually called x y and z, and vectors are added by adding their components. Here is our vector class:

class MyVector implements Addable<MyVector> { double x,y,z; MyVector(double x, double y, double z) { this.x=x; this.y=y; this.z=z; } public MyVector add(MyVector other) { return new MyVector(x + other.x, y+other.y, z+other.z); } public String toString() { return x+", " +y+", "+z; } }

Then we can use this like:

MyVector v1=new MyVector(1,2,3); MyVector v2=new MyVector(1,1,1); MyVector v3=new MyVector(2,2,2); MyVector[] data = {v1, v2, v3}; addUp(data); // 4.0, 5.0, 6.0

Type erasure

Type parameters cannot be used with the freedom of data parameters. For example, type

parameters cannot be instantiated. Neither can arrays of generic types be instantiated. The reason

for this is type erasure, which is how generics are implemented in Java.

For example in our addUp method, it is usual to initialise a running total with zero, by instantiating a

zero value:

static <T extends Addable<T>> void addUp(T[] values) { T t = new T(0); // will not compile for (int i = 0; i < values.length; i++) { t = t.add(values[i]); } System.out.println(t); } }

There is an issue as to whether the actual type has such a constructor - but we cannot do this

anyway.

In C++, generic source code is written as a template, and the compler generates different copies of it

for each version with a different actual type. But in Java, the compiler produces only one version,

with the type parameters removed. The following happens:

1. When a generic class or interface or method is compiled, any occurence of a type parameter is

replaced by its upper bound, or Object if there is no bound

2. When a generic type is instantiated, the actual type parameter is removed, leaving the raw type

(so if you wrote List<String>, it becomes just List ).

Page 210: Java

Java

Page 210 - Copyright © 2012 Walter Milner - all rights reserved

3. Types are checked and casts are generated by the compiler if required.

We started off saying

"Suppose you had a data structure containing Objects, and you use it to store Strings in. When you

recall an element, you need a typecast to tell the compiler that the Object is actually a String:

String string = (String) data.getOne();"

Type erasure in effect does this for you.

Arrays of generic types

Type erasure means this is not allowed directly. We can get around this by wrapping an Object array,

and type casting insertions and references. The following example does this, and shifts the index so

that it does not have to start at zero.

class MyArray<T> { private final int first, last; private Object[] array; MyArray(int first, int last) { this.first = first; this.last = last; array = new Object[last - first + 1]; } @SuppressWarnings("unchecked") public T get(int index) { return (T) array[index - first]; } void put(int index, T value) { array[index - first] = value; } }

This is used for example:

MyArray<String> stringArray = new MyArray<>(100, 200); stringArray.put(100, "One"); stringArray.put(101, "Two"); stringArray.put(102, "Three"); stringArray.put(200, "Last"); System.out.println(stringArray.get(100)); // stringArray.put(201, "Three"); array index out of bounds exception

The line

MyArray<String> stringArray = new MyArray<>(100, 200);

creates an array with first element index 100, and last is 200.

Page 211: Java

Java

Page 211 - Copyright © 2012 Walter Milner - all rights reserved

The Collections Framework

The Java Collections framework is a set of implementations of computer science data structures. An

array is an example of a data structure. Arrays are good for many purposes, but they are limited -

most notably, the number of elements in an array is fixed at compile-time. Other data structures

(lists, stacks, queues, trees, maps) are sometimes more effective. Because data structures are such a

fundamental aspect of computing, it is sensible that there are foundation classes for them.

Each data structure characteristically has a set of associated algorithms, to add data to it, remove

data, search and so on, and these naturally translate into OOP methods.

These algorithms are indifferent to the type of data in the structure. For example, searching a tree

does not depend on the type of data in it. However, Java is a strongly-typed language - each variable

must have a fixed and known type. So, how to have the same algorithm irrespective of type, when

the code must say what type it is?

That problem is solved by generics. The structures have a type parameter, so when we we can create

a list, for example, we supply a parameter which specifies what the type in the list will be. Solved,

very simply.

The Collections framework also shows a lot of abstraction. Each one is an implementation of a data

structure. How is the implementation done? We don't know, and we don't care. The collection will

specify what methods are available (insert, remove etc), and how fast they are (in big O notation -

google it). We decide which to use on that basis - not on how they work internally. In fact the

implementation might change, but it will make no difference to us.

Useful Link

The Oracle Collections Trail

Example

Suppose we want to have an array of Strings - but we do not know how many there will be. An

ArrayList does it:

ArrayList<String> list = new ArrayList(); list.add("One"); list.add("Two"); list.add("Three"); for (String s : list) { System.out.println(s); }

When we declare 'list', we have to supply the <String> type parameter to say we want a list of

Strings. Then we can just add and remove them. Note also the convenient for-each loop. It can be

read as 'for each String in list, calling it s, do ....'.

Interfaces and implementations

The framework has a set of interfaces (how you might want to use the data structure) and classes

(implementations of those interfaces). This diagram shows the main interfaces, in black, and the

most commonly used implementations, in red:

Page 212: Java

Java

Page 212 - Copyright © 2012 Walter Milner - all rights reserved

HashSet

A HashSet is like a mathematical set. It has no order, and no duplicates. For example:

class Test { public static void main(String[] args) { HashSet<MyClass> set = new HashSet(); MyClass mc1 = new MyClass(1, 1); MyClass mc2 = new MyClass(1, 2); MyClass mc3 = new MyClass(2, 2); MyClass mc4 = new MyClass(1, 2); set.add(mc1); set.add(mc2); set.add(mc3); set.add(mc1); set.add(mc4); for (MyClass c : set) { c.display(); } } } class MyClass { int x, y; MyClass(int x, int y) { this.x = x; this.y = y; } void display() { System.out.println(x + " " + y); } public int hashCode() { int hash = 3; hash = 79 * hash + this.x; hash = 79 * hash + this.y; return hash; } public boolean equals(Object other) { return (x == ((MyClass) other).x && y == ((MyClass) other).y); } }

The output is:

1 1 1 2 2 2 So a HashSet contains no duplicates. If we try to add the same object twice, it is only present once.

Nor can we add a different object if it .equals an object already there.

A HashSet uses a hash code of its elements to determine where to store them. This is the hash

function used in the underlying hash table.

Page 213: Java

Java

Page 213 - Copyright © 2012 Walter Milner - all rights reserved

ArrayList

An ArrayList is very like an array which can grow and shrink. It is ordered in the sense that it tracks

the first item, second and so on, as a sequence. This not the same as sorted. Elements can be added

at the end, or at a given index. Elements at an index, or a given instance can be removed. If the type

in the ArrayList implements Comparable, then Collections.sort can sort the list. For example, using

objects of type Record:

class Record implements Comparable<Record> { int key; String value; Record(int key, String value) { this.key=key; this.value=value; } public String toString() { return "Key: "+key+" Value:"+value; } public int compareTo(Record other) { if (key>other.key) return 1; if (key==other.key) return 0; return -1; } }

We can have an ArrayList of them:

ArrayList<Record> list = new ArrayList<>(); list.add(new Record(4,"Four")); // added at the end Record rec = new Record(5,"Remove"); list.add(rec); list.add(new Record(6,"Six")); list.add(2, new Record(7,"Added at 2")); // added as index 2 list.remove(rec); for (Record r: list) System.out.println(r); // get 4 7 6 Collections.sort(list); for (Record r: list) System.out.println(r); // get 4 6 7

An ArrayList in effect wraps an array with a certain capacity. Adding an element takes a constant

average time, and causes the capacity to automatically grow.

LinkedList

The LinkedList class is an implementation of the corresponding

data structure, consisting of nodes with pointers to the next

node, with nodes maybe not next to each other in memory. It is

doubly-linked, so that as well as a pointer from a node to the

next, there is a pointer to the previous, and the list can be

traversed in either direction.

A linked list can be used like an ArrayList:

Page 214: Java

Java

Page 214 - Copyright © 2012 Walter Milner - all rights reserved

LinkedList<Record> list = new LinkedList<>(); list.add(new Record(1,"One")); Record rec = new Record(2,"Two"); list.add(rec); list.add(new Record(3,"Six")); list.add(2, new Record(4,"Added at 2")); for (Record r: list) System.out.println(r); // get 1 2 4 3

But, the time to access elements is

different. An ArrayList is backed by an array,

and to access the nth element this works

directly, so the time to do this does not

depend on n. But for a linked list, the

system must follow the links from the head

(or the tail) so it gets slower for longer lists,

as shown.

So a linked list is not suitable where fast

access to a given element is needed.

But it does work well as a stack (LILO) or a

queue (FIFO) . For example:

LinkedList<Record> queue = new LinkedList<>(); Record rec1 = new Record(1,"Test"); Record rec2 = new Record(2,"Test"); Record rec3 = new Record(3,"Test"); queue.addFirst(rec1); queue.addFirst(rec2); queue.addFirst(rec3); while (queue.peekLast()!=null) { Record rec =queue.removeLast(); System.out.println(rec); // 1 2 3 }

TreeMap

A HashMap provides a structure in which key-value pairs can be stored and retrieved, and unlike a

HashSet, it allows for duplicates.

But more fun is a TreeMap. This is like an ordered binary tree implemented in another section,

except that it is based on a red-black tree, which has an insertion algorithm such that it remains

balanced. A TreeMap is therefore good if you need to maintain the data ordered:

TreeMap<String, String> treeMap = new TreeMap<>(); treeMap.put("D", "One"); // put = insert a key, value pair treeMap.put("B", "Two"); treeMap.put("E", "Three"); treeMap.put("C", "Four"); treeMap.put("A", "Five"); for (String key: treeMap.keySet()) System.out.println(key+" : "+ treeMap.get(key)); // get A B C D E

The for is the new 'foreach' loop introduced in Java 5. The keySet is the set of keys in the tree. So the

loop effectively says 'for each key in the tree,...show me the key and its associated value.'

Page 215: Java

Java

Page 215 - Copyright © 2012 Walter Milner - all rights reserved

Exercise

1. Write code to measure the time to access the central node in a LinkedList of different sizes, as

shown in the graph.

2. Do the same for an ArrayList.

3. Write code to show a LinkedList being used as a stack.

Page 216: Java

Java

Page 216 - Copyright © 2012 Walter Milner - all rights reserved

Enums

An enum is a small set of symbolic constants. Enums were introduced in Java 5.

For example, suppose we are writing an on-line theatre ticket booking system. A customer would

choose a seat which is free, enter their credit card details, and buy the ticket. We must ensure that

someone else does not book the ticket while they are entering their card details, or we will sell it

twice.

We can do this by having three states a ticket can be in - free, locked or purchased. We could code

the state as an int of magic numbers - 0=free, 1=locked, 2=purchased, like

class Ticket { char row; int number; int state; Ticket(char row, int number) { this.row=row; this.number=number; state=0; // free } }

Enums offer a much better way:

enum TicketState { FREE, LOCKED, PURCHASED } class Ticket { char row; int number; TicketState state; Ticket(char row, int number) { this.row=row; this.number=number; state=TicketState.FREE; } }

This says that a TicketState is one of FREE, LOCKED or PURCHASED - in capitals, since they are

constants. The 'state' attribute of a Ticket object has type TicketState.

Enums versus Magic Numbers

1. Enums say what they mean (like LOCKED, not 0) in code

2. Enums also say what they mean in println output (LOCKED not 0)

3. They have a compile-time check on domain errors (in other words you cannot say state=3;

which you could if 'state' was an int)

Enums as classes

Many languages have an equivalent of enum. For example the C version of the TicketState enum

would look identical to the Java version. But C enums and ints can be interchanged - losing the

advantages of enums over magic numbers.

Page 217: Java

Java

Page 217 - Copyright © 2012 Walter Milner - all rights reserved

In fact a Java enum is a special type of class. This means it can have constructors, methods and fields,

and so the properties of a thing can be modelled in code:

enum Season { // start an enum - a special class definition // allowed values - in effect, constructor calls: SPRING("Spring"), SUMMER("Summer"), AUTUMN("Autumn"), WINTER("Winter"); String name; // a data field Season(String name) { // the constructor this.name = name; } public String toString() { // a method, over-riding toString - nicer than capitals return name; } Season next() { // method returning a Season - the next one switch (this) { // can use switch on an enum case SPRING: return SUMMER; case SUMMER: return AUTUMN; case AUTUMN: return WINTER; case WINTER: return SPRING; } return null; // never get here } }

Then we can use the enum like:

Season season = Season.SPRING; System.out.println(season); // Spring System.out.println(season.next()); // Summer

An enum can have constructors, but they cannot be instantiated in code, like

Season newOne = new Season("Weird"); // compile-error

The compiler generates constructor calls as it encounters the list of allowed values (

SPRING("Spring"), SUMMER.. ).

An enum may only be relevant to one class, in which case it is appropriate to make it inner:

class Ticket { private enum TicketState { FREE, LOCKED, PURCHASED } char row; int number; TicketState state; Ticket(char row, int number) { this.row = row; this.number = number; state = TicketState.FREE; } }

Page 218: Java

Java

Page 218 - Copyright © 2012 Walter Milner - all rights reserved

Exceptions

An exception is an unusual situation which will affect the normal execution of a program.

For example:

class Test { public static void main(String[] args) { int y = 0; int x; Scanner scanner = new Scanner(System.in); System.out.println("Enter an integer"); y=scanner.nextInt(); x = 12 / y; } }

Usually this inputs an integer and divides 12 by it. But what if the user inputs 0? This happens:

Enter an integer 0 Exception in thread "main" java.lang.ArithmeticException: / by zero at test.Test.main(Test.java:13) Java Result: 1 The program 'throws' an exception and terminates abruptly.

The Java language has been designed to provide the programmer with tools to deals with situations

like these.

Types of exceptions

1. Program bugs. While a bug will often produce an exception, the language design cannot cope with

these. Exception handling will not fix program bugs. It is illogical to suppose that program code could

solve errors in program code.

2. Invalid input data

The first example showed this. Input values might come from a user at a keyboard, read from a data

file, from a web server or whatever. The values which your program inputs may be invalid.

Exception-handling can help here.

3. I/O communications failure

For example your program tries to read a file which does not exist. Or you try to write to a file and

the disc is full, or the file is read-only. Or you are receiving data from a remote server and the

network connection is lost. Exception-handling can help here.

4. System failure

The machine runs out of memory, or the JVM breaks (almost unknown). Recovery from such

situations is usually impossible.

Page 219: Java

Java

Page 219 - Copyright © 2012 Walter Milner - all rights reserved

try.. catch

A try..catch statement is often used in relation to exceptions. The idea is..

try { .. some code which might go wrong } catch (the exception) { .. do this instead when it goes wrong }

For example in our first program:

class Test { static void doMethod() { int y = 0; int x; Scanner scanner = new Scanner(System.in); System.out.println("Enter an integer"); y = scanner.nextInt(); try { x = 12 / y; System.out.println("12 / " + y + " = " + x); } catch (ArithmeticException ex) { System.out.println("Its gone wrong"); System.out.println(ex.getMessage()); ex.printStackTrace(); } } public static void main(String[] args) { doMethod(); System.out.println("Program ends normally"); } }

Now when 0 is input, this happens:

Enter an integer 0 Its gone wrong in the catch clause / by zero this is the getMessage() java.lang.ArithmeticException: / by zero start of the stack trace Program ends normally at test.Test.doMethod(Test.java:14) at test.Test.main(Test.java:25) Now our exception has been caught, execution proceeds, and the program ends normally. The

getMessage method outputs a descriptive message about the exception, and the stack trace shows

which line it occured in and which method, and which method called that, and so on - often to

considerable depth.

Exception and exceptions

An exception is a concept, an idea, and an event. Exception (capital letter) is a Java class, and

instances of that class are also called exceptions, or exception objects. Exception has many

subclasses. ArithmeticException is one of those. It inherits the getMessage() and printStackTrace()

methods.

Page 220: Java

Java

Page 220 - Copyright © 2012 Walter Milner - all rights reserved

The hierarchy

The base class is Throwable, which has the getMessage and printStackTrace methods. This has two

subclasses - Error and Exception.

Instances of Error and its subclasses are serious and an application could not be expected to recover

from one - a JVM error is an example.

An Exception instance is less serious and might be recovered from.

Exception and most of its subclasses are checked exceptions. That means that if you use a method

which might throw a checked exception, the compiler will require that the exception is dealt with

somehow - maybe by catching it. For example:

Here we are opening a file called 'textfile.txt' for input. But the compiler signals that this might

produce a FileNotFoundException, and our code must deal with that.

The class RuntimeException, and its subclasses, are not checked. An example is

ArrayIndexOutOfBoundsException, like this:

Page 221: Java

Java

Page 221 - Copyright © 2012 Walter Milner - all rights reserved

package test; class Test { public static void main(String[] args) { int[] data = new int[100]; System.out.println(data[100]); } }

which produces: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100 at test.Test.main(Test.java:10) Java Result: 1 These usually result from programming errors (as this does) and we have already said we cannot expect to deal with programming errors with program code - so forcing them to be handled would be pointless. Also, accessing array elements is so common that forcing the programmer to deal with a possible exception would clutter and obscure normal program code.

Catching exceptions

There are two ways to deal with an exception - catch it or throw it. Firstly, catching it.

As an example we use code to read and display a text file. Full explanation of i/o is in another

section. There are problems with the following code:

class Test { public static void main(String[] args) { try { // open file FileInputStream fstream = new FileInputStream("c:/temp/test.txt"); DataInputStream in = new DataInputStream(fstream); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String str; // read file while ((str = br.readLine()) != null) { System.out.println(str); } // close file in.close(); } catch (Exception e) { } } }

The first problem is that it has a catch block, so the compiler is happy. But there is nothing in the

catch block. We should at least do something. If reading that file was essential to the application, we

must end it - and hopefully tell the user why:

catch (Exception e) { System.out.println("Cannot read the important file"); System.exit(1); }

Secondly, we are catching an Exception. Because of the way a try catch works, this will catch an

instance of Exception, and any subclass - pretty much anything. The catch should be as specific as

possible:

Page 222: Java

Java

Page 222 - Copyright © 2012 Walter Milner - all rights reserved

catch (FileNotFoundException fnf) { System.out.println("Cannot find the important file"); System.exit(1); }

Now this is thrown by the FileInputStream constructor. But the readLine method throws an

IOException as well (for example if the drive fails part way through reading the file) . No problem -

we can have additional catch blocks..

catch (FileNotFoundException fnf) { System.out.println("Cannot find the important file"); System.exit(1); } catch (IOException iox) { System.out.println("Error when reading file"); System.exit(2); }

After the last catch you can also have a finally block, like

try { .. something.. } catch (some exception) { .. try to recover.. } finally { .. this executes with or without error }

But in our example we do not recover from the error, just stop, so a finally would be pointless.

Throwing an error

So you can deal with an exception by catching it. You can also throw it. Suppose we put our file read

in a method:

static void readFile() throws FileNotFoundException, IOException { FileInputStream fstream = new FileInputStream("c:/temp/test.txt"); DataInputStream in = new DataInputStream(fstream); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String str; // read file while ((str = br.readLine()) != null) { System.out.println(str); } // close file in.close(); }

So we have declared readFile to throw those two exceptions. That means that in turn, anything

which calls that method must catch them (or throw them again). For example:

Page 223: Java

Java

Page 223 - Copyright © 2012 Walter Milner - all rights reserved

public static void main(String[] args) { try { readFile(); } catch (FileNotFoundException fnf) { System.out.println("Cannot find the important file"); System.exit(1); } catch (IOException iox) { System.out.println("Error when reading file"); System.exit(2); } }

It is a design issue to decide if code should deal with an exception itself, or pass it up the execution chain for other code to deal with.

Defining your own exceptions

When writing methods in your own classes, you may realise an exception might occur, but there is no subclass of Exception which is appropriate - this is usually the case. The solution is to write your own. This would be a subclass of Exception if you want it to be checked, or of RuntimeException for unchecked. For example, suppose you defined a Pixel class. This would need red, green, blue and alpha (transparency) components, each in the range 0 to 1. But what if code attempted to instantiate a pixel with a component out of range? One solution would be to define and throw a BadPixelException:

class Pixel { double red, green, blue, alpha; Pixel(double red, double green, double blue, double alpha) throws BadPixelException { if (red < 0 || red > 1) { throw new BadPixelException(); } if (green < 0 || green > 1) { throw new BadPixelException(); } if (blue < 0 || blue > 1) { throw new BadPixelException(); } if (alpha < 0 || alpha > 1) { throw new BadPixelException(); } this.red = red; this.green = green; this.blue = blue; this.alpha = alpha; } } class BadPixelException extends Exception { public String getMessage() { return "Bad pixel"; } }

This might be used like:

Page 224: Java

Java

Page 224 - Copyright © 2012 Walter Milner - all rights reserved

public static void main(String[] args) { Pixel pixel = null; try { pixel = new Pixel(1.5, 0.5, 0.5, 0); } catch (BadPixelException bpe) { System.out.println(bpe.getMessage()); } }

Page 225: Java

Java

Page 225 - Copyright © 2012 Walter Milner - all rights reserved

Multi-threading

What is concurrency?

In a quick phrase, the computer doing several things at once.

Background

In 1957 the UNIVAC II computer was on sale, from Remington Rand. It had 2k to 10k memory and

could do 5236 additions in a second. The average installation cost $1 240 000, and it took 18 to 24

months to deliver. This was one of

the most powerful models then

available.

With such a high price and limited

power, attention was paid to how

best to use such machines. One

idea was time-sharing. The

machine was connected to many

terminals - keyboards and teletype

printers, so that many people

could use it. Each user in turn got

a timeslice of a few milliseconds.

From their point of view, it appeared they had exclusive use of a million dollar computer.

This had to be managed by the operating system. Each user's program and data had to be kept

separate from the others, and at the start of the timeslice it had to somehow continue from where it

was paused at the end of the previous timeslice.

This was the start of multi-processing - one computer doing several tasks at the same time.

Modern multi-processing

The user of a PC or laptop or smartphone today now takes it for granted that they will be able to

have wordprocessing and a spreadsheet and an email client running at the same time. We now have

one user and one OS, but several applications, background processes and maybe several processors

in use. The OS will manage the memory allocations for this, and the time scheduling. These are

known as heavyweight processes. Heaveyweight processes usually do not share memory or data.

Heavyweight processes

Page 226: Java

Java

Page 226 - Copyright © 2012 Walter Milner - all rights reserved

We are only concerned with the JVM, running our Java application. The OS sees this as a single

heavyweight process, but the JRE can run the app as several threads. When it starts main executing,

this runs in one thread. But other threads can also be started, if our program makes that happen.

The runtime schedules the time management of these threads, and they will usually share data

values in common memory:

Running a new thread

When a Java application starts, it has a single thread. The runtime will also run many other threads,

but the application just has one. How do we start an extra thread in our application? There are two

methods.

Sub-classing Thread

There is a class called Thread, which has a method called run(), which is what happens when the

thread executes. We can subclass Thread and override run() to make our thread do what we want.

We start the thread by calling its start() method:

class Test { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); } } class MyThread extends Thread { public void run() { System.out.println("Thread has run"); } }

The thread ends when the run method ends.

Implementing Runnable

The second, and better, method is to write a class which implements the Runnable interface. This

interface has just one method, which is run(), in which you put what you want the thread to do. You

instantiate this class to create a Runnable object, then make a new Thread, passing the Runnable

object to its constructor. Then you start the new Thread:

Java lightweight threads

Page 227: Java

Java

Page 227 - Copyright © 2012 Walter Milner - all rights reserved

class Test { public static void main(String[] args) { Runner runner = new Runner(); // make a Runner Thread newThread = new Thread(runner); // make a Thread linked to the Runner newThread.start(); // start the new Thread } } class Runner implements Runnable { public void run() { System.out.println("Thread has run"); } }

This method is better than subclassing Thread. This is because if your class subclasses Thread, it

cannot subclass anything else. But your class that implements Runnable can subclass anything, and

can also implement additional interfaces.

Threads are not function calls

It is tempting to think of a thread as a method invocation or function call, but it is not. For example,

if we run three threads:

class Test { public static void main(String[] args) { Runner runner1 = new Runner(1); Runner runner2 = new Runner(2); Runner runner3 = new Runner(3); Thread newThread1 = new Thread(runner1); Thread newThread2 = new Thread(runner2); Thread newThread3 = new Thread(runner3); newThread1.start(); newThread2.start(); newThread3.start(); } } class Runner implements Runnable { int id; Runner(int id) { this.id=id; } public void run() { System.out.println("Thread ID:"+id); } }

you might think that

newThread1.start();

starts and completes, and then

newThread2.start();

starts and completes, then

newThread3.start();

But if you run this code, the output is sometimes Thread ID:1 Thread ID:3 Thread ID:2

Page 228: Java

Java

Page 228 - Copyright © 2012 Walter Milner - all rights reserved

but not always. Sometimes the sequence is 1 2 3, which is what you probably expected. These three

threads run at the same time. The runtime schedules the execution of the threads, in an

unpredictable sequence. This means concurrent programming introduces a completely new element

- execution can be indeterminate. The output is not the same every time it is run.

Why Use Threads?

Because

1. They make more efficient use of processor time, because if the application must wait for some

external event to happen, the processor can do the waiting in one thread, while executing other

code in another thread.

2. It is natural to think of the application doing more than one thing at a time. For example, in Tetris

the blocks should fall down at the same time as the user presses keys.

For example, suppose we have an application which should monitor a folder for the presence of

some file, and process it when it arrives. Meanwhile it should do something else. The following code

will wait for the appearance of 'test.txt' in folder c:/temp. When it finds it, it processes it and deletes

it. Meanwhile the main thread will run until the user enters 'q', at which point the file watcher stops,

if it is still running, and the application stops.

The run() of the thread uses Thread.sleep(1000); which makes the current thread go to sleep for

1000 milliseconds or 1 second (during which time main is doing something). A sleeping thread can be

interrupted - in this case, the file watcher then stops.

The loop

while (!file.exists()) {

could have been in main, with no extra thread. But with that structure, the application can do

nothing except wait for the file. Here is main, which starts the other thread, then takes keyboard

input, until it gets "q", in which case it interrupts the other thread:

class Test { public static void main(String[] args) { Thread thread = new Thread(new FileWatcher()); thread.start(); Scanner scanner = new Scanner(System.in); String key; while (true) { key=scanner.nextLine(); if (key.equals("q")) { thread.interrupt(); return; } } } }

Here is the second thread:

Page 229: Java

Java

Page 229 - Copyright © 2012 Walter Milner - all rights reserved

class FileWatcher implements Runnable { File file = new File("C:////temp//test.txt"); public void run() { while (!file.exists()) { try { Thread.sleep(1000); } catch (InterruptedException ie) { System.out.println("Ended with no file"); return; } } System.out.println("Got file"); // process file.. file.delete(); } }

Data shared between threads

Consider this:

class Test { public static void main(String[] args) { Process p = new Process(); Thread thread1 = new Thread(p); Thread thread2 = new Thread(p); thread1.start(); thread2.start(); System.out.println(p.c); } } class Process implements Runnable { long c = 0; public void run() { c += 1; System.out.println("Finished"); }

}

We only have one Process object, and we run two threads on it, both of which change c. The run()

method increments c, so we might get the output Finished Finished

2, if the sequence is as shown.

But we might also get 0 Finished Finished, if main finishes before

thread1 or thread2:

We can also get Finished 1 Finished, if thread1 completes first, then

main, then thread2.

Harder to explain is Finished Finished 1, which is also possible. How

can thread1 and thread2 complete, yet c is only 1?

It happens because of c+=1. Execution of this involves three steps:

thread1, thread2 and main

main, thread1 then thread2

Page 230: Java

Java

Page 230 - Copyright © 2012 Walter Milner - all rights reserved

get the value of c, add 1 to c, and store the result back in c. The sequence might be:

thread1 gets the value of c =0 thread2 gets the value of c=0 thread1 calculates c+1 = 1 thread2 calculates c+1 = 1 thread1 stores 1 in c thread2 stores 1 in c so the threads have executed c+=1 twice, but c is only 1.

This is equivalent to database sharing problems. Two users read the same database, then both

update it. But the update of the first is overwritten by the upate of the second.

The database problem is solved by some kind of locking so that only one user can use the database

at a time.

The point is that shared data will be processed in an unpredictable way, unless thread sequencing

has some kind of co-ordination.

The Thread class

We can pass a name to a Thread in its constructor, and a thread's toString will use it:

Thread thread = new Thread("My thread"); System.out.println(thread);

The output from this is Thread[My thread,5,main] - the name of the thread, its priority level ( 1 to

10, which the scheduler uses when choosing which thread to run when), and its threadgroup -

discussed later.

We can make a thread a daemon. Usually an application will run until System.exit() is called, or all

threads, including main, have ended. Threads normally end when their run() method has ended. So

an application with a thread with an endless loop in the run will not end:

.. Thread thread = new Thread(new Process()); thread.start(); .. class Process implements Runnable { public void run() { while (true); } }

But daemon threads do not count - an application will end even if daemon threads are still running

(and they will then be stopped). So

thread.setDaemon(true);

means this stops when main ends. The idea is that a daemon thread can provide services to other

threads, but we do not need to remember to end them.

Sleep and interrupt

Thread has an interrupt method. A thread can invoke the interrupt method of another thread. This is

useful if the thread carries out some long process, such as reading a file across a network. We want

to set the thread on this task, and be alerted (by an interrupt) when it has finished.

Page 231: Java

Java

Page 231 - Copyright © 2012 Walter Milner - all rights reserved

What does the calling thread do while it waits for the service thread? It can go into an endless loop

as it waits to be interrupted - but this wastes processor power. Better is to invoke the sleep method,

which puts the current method to sleep for a length of time - with the expectation that the service

will interrupt the sleep when it completes and interrupts.

So what happens is

the service thread is started we go to sleep for a length of time maybe we are interrupted by the service completing in the set time - we carry on if we are not (service took too long) we carry on without the service

Why must the service provider be a thread? Why can't it be a normal class, with a suitable method

call, and we just have a return from that method? Because we expect the service to take a long time,

maybe waiting for another computer on the network. If it’s a normal method call, our machine halts

waiting for the network. If it’s a thread - on our machine other threads will still run, and we will not

waste processor time waiting.

For example - suppose we have a Service thread that fetches a file. We will allow a maximum of 20

milliseconds to complete it. When the Service thread finishes, it must interrupt the thread that

called it. So we need to pass a reference to the current thread to it, so it knows what to interrupt.

Thread.currentThread() gives us that. Here is the main thread:

class Test { public static void main(String[] args) { Thread mainThread=Thread.currentThread(); Thread thread = new Thread(new Service(mainThread)); thread.start(); try { Thread.sleep(20); System.out.println("Service timed out"); } catch (InterruptedException ie) { System.out.println("Service completed"); } } }

And here is the service thread. It has a do-nothing loop to simulate the activity which it must do, like

fetching a file:

Page 232: Java

Java

Page 232 - Copyright © 2012 Walter Milner - all rights reserved

class Service implements Runnable { Thread whatToInterrupt; Service(Thread t) { whatToInterrupt=t; } public void run() { // simulate time taken for the service for (int i=0; i<10000000; i++); whatToInterrupt.interrupt(); } }

Perils of multi-threading

Habits of thought which develop after conventional single-threaded programming experience lead

to pitfalls when multi-threading.

We look at this with an example. Suppose we have an online eCommerce app. We have a stock level

of items for sale. A customer can log on and choose to buy. We need to check there are goods in

stock, and if so, sell one an dreduce the stock level by one.

Since it is online, we may have 100 customers at the same time. We simulate this by having a Selling

class, instances of which are a thread which does the selling process, and we run 100 threads at the

same time. Here is main:

class Test { Stock stock = new Stock(); public static void main(String[] args) { Test test = new Test(); Selling[] seller = new Selling[100]; for (int i = 0; i < 100; i++) { seller[i] = new Selling(test); seller[i].start(); } System.out.println(test.stock.level); } }

The Stock class is just:

class Stock { int level = 100; }

and the Selling thread is:

Page 233: Java

Java

Page 233 - Copyright © 2012 Walter Milner - all rights reserved

class Selling implements Runnable { Thread thread; Test owner; Selling(Test owner) { thread = new Thread(this); this.owner = owner; } void start() { thread.start(); } synchronized void sell() { } public void run() { for (int i = 0; i < 1000; i++) { // got any in stock? if (owner.stock.level > 0) { // customer thinks about it for (int j = 0; j < 10000; j++); // and buys one owner.stock.level--; } } } }

Is this correct? No.

The first problem is thinking of a thread start as a function call, which will not return until after

completion. So in main:

Selling[] seller = new Selling[100]; for (int i = 0; i < 100; i++) { seller[i] = new Selling(test); seller[i].start(); } System.out.println(test.stock.level);

It looks like we run 100 threads, and then output the stock level. But in fact we just start 100 threads

then output the stock level - possibly before all 100 threads have completed.

How to fix this? We could count the completed threads, and not go onto the print in main until 100

have completed:

class Test { Stock stock = new Stock(); int completedThreadCount = 0; public static void main(String[] args) { .. start 100 threads while (test.completedThreadCount < 100) { try{Thread.sleep(10);} // pause for 10 milliseconds catch (InterruptedException ie) {System.out.println(ie);} } System.out.println(test.stock.level); } }

and

Page 234: Java

Java

Page 234 - Copyright © 2012 Walter Milner - all rights reserved

class Selling implements Runnable { .. public void run() { .. owner.completedThreadCount++; System.out.println(owner.completedThreadCount + " threads completed"); .. } }

Is this correct? Usually - but here is some sample output:

94 threads completed 95 threads completed 90 threads completed 99 threads completed 89 threads completed 87 threads completed -3 100 threads completed 97 threads completed 98 threads completed 96 threads completed 93 threads completed Before reading on, try to work out how this could come about.

The -3 is the final stock level. We will come back to why it is negative. This output comes as 100

threads are completed. But how come 97 are completed after 100, when each thread just

increments the completed count?

The problem is:

owner.completedThreadCount++;

This reads the current value of

completedThreadCount, adds one, and

stores the result. But during the

execution of that statement, other

threads are also executing. The

sequencing of those threads is

controlled by the JRE. What has

happened, among other things, is as

shown.

What we need is some way to ensure

that during this statement, no other

thread can 'but in.'

Synchronized statement

This is a Java keyword which we can apply to a statement. We say:

Thread sequence

Page 235: Java

Java

Page 235 - Copyright © 2012 Walter Milner - all rights reserved

synchronized (someObject) <statement> ;

Then first the object is locked, the statement executes, with exclusive access to the object, then the

lock is released. First in, some other thread might hold the lock, in which case our thread must wait

until the other thread releases it. The statement might be a block.

In our example, we need to say

synchronized (owner) { owner.completedThreadCount++; System.out.println(owner.completedThreadCount + " threads completed"); }

completedThreadCount is an attribute of the 'owner' object, so getting a lock on this fixes the

problem, and the thread count goes up to 100 as expected, every time.

This code may require one thread to wait on another, so it is slower - but it is thread-safe : that is, it

works correctly with several threads running.

But we still have the problem that we can get a negative stock level, even though every thread checks there is some in stock before selling one: 97 threads completed 98 threads completed 99 threads completed 100 threads completed -3 But now we know why - after one thread has checked the stock level is >0, another thread does the

same, sells one, then the first thread sells one also. We can fix that again using synchronized:

synchronized (owner) { for (int i = 0; i < 1000; i++) { // got any in stock? if (owner.stock.level > 0) { // customer thinks about it for (int j = 0; j < 10000; j++); // and buys one owner.stock.level--; } } }

Synchronized method

As well as making a statement synchronized, we can also apply that to a whole method.

In that case, the lock is acquired on the object executing the method. In our case, the lock needs to

be on the stock level, so we need to switch the selling method into the Stock class:

Page 236: Java

Java

Page 236 - Copyright © 2012 Walter Milner - all rights reserved

class Stock { int level = 100; synchronized void sell() { for (int i = 0; i < 1000; i++) { // got any in stock? if (level > 0) { // customer thinks about it for (int j = 0; j < 10000; j++); // and buys one level--; } } } }

and the Selling thread run has to say:

public void run() { owner.stock.sell(); .. }

It could be argued this approach is less logical, since the sell method is concerned with the sell

thread, not the stock object.

Page 237: Java

Java

Page 237 - Copyright © 2012 Walter Milner - all rights reserved

Classes and types

Earlier we said 'a class is a type of object'. That was an attempt to provide a simple idea of what a

class is, to a beginner. It does not work for purely static classes. Neither does it correspond to a more

precise idea of 'type'.

Suppose we say

Object obj = "Hello";

We are declaring obj to be an Object, but we are assigning a String to it. Can we do that? Yes.

What about

String obj = new Object();

No. We get a compile-time error - "Incompatible types".

It depends on the class hierarchy. We can say

<base class> ref = new <subclass>

but not

<subclass> ref = new <baseclass>

How come? Because of the way inheritance works, a subclass instance will be able to do everything

a base class can, so the compiler can be happy that in the first case, if we tell ref to do one of its

methods, the subclass object will be able to do so. But a subclass may have methods which the base

class did not have, so in the second case we may ask ref to do a method which the base object does

not possess. For example

String obj = new Object(); char c = obj.charAt(0);

will not work, since Object does not have a charAt method.

How about

Object obj = "Hello"; char c = obj.charAt(0);

Another fail - cannot find symbol - method charAt. We have told the compiler that obj is an Object,

and Object does not have a charAt method. But we know that a String does. How about

Object obj = "Hello"; char c = ( (String) obj).charAt(0);

No problem, at compile-time or run-time. How about

Object obj = new Integer(2); char c = ( (String) obj).charAt(0);

No compile-time error. But when we run it, a ClassCastException is thrown - an Integer cannot be

cast to a String (and this is an unchecked exception so it might come as a surprise). Why is there no

compile-time error? We have told the compiler that ref is an Object. Then can an Object be cast to a

String? Sometimes, as the previous example showed. But that was when it was actually a String. In

this case obj is actually a Integer, and it is impossible to cast an Integer to a String.

Page 238: Java

Java

Page 238 - Copyright © 2012 Walter Milner - all rights reserved

"Variables have types, objects have classes."

The Java Language Specification says

In the Java programming language, every variable and every expression has a type

that can be determined at compile-time. The type may be a primitive type or a

reference type. Reference types include class types and interface types. Reference

types are introduced by type declarations, which include class declarations (§8.1)

and interface declarations (§9.1). We often use the term type to refer to either a

class or an interface.

In the Java virtual machine, every object belongs to some particular class: the class

that was mentioned in the creation expression that produced the object (§15.9), or

the class whose Class object was used to invoke a reflective method to produce the

object, or the String class for objects implicitly created by the string concatenation

operator + (§15.18.1). This class is called the class of the object. An object is said

to be an instance of its class and of all superclasses of its class.

For example

Object ref = new Integer(3);

The variable is 'ref'. The type of 'ref' is Object, since that was how it was declared - its 'compile-time

type'.

There is also an object here - the one created by the 'new Integer(3)'. The class of that object is

Integer, since that was mentioned in the 'creation expression'. A reference is a hidden pointer, so

the situation can be shown as:

Suppose we have

Object obj = new Integer(3); obj = "Hello";

Then after this the situation is:

Page 239: Java

Java

Page 239 - Copyright © 2012 Walter Milner - all rights reserved

The type of ref is still Object. Its value is an object with a different class - a String. The Integer object

might be garbage collected if appropriate.

Interfaces

The JLS says:

Even though a variable or expression may have a compile-time type that is an

interface type, there are no instances of interfaces. A variable or expression whose

type is an interface type can reference any object whose class implements (§8.1.5)

that interface.

So that you cannot say:

ActionListener listener = new ActionListener();

This makes sense, since an interface has no method implementations, so 'listener' would not 'know'

how to do the required methods. But we can say:

ActionListener listener = new MyListener(); .. class MyListener implements ActionListener { public void actionPerformed(ActionEvent e) { //whatever } }

Here the type of the variable listener is ActionListener, which is an interface not a class. But the

value of 'listener' (what it refers to) is an object, with class MyListener, which implements the

ActionListener interface.

Automatic conversions and casts

A change of type is either an automatic conversion, like

Object obj = new Integer(3);

or an explicit typecast like

Object obj = (Object) new Integer(3);

Some conversions are allowed, some are not. Some produce compile-time errors, some runtime

exceptions. Here we go. Suppose we have (with Base extending Object)

Page 240: Java

Java

Page 240 - Copyright © 2012 Walter Milner - all rights reserved

class Base {} class Sub extends Base {}

Firstly automatic conversions:

Base a = new Base(); // OK Base b = new Sub(); // OK - can convert to a base class Base c = new Object(); // compile-time Incompatible types. // Can't convert to a subclass Integer j = "wwww"; // compile-time Incompatible types // Can't convert to an unrelated class

This make sense. We can convert to a base class, because a subclass can do everything a base class

can. You cannot convert to a subclass, since a subclass may have methods which a base class cannot

do. You cannot convert between unrelated classes (where one is not a subclass of the other) for the

same reason. These are all compile-time errors so there is little to worry about.

For explicit casts, you might get compile-time or run-time, and it might be because the cast fails, or

the assignment:

Base d = (Base) new Sub(); // OK - cast to a base class a) Base e = (Base) new Object(); // run-time class cast exception b) Object f = (Base) new Object(); // runtime Object g=(Object) new Base(); // OK - cast to a base class c) Base h=(Object) new Base(); //No compile time Incompatible types d) Sub i= (Object) new Base(); // no compile time

(a) fails because you cannot convert a base class to a subclass, since the subclass might have

members which the base class does not.

(b) fails for the same reason - the conversion not the assignment, so it does not matter what you

assign to.

(c) fails because of the assignment - you cannot assign a base class to a subclass.

(d) fails for the same reason

Page 241: Java

Java

Page 241 - Copyright © 2012 Walter Milner - all rights reserved

Input and Output

Java treats all of the following as examples of I/O

reading input from the keyboard

writing characters to the screen

reading or writing a file

reading or writing through a Socket to another computer, possibly using http, possibly over the internet.

Files differ in content and structure. A text

file is a sequence of characters, some of

which are newline, so the file can be thought

of as a series of lines of text. A file might

instead contain other primitive types, in

binary format. It might be a mixture of these,

perhaps in a format like a Word file or a jpg

image file. It might contain some Java

objects.

The file might be located on a local drive like

'drive c' on Windows, or on a USB stick

looking like a drive letter. The drive might be

mapped to the network, so the file might be

located on another computer.

There is a hierarchy of classes to deal with

this, with appropriate methods. These are

mirrored - a set of classes for input, and a

corresponding set for output.

A new set of I/O classes, called NIO, was

introduced in Java 1.4, and another set as

NIO2 in Java 7. These are covered elsewhere.

Reading and writing bytes

A FileOutputStream has methods for writing bytes to a file. Of course all data consists of one or

more bytes, but FileOutputStream can write a byte explicitly.

In the following, a stream is opened when the FileOutputStream is constructed. It is important that

after use, the stream is also closed, as quickly as possible. Otherwise system resources are used

wastefully - and if a buffer is used, data may never actually be written.

Not quite so new

Page 242: Java

Java

Page 242 - Copyright © 2012 Walter Milner - all rights reserved

byte a = 1; byte b = 2; byte c = 3; // write data FileOutputStream out = null; try { out = new FileOutputStream("c:/temp/out.dat"); out.write(a); out.write(b); out.write(c); out.close(); } catch (FileNotFoundException fex) { System.out.println("File not found"); } catch (IOException fex) { System.out.println("Error writing"); } // read data FileInputStream in = null; try { in = new FileInputStream("c:/temp/out.dat"); int d; while ((d = in.read()) != -1) { System.out.println(d); } out.close(); } catch (FileNotFoundException fex) { System.out.println("File not found"); } catch (IOException fex) { System.out.println("Error reading"); }

The read() method returns an int, when it actually reads byte. This is so that it can return -1 if it is told to read, and the end of the file has been reached. Normally the byte read is the least significant of the 4 bytes in the int. In

out = new FileOutputStream("c:/temp/out.dat");

If the file already exists, it would first be deleted. Another constructor:

out = new FileOutputStream("c:/temp/out.dat", true);

instead appends data to an existing file.

Reading and Writing Characters

For reading and writing characters into a file, the FileReader and FileWriter are more appropriate.

You could split chars into 2 bytes and write them as such, but FileWriter alows you to write a String

at a time:

Page 243: Java

Java

Page 243 - Copyright © 2012 Walter Milner - all rights reserved

String line1 = "Line one"; String line2 = "Line two"; // write data FileWriter out = null; try { out = new FileWriter("c:/temp/out.chars"); out.write(line1); out.write("\n"); out.write(line2); out.write("\n"); out.close(); } catch (FileNotFoundException fex) { System.out.println("File not found"); } catch (IOException fex) { System.out.println("Error writing"); } // read data FileReader in = null; try { in = new FileReader("c:/temp/out.chars"); int d; while ((d = in.read()) != -1) { System.out.print((char) d); } in.close(); } catch (FileNotFoundException fex) { System.out.println("File not found"); } catch (IOException fex) { System.out.println("Error reading"); } }

Note how we have written new line characters '\n' after each 'line'.

A primitive char is always a 16-bit Unicode, but characters written to a file may have a different

character set. FileReader/Writer uses the default - which you can find by:

Charset def = Charset.defaultCharset(); System.out.println(def);

on the machine this is being written on, that is UTF-8. To use a specific charset, you must use

OutputStreamWriter or InputStreamReader, such as:

try { FileOutputStream fos = new FileOutputStream("c:/temp/test.txt"); Charset charSet = Charset.forName("UTF-16LE"); OutputStreamWriter osw = new OutputStreamWriter(fos, charSet); osw.write("ABب"); // A B and Arabic beh = Unicode 0628 osw.close(); FileInputStream fis = new FileInputStream("c:/temp/test.txt"); InputStreamReader isr = new InputStreamReader(fis, charSet); int i; while ((i = isr.read()) != -1) { System.out.println(Integer.toHexString(i) + " " + (char) i); } isr.close(); } catch (Exception e) { System.out.println(e); }

output:

41 A 42 B ب 628

Page 244: Java

Java

Page 244 - Copyright © 2012 Walter Milner - all rights reserved

UTF-16LE is 16 bit, with LE meaning LittleEndian - the lower order byte is stored first. See the API for

more details.

Buffered streams

Reading and writing single bytes or characters to a device is very inefficient compared to using a

buffer. The idea is that an area of memory called a buffer is used. Data to be written is placed in the

buffer, and the buffer is only actually written to the device when the buffer is full (or it is 'flushed').

This greatly reduces the number of I/O operations with their associated overheads.

We can do this simply using a BufferedReader/Writer object, constructed by wrapping a

FileReader/Writer:

String line1 = "Line one"; String line2 = "Line two"; // write data BufferedWriter out = null; try { out = new BufferedWriter(new FileWriter("c:/temp/out.chars")); out.write(line1); out.write("\n"); out.write(line2); out.write("\n"); out.close(); } catch (FileNotFoundException fex) { System.out.println("File not found"); } catch (IOException fex) { System.out.println("Error writing"); } // read data BufferedReader in = null; try { in = new BufferedReader(new FileReader("c:/temp/out.chars")); int d; while ((d = in.read()) != -1) { System.out.print((char) d); } in.close(); } catch (FileNotFoundException fex) { System.out.println("File not found"); } catch (IOException fex) { System.out.println("Error reading"); }

Reading and Writing Primitives

We can do I/O with the other primitive types using a DataInputStream and DataOutputStream.

There is an issue with this, since readInt() cannot return -1 to signal the end of file, since -1 might be

a valid data value. One approach to this is read until an end of file exception, but it is not

straightforward to distinguish between this and an unexpected end of file, say because the drive has

failed in the middle of a read.

The approach used here is to preceed the actual int writes by a count of how many there will be.

Then the read first reads that number, then continues to iterate the reading of that number of actual

data ints. This way an end of file exception could only be caused by some kind of failure:

Page 245: Java

Java

Page 245 - Copyright © 2012 Walter Milner - all rights reserved

int[] data = {1, 2, 3, 4, 5}; // write data DataOutputStream out = null; try { out = new DataOutputStream(new FileOutputStream("c:/temp/out.int")); out.writeInt(data.length); // write record count for (int i = 0; i < data.length; i++) { out.writeInt(data[i]); } out.close(); } catch (FileNotFoundException fex) { System.out.println("File not found"); } catch (IOException fex) { System.out.println("Error writing"); } // read data DataInputStream in = null; try { in = new DataInputStream(new FileInputStream("c:/temp/out.int")); int recordCount = in.readInt(); // read record count int d; for (int i = 0; i < recordCount; i++) { d = in.readInt(); System.out.println(d); } } catch (FileNotFoundException fex) { System.out.println("File not found"); } catch (EOFException fex) { System.out.println("Unexpected end of file"); } catch (IOException fex) { System.out.println("Error writing"); } }

Reading and Writing Objects

An ObjectOutputStream can be used to write objects of any class. For this, the class has to declare

that it implements Serializable. In fact this is just a 'marker interface' with no methods. It just

enables the compiler to check that you will read and write objects of a class which should be.

Having constructed an ObjectOutputStream, you can just writeObject() into it, and readObject in

reverse.

You can also write primitives into an ObjectOutputStream, so it is possible to use the technique of

writing the number of objects, followed by the actual objects.

Page 246: Java

Java

Page 246 - Copyright © 2012 Walter Milner - all rights reserved

class Test { public static void main(String[] args) { MyClass obj1 = new MyClass(5, "Testing"); // write data ObjectOutputStream out = null; try { out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("c:/temp/out.objects"))); out.writeObject(obj1); out.close(); } catch (FileNotFoundException fex) { System.out.println("File not found"); } catch (IOException fex) { System.out.println("Error writing"); } // read data MyClass obj2 = null; ObjectInputStream in = null; try { in = new ObjectInputStream(new BufferedInputStream(new FileInputStream("c:/temp/out.objects"))); obj2 = (MyClass) in.readObject(); out.close(); obj2.display(); } catch (ClassNotFoundException c) { System.out.println("Class not found"); } catch (FileNotFoundException fex) { System.out.println("File not found"); } catch (IOException fex) { System.out.println("Error writing"); } } } class MyClass implements Serializable { int x; String s; MyClass(int x, String s) { this.x = x; this.s = s; } void display() { System.out.println(s + " " + x); } } class Test { public static void main(String[] args) { MyClass obj1 = new MyClass(5, "Testing"); // write data ObjectOutputStream out = null; try { out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("c:/temp/out.objects"))); out.writeObject(obj1); out.close(); } catch (FileNotFoundException fex) { System.out.println("File not found"); } catch (IOException fex) { System.out.println("Error writing"); } // read data MyClass obj2 = null; ObjectInputStream in = null; try { in = new ObjectInputStream(new BufferedInputStream(new FileInputStream("c:/temp/out.objects")));

Page 247: Java

Java

Page 247 - Copyright © 2012 Walter Milner - all rights reserved

obj2 = (MyClass) in.readObject(); out.close(); obj2.display(); } catch (ClassNotFoundException c) { System.out.println("Class not found"); } catch (FileNotFoundException fex) { System.out.println("File not found"); } catch (IOException fex) { System.out.println("Error writing"); } } } class MyClass implements Serializable { int x; String s; MyClass(int x, String s) { this.x = x; this.s = s; } void display() { System.out.println(s + " " + x); } }

When the object is written to the file, the name of the class is written, followed by the value of the

fields. When the object is read, there is a check that the class is known - which might fail. This is why

a ClassNotFound exception needs to be caught.

A MyClass object has a String field, which is itself an object. So we might be saving an object which

contains several other objects, each of which contains several other objects and so on. This means

that in general a graph of objects needs to be written. This will work, provided each class is declared

to implement the Serializable interface.

Command line I/O

The class System represents the system the application is executing on. It has a static data field

name 'out', which is an instance of PrintStream, which is a subclass of OutputStream. A PrintStream

has a method println - hence the familar

System.out.println("Hello world");

It also has the less familiar printf:

double x=3; System.out.printf("x = %f \n", x);

which imitates the corresponding C function in stdio.h

There is also the standard error stream:

System.err.println("It's all gone wrong");

but this normally maps to standard out.

Page 248: Java

Java

Page 248 - Copyright © 2012 Walter Milner - all rights reserved

For input, there is System.in, but this takes some work to actually input something. In Java 5 the

Scanner class was introduced. An instance of this parses an input stream, separating it into

primitives and strings - like

Scanner scanner = new Scanner(System.in); int x; x=scanner.nextInt();

Page 249: Java

Java

Page 249 - Copyright © 2012 Walter Milner - all rights reserved

Reflection

The idea of Reflection is to programmatically get information relating to classes.

Typically we have code like

String s = "Hello";

and we know what class s is by looking at the code. But if we cannot do that - how could we find out

about the s object using Java code? That is what the Reflection API is.

We start with the Class object, which represents a class (Class is a class, instances of which

represents classes. Concentrate.)

There are two common ways to get a Class - getClass and forName()

String s="Hello"; Class c = s.getClass(); System.out.println(c); // class java.lang.String try { c=Class.forName("java.lang.Integer"); System.out.println(c); // class java.lang.Integer } catch (ClassNotFoundException cnf) { System.out.println("We've lost Integer"); }

Note the forName must be the fully qualified name - Integer is not found.

Once we have a Class, we can get information about it:

try { Class c = Class.forName("javax.swing.plaf.basic.BasicBorders"); Class d=c.getSuperclass(); System.out.println(d); // class java.lang.Object Class[] e = c.getClasses(); for (Class f:e) System.out.println(f); // ButtonBorder, FieldBorder, MarginBorder... Method[] methods = c.getDeclaredMethods(); for (Method f:methods) System.out.println(f); // getButtonBorder, getInternalFrameBorder, getMenuBarBorder. } catch (ClassNotFoundException cnf) { System.out.println("Class not found");}

getClass returns the runtime class of the object, not the compile-time type of the variable. For

example:

Page 250: Java

Java

Page 250 - Copyright © 2012 Walter Milner - all rights reserved

class Test { public static void main(String[] args) { Base b = new Sub(); // automatic conversion Class c = b.getClass(); System.out.println(c); // get Sub not Base } } class Base { } class Sub extends Base { }

Using Reflection

Usually we would only store a single type in a collection - say an ArrayList of Strings. We woudl do

this with a type parameter:

ArrayList<String> strings = new ArrayList<String>();

Suppose for some reason we want to store 2 types in the same list - a mixture of Strings and Integers

say. The problem is that when we retrieve them, how do we know which type it is? Use reflection:

ArrayList list = new ArrayList(); list.add("One"); list.add("Two"); list.add("Three"); list.add(new Integer(1)); list.add(new Integer(2)); list.add(new Integer(3)); try { for (Object obj : list) { if (obj.getClass() == Class.forName("java.lang.String")) { System.out.println("String : " + obj); } if (obj.getClass() == Class.forName("java.lang.Integer")) { System.out.println("Integer : " + obj); } } } catch (ClassNotFoundException cnf) { }

outputs: String : One String : Two String : Three Integer : 1 Integer : 2 Integer : 3

Page 251: Java

Java

Page 251 - Copyright © 2012 Walter Milner - all rights reserved

Networking - UDP

Protocols

When you answer a phone call, you probably say your name, or 'Hello', or something similar. The

caller expects this - it tells them the call has been picked up. This is an example of a protocol - a set

of rules about how communication will take place.

Digital communication is based on protocols. A very common one is HTTP - hyper-text transfer

protocol. This is the basis for the operation of the 'world-wide web'. FTP is file transfer protocol.

And so on.

TCP/IP and UDP

The internet and most LANs use a set of protocols called TCP/IP, the Internet protocol suite.

One of those is UDP - User Datagram Protocol. This is very simple. The sender constructs a packet of

up to 64k of data, and sends it.The packet includes the IP address of the source and the destination.

The reciever checks for packets whose destination matches their address, and picks up the data.

That's it.

So this is very much like sending something by postal mail - you just put the address on it and send

it.

This is simple but limited. The sender does not know if the packet is received. The sender might reply

with an acknowledgement, but this is not part of the UDP protocol.

Since 64k is not much (for a graphics image, say), so you might send a set of packets. But there is no

guarantee they will arrive in the same sequence they are sent. You could put sequence numbers in

the packets, and the receiver could then check they are all there and re-arrange them if they are out

of sequence - but again this is not part of the UDP protocol.

There are Java Foundation classes for sending and receiving UDP packets.

Ports

A port is just a number (0 to 65535). The purpose is to send different message streams over the

same cable (or wireless channel or other link). Different message streams use different port

numbers. This is a form of multiplexing.

The use of ports is controlled by an organisation called IANA. Port numbers 0 to 1023 are the 'well-

known ports'. For example, http normally runs on port 80. SMTP email transfer is on port 25.

Ports 1024 to 49151 are the registered ports - registered with IANA, mostly by commercial

organisations - for example, 2967 Syantec anti-virus.

49152 to 65535 cannot be registered, and so can be used for temporary purposes.

When we send a UDP packet, we must choose a port number to use (one not already in use). The

receiver needs to listen on that port.

Page 252: Java

Java

Page 252 - Copyright © 2012 Walter Milner - all rights reserved

Sockets

A socket is a software construct for the end-point of a communication - send or recieve. A socket has

an IP address and a port number. Our software to use UDP must make a socket to send packets

through. Java has a set of classes to model sockets.

UDP example

To start with we will have two programs showing UDP send and receive, as simple as possible. Do

this as follows:

Run the two programs on different machines on the same network.

Start the receiver first. It waits to receive a packet. Then start the sender. The receiver

should show the data it receives.

You need to know the IP address of the reciever. ( ipconfig on Windows, /sbin/ifconfig on

Linux)

You may need to stop firewalls

The sender is:

try { DatagramPacket packet; DatagramSocket socket = new DatagramSocket(); // make a UDP socket int port = 49152; // port to use byte[] buf = "Hello".getBytes(); // convert string to array of bytes // the receiver has IP address 172.16.1.37 InetAddress address = InetAddress.getByAddress(new byte[]{(byte) 172, 16, 1, 37}); // construct the packet packet = new DatagramPacket(buf, buf.length,address, port); socket.send(packet); // send it } catch (Exception ex) { System.out.println(ex); }

This just makes a packet and sends it. The receiver is:

byte[] buffer = new byte[256]; // to receive data try { int port = 49152; // matching port DatagramSocket socket = new DatagramSocket(port); // make a socket // prepare a packet with this buffer DatagramPacket packet = new DatagramPacket(buffer, buffer.length); System.out.println("Listening"); // listen (forever) for a packet to this IP address on this port socket.receive(packet); System.out.println("Received : " + new String(buffer)); } catch (Exception ex) { System.out.println(ex); }

This needs to be run first - it just waits until it receives an appropriate packet.

Multicast sockets

The above is not very useful, since we do not usually know the IP address of the computer receiving

the message. We can overcome this by using a MulticastSocket, which can send a UDP packet which

can be received by any address looking in the same 'group':

Page 253: Java

Java

Page 253 - Copyright © 2012 Walter Milner - all rights reserved

int port = 49155; socket = new MulticastSocket(port); group = InetAddress.getByName("224.0.0.2"); socket.joinGroup(group); DatagramPacket packet; packet = new DatagramPacket(buf, buf.length, group, port); socket.send(packet); .. socket.leaveGroup(group);

The group is identified by a Class D IP addresses are in the range 224.0.0.1 to 239.255.255.255,

inclusive.

We can use this as follows

One machine broadcasts its own IP address, then listens for a reply for 1 second

This is repeated until it gets a reply

The other machine listens for as multicast in this group. When it gets one, it sends back its

own IP address

After this, both machines have discovered the IP address of the other. Here is the code for the frist

machine. The listen process is:

static boolean listen() { DatagramSocket socket = null; byte[] buffer = new byte[4]; // to receive data try { int port = 49157; // matching port socket = new DatagramSocket(port); // make a socket socket.setSoTimeout(1000); // timeout after 1 second // prepare a packet with this buffer DatagramPacket packet = new DatagramPacket(buffer, buffer.length); System.out.println("Listening"); // listen for 1 second for a packet to this IP address on this port socket.receive(packet); InetAddress ad= InetAddress.getByAddress(buffer); System.out.println("Received from IP address " + ad); socket.close(); } catch (SocketTimeoutException so) { socket.close(); System.out.println("No answer"); return false; } catch (Exception ex) { socket.close(); System.out.println(ex); } return true; }

We use this from main:

Page 254: Java

Java

Page 254 - Copyright © 2012 Walter Milner - all rights reserved

public static void main(String[] args) { MulticastSocket socket = null; boolean answer = false; byte[] buf = new byte[4]; // Get this machine's IP address try { InetAddress addr = InetAddress.getLocalHost(); byte[] ipAddr = addr.getAddress(); System.arraycopy(ipAddr, 0, buf, 0, 4); } catch (UnknownHostException e) { System.out.println("Can't get IP address"); } InetAddress group = null; try { int port = 49155; socket = new MulticastSocket(port); group = InetAddress.getByName("224.0.0.2"); socket.joinGroup(group); DatagramPacket packet; packet = new DatagramPacket(buf, buf.length, group, port); while (!answer) { socket.send(packet); System.out.println("Broadcasting"); answer = listen(); } socket.leaveGroup(group); } catch (Exception ex) { System.out.println(ex); } // end of broadcast and listen } // end of main

The code for the other machine is:

public static void main(String[] args) { byte[] buffer = new byte[4 ]; try { int port = 49155; MulticastSocket socket = new MulticastSocket(port); InetAddress group = InetAddress.getByName("224.0.0.2"); socket.joinGroup(group); DatagramPacket packet = new DatagramPacket(buffer, buffer.length); System.out.println("Listening"); socket.receive(packet); // buffer now contains IP address of other machine System.out.println("Received : "); reply(buffer); socket.leaveGroup(group); socket.close(); } catch (IOException ex) { System.out.println("In main: "+ex); } }

and reply() is:

Page 255: Java

Java

Page 255 - Copyright © 2012 Walter Milner - all rights reserved

static void reply(byte[] buffer) { DatagramSocket socket = null; try { int port = 49157; socket = new DatagramSocket(port); // form address of other machine InetAddress address = InetAddress.getByAddress(buffer); byte[] buf = new byte[4]; try { // get our address into buf InetAddress add = InetAddress.getLocalHost(); buf =add.getAddress(); } catch (UnknownHostException uh) { System.out.println("Can't get address"); } // send our address back DatagramPacket packet = new DatagramPacket(buf, buf.length, address,port); socket.send(packet); socket.close(); } catch (IOException ex) { System.out.println(ex); } }

The logic of this could be modified to turn the first machine into a server, finding clients on the

network. Typically a new thread would be started to 'talk' to each client.

Page 256: Java

Java

Page 256 - Copyright © 2012 Walter Milner - all rights reserved

Networking - TCP

We have seen that UDP is like postal mail. You make a packet, write the address on it, and post it. It

might reach its destinantion.

TCP (Transmission Control Protocol) is like a phone call. You dial the number, and a connection is

established. You can talk and listen, then you hang up and the connection is closed.

TCP packets will be received in the order they are sent, and a missing packet can be detected.

TCP classes

Java has a Socket class to model a TCP socket. This has getInputStream and getOutputStream

methods to get i/o streams so that sockets can be written to and read from.

But how to start up? There is a need for a mechanism whereby a machine can wait for a connection,

and then i/o between the sockets can proceed. The ServerSocket class can do this.

ServerSocket example

In the following example, one machine (client) can take keyboard input and send it over a TCP

connection to another (server).

The server first creates a ServerSocket and waits for a connection from a client:

ServerSocket serverSocket = null; try { // make a ServerSocket on port 50000 serverSocket = new ServerSocket(50000); } catch (IOException e) { System.out.println(e); System.exit(1); } Socket clientSocket = null; try { // wait for a connection clientSocket = serverSocket.accept(); } catch (IOException e) { System.out.println(e); System.exit(2); }

It then repeatedly reads input from it and displays it. If the input is 'bye' the connection is closed:

try { BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println(inputLine); if (inputLine.equals("bye")) { break; } } serverSocket.close(); clientSocket.close(); } catch (IOException ioe) { System.out.println(ioe); }

The client firstly needs to create a TCP connection with the server machine (name "WALTER-HP") on

the same port, and get an output stream to it:

Page 257: Java

Java

Page 257 - Copyright © 2012 Walter Milner - all rights reserved

Socket socket = null; PrintWriter out=null; try { socket = new Socket("WALTER-HP", 50000); out = new PrintWriter(socket.getOutputStream(), true); } catch (UnknownHostException e) { System.err.println(e); // can't find computer System.exit(1); } catch (IOException e) { System.err.println(e); // can't connect System.exit(2); }

It then gets an input stream from the keyboad, and in a loop reads from it and sends to teh output

stream, until 'bye' is entered:

BufferedReader stdIn = new BufferedReader( new InputStreamReader(System.in)); String userInput; try { while ((userInput = stdIn.readLine()) != null) { out.println(userInput); if (userInput.equals("bye")) break; } out.close(); stdIn.close(); socket.close(); } catch (IOException ioe) { System.out.println(ioe); }

This only handles one client, but several can be dealt with at the same time by repeatedly waiting for

an accept and starting a new thread to communicate with the client.

This code requires the client to know the machine name of the server. This can be fixed by having

the server do a UDP multicast, so the client can first discover any available server on the network,

then proceed to connect and communicate.

Page 258: Java

Java

Page 258 - Copyright © 2012 Walter Milner - all rights reserved

Networking - URLs

Here is an idea. A client could run a program (call it a 'user agent', UA) which can display a file. The

UA can establish a TCP connection with a server, and request a file held on the server. The server can

find the file, saved locally, and send it back, and the UA can display it. The file could contain special

'tags' indicating links to other files, possibly on other servers. When the user clicks on the link, a new

file is fetched and displayed.

That idea is the hyper-text transfer protocol http, and most UAs are called browsers. That could all

be programmed with TCP sockets. But because it is so common, Java offers a higher-level class called

URL which already implements the lower level communication for you.

Reading a webpage

The URL class makes it extremely easy to read a web page:

try{ URL url = new URL("http://www.google.com/"); BufferedReader in = new BufferedReader( new InputStreamReader(url.openStream())); String inputLine; while ((inputLine = in.readLine()) != null) System.out.println(inputLine); in.close(); } catch (Exception e) { System.out.println(e); }

CGI and URLs

The HTTP protocol is very simple. A 'command' is sent to the server. The most common command is

GET - in other words, get me a web page. Several of the others are usually disabled for obvious

security reasons - PUT to upload and web page, and DELETE.

Sometimes we need to supply data to the server, and expect a response, normally in the form of an

html document. This happens when we fill in a form on a web page. Data in the form is sent to the

server, a server-side script collects the data and processes it, and outputs a web page containing the

response.

The 'Common Gateway Interface' CGI provides two ways of uploading data - GET and POST. Here we

use GET.

This method puts the data in a query string which is appended to the URL, in the form of name value

pairs. For example, in

waltermilner.com/add.php?x=2&y=4

the start of the query string is marked by the ? and uploads a name x with a value 2, and a name y

with a value 4.

This is being sent to the script add.php in the domain waltermilner.com. This is a very simple

technique - but the fact that the data is visible in the URL means it cannot be used where there are

security concerns.

Page 259: Java

Java

Page 259 - Copyright © 2012 Walter Milner - all rights reserved

Usually CGI access comes from a web page in a browser. Can we do it from a Java program? Simple:

try { URL url = new URL("http://www.waltermilner.com/add.php?x=2&y=4"); BufferedReader in = new BufferedReader( new InputStreamReader(url.openStream())); String result = ""; String inputLine; while ((inputLine = in.readLine()) != null) { result += inputLine; } in.close(); System.out.println(result); } catch (Exception e) { System.out.println(e); }

which outputs 6.

The server-side script for this is in PHP:

<?php $x=$_GET['x']; $y=$_GET['y']; $z=$x+$y; echo $z; ?>

$_GET lets us get the values of variables supplied in the query string, and echo outputs something -

which the web server sends back to us. Variables in PHP are preceded by a $.

HttpURLConnection and POST

In the POST method, names and values are sent in a data block which appears at the server as

'environment variables'. To do this from Java we can use the HttpURLConnection class. This is a

concrete subclass of the abstract URLConnection, with appropriate features for http transfers. First

create the connection and do the request:

URL url; String params="x=2&y=4"; HttpURLConnection connection = null; try { //Create connection url = new URL("http://waltermilner.com/add.php"); connection = (HttpURLConnection)url.openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); // want to output to connection. // input is true by default // Send request DataOutputStream wr = new DataOutputStream ( connection.getOutputStream ()); wr.writeBytes (params); wr.close (); } catch (Exception ex) { System.out.println(ex); System.exit(0); }

then get the response:

Page 260: Java

Java

Page 260 - Copyright © 2012 Walter Milner - all rights reserved

try{ //Get Response InputStream is = connection.getInputStream(); BufferedReader rd = new BufferedReader(new InputStreamReader(is)); String line; String result=""; while((line = rd.readLine()) != null) { result+=line; } rd.close(); connection.disconnect(); System.out.println(result); } catch (Exception e) { System.out.println(e); }

The corresponding script is changed to expect the data in POST:

<?php $x=$_POST['x']; $y=$_POST['y']; $z=$x+$y; echo $z; ?>