Java

March 28, 2017 | Author: Rulz Andrei | Category: N/A
Share Embed Donate


Short Description

Download Java...

Description

Java

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 1 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 2 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 3 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 4 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 5 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 6 - Copyright © 2012 Walter Milner - all rights reserved

Java

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:

Command line interface

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

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

Java depending on the version. Check you have this, then make sure this is included in the list of folders in the path. Google how set the path for your version of Windows.

to

Type in cd Desktop This changes directory to your Desktop. Type in

Running java.exe

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

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

Java 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 9 - Copyright © 2012 Walter Milner - all rights reserved

Java

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

NetBeans 7.1.2 running on openSUSE Linux

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 Figure 1

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.

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

Java 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 11 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 . So if you wrote ProgramTwo.java, say javac ProgramTwo.java 4. Run it by saying java . 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 12 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 13 - Copyright © 2012 Walter Milner - all rights reserved

Java

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

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

Source code and byte code

Java 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 15 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 16 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 byte short int long

Memory usage (bytes) 1 2 4 8

Minimum value

Maximum

-128 -32,768 -2,147,483,64 -9,223,372,036,854,775,808

127 32,767 2,147,483,63 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 17 - Copyright © 2012 Walter Milner - all rights reserved

Java

Variables Java programs handle data by using variables. Here is a program fragment which is pretty easy to see what it does: int int int x = y = z =

x; y; z; 2; 3; 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 18 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 19 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 20 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 21 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 22 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 23 - Copyright © 2012 Walter Milner - all rights reserved

Java

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)

Memory

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.

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;

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.

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

Java The obvious way to do this is with two statements: x=y; y=x;

Suppose we trace this: Values in memory

x

1

y

2

x

2

y

2

x

2

y

2

Program step

Effect

Initial state

x=y; y=x;

x=y; y=x;

The value from y (2) has been written into cell x, overwriting the previous 1 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

x

1

y

2

temp

?

x

1

y

2

temp

1

x

2

y

2

temp

1

Program step

Effect

Initial state

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

We've made a temporary copy of x

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

Write the value of y into x

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

Java x

2

y

1

temp

1

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

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

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.

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

Java

Expressions Something like 4-3 is an expression. In an assignment statement, we say something like x = ; 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 27 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 28 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 postincrement, 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 29 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 ( )

The 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 30 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 x

?

y

?

x

12

y

?

x

12

y

1

x

12

y

2

x

12

y

2

Program

Comment

int x; int y; Scanner myScanner = new Scanner(System.in); x=myScanner.nextInt(); y=1; if (x>10) y=2; System.out.println(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

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

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

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

2 is output

scanner object created (omitted) and 12 input

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

Java 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 32 - Copyright © 2012 Walter Milner - all rights reserved

Java 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(x5 && x5 && 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 xyz xzy yxz yzx zxy zyx Here we go:

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

Java 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 37 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 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>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 1234>>1 1234>>2 1234>>3 1234>>4

0000 0000 0000 0000 0000 0100 1101 0010 0000 0000 0000 0000 0000 0010 0110 1001 0000 0000 0000 0000 0000 0001 0011 0100 0000 0000 0000 0000 0000 0000 1001 1010 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 2 1 0 -1 -2 -3

0000 0000 0000 0000 0000 0000 0000 0011 0000 0000 0000 0000 0000 0000 0000 0010 0000 0000 0000 0000 0000 0000 0000 0001 0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1110 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 52 - Copyright © 2012 Walter Milner - all rights reserved

Java Inversion ~ switches 1s to 0s and vice versa. Left shift (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]; // data[0] = new Pair(3, 2); // data[1] = new Pair(2, 2); data[2] = new Pair(1, 2); Arrays.sort(data); // // see what we've got for (int i = 0; i < data.length; data[i].show(); }

make an array put 3 elements in sort i++) {

The output is: 12 22 32

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 120 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 121 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 import import import

java.awt.event.ActionEvent; java.awt.event.ActionListener; javax.swing.JButton; 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 122 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 123 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 124 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 125 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 126 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 127 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 packageprivate. That means they can be accessed within their package, only, and not from outside.

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

Java 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:

private default package-private protected public

data yes - use get/set methods constant data only constant data only constant data only

methods class-internal only if needed by package if to be used in sub-class in different package 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 129 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 130 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 131 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 132 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 133 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 Name: Jane Jones Department: Marketing Name: Joe Jeffs Department: Production Name: John Smith Department: Marketing

Salary: Salary: Salary: Salary:

20000 22000 19000 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 .

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 134 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 .

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 135 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 static static static

}

Department[] departments = new Department[10]; int departmentCount = 0; Employee[] employees = new Employee[10]; 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 136 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 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 148 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 -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 183 - Copyright © 2012 Walter Milner - all rights reserved

Java if (cells[0][0].getContents() == c && cells[0][2].getContents() == c) { result = true; } if (cells[1][0].getContents() == c && cells[1][2].getContents() == c) { result = true; } if (cells[2][0].getContents() == c && cells[2][2].getContents() == c) { result = true; } //check columns if (cells[0][0].getContents() == c && cells[2][0].getContents() == c) { result = true; } if (cells[0][1].getContents() == c && cells[2][2].getContents() == c) { result = true; } if (cells[0][2].getContents() == c && cells[2][2].getContents() == c) { result = true; } // leading diagonal if (cells[0][0].getContents() == c && cells[2][2].getContents() == c) { result = true; } //other diagonal if (cells[0][2].getContents() == c && cells[2][0].getContents() == c) { result = true; } if (result) { { gameOver = true; label.setText("Game over"); }

cells[0][1].getContents() == c &&

cells[1][1].getContents() == c &&

cells[2][1].getContents() == c &&

cells[1][0].getContents() == c &&

cells[1][1].getContents() == c &&

cells[1][2].getContents() == c &&

cells[1][1].getContents() == c &&

cells[1][1].getContents() == c &&

}

} }

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 184 - Copyright © 2012 Walter Milner - all rights reserved

Java 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() int col = (int) (Math.random() while (board.getCell(row, col) row = (int) (Math.random() col = (int) (Math.random() } // and put an O there board.set(row, col, 'O'); }

* 3); * 3); != ' ') { * 3); * 3);

}

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 185 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 coordinates - 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 186 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 187 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 188 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 189 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 190 - Copyright © 2012 Walter Milner - all rights reserved

Java If you look through the Java API, you will see countless examples of oveloaded constructors and methods.

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

Java

More OOP This part covers further aspects of object-oriented programming.

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

Java

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 193 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 194 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 195 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 196 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 197 - Copyright © 2012 Walter Milner - all rights reserved

Java

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\NetBeansProj ects\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 198 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 199 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 200 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 201 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 202 - Copyright © 2012 Walter Milner - all rights reserved

Java void reverse() { class Stack { // start definition of local class ArrayList 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 203 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 204 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 {

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 205 - Copyright © 2012 Walter Milner - all rights reserved

Java class LinkedList { 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 strings = new LinkedList(); strings.add("One"); strings.add("Two"); strings.add("Three"); strings.traverse(); // One Two Three LinkedList 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 strings = new LinkedList(); LinkedList objects = strings;

the second line is a compile error.

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

Java 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 LinkedList arrayToLinkedList(E[] array) { LinkedList 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 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 207 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 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 { 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 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 208 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 { 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 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, it becomes just List ).

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

Java 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 { 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 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 stringArray = new MyArray(100, 200);

creates an array with first element index 100, and last is 200.

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

Java

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 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 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 211 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 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: 11 12 22 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 212 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 { 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 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 213 - Copyright © 2012 Walter Milner - all rights reserved

Java LinkedList 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 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 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 214 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 215 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 216 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 217 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 218 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 219 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 220 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 221 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 222 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 223 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 224 - Copyright © 2012 Walter Milner - all rights reserved

Java

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

Heavyweight processes

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.

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

Java 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

Java lightweight threads

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:

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

Java 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 227 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 228 - Copyright © 2012 Walter Milner - all rights reserved

Java 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"); } thread1, thread2 and main }

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: main, thread1 then thread2

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

Java 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 230 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 231 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 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 233 - Copyright © 2012 Walter Milner - all rights reserved

Java 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.' Thread sequence Synchronized statement This is a Java keyword which we can apply to a statement. We say:

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

Java synchronized (someObject) ;

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 235 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 236 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 ref = new

but not ref = new

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 237 - Copyright © 2012 Walter Milner - all rights reserved

Java "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 238 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 239 - Copyright © 2012 Walter Milner - all rights reserved

Java 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:

a) b) c) d)

Base d = (Base) new Sub(); // OK - cast to a base class Base e = (Base) new Object(); // run-time class cast exception Object f = (Base) new Object(); // runtime Object g=(Object) new Base(); // OK - cast to a base class Base h=(Object) new Base(); //No compile time Incompatible types 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 240 - Copyright © 2012 Walter Milner - all rights reserved

Java

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.

Not quite so new

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.

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

Java 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 242 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 243 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 244 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 245 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 246 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 247 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 248 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 249 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 strings = new ArrayList();

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 250 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 'wellknown 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 251 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 252 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 253 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 254 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 255 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 256 - Copyright © 2012 Walter Milner - all rights reserved

Java 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 257 - Copyright © 2012 Walter Milner - all rights reserved

Java

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 258 - Copyright © 2012 Walter Milner - all rights reserved

Java 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:

$_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 259 - Copyright © 2012 Walter Milner - all rights reserved

Java 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:

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

View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF