Recent Comments widget by VAMPIRE
Showing posts with label learn java language online. Show all posts
Showing posts with label learn java language online. Show all posts

Friday, July 1, 2011

lesson 9-Streams and Exceptions

9. Streams and

Exceptions

To be able to read and

write files

To understand the

concepts of text and

binary streams

To learn how to throw

and catch exceptions

To be able to process

the command line

To be able to

read and write

objects using

serialization

Streams, Readers, and

Writers

There are two

different ways to store

data: text or binary

formats.

In text format, data

items are represented

in human-readable

form, as a sequence of

characters. For

example, the interger

12345 is stored as the

sequence of five

characters:

‘1’ ‘2’ ‘3’ ‘4’ ‘5’

In binary form, data

items are represented

in bytes. For example,

the integer 12345 is

stored as a sequence

of four bytes:

0 0 48 57 (because

12345 = 48*256 + 57)

We use the Reader and

Writer classes and

their subclasses to

process text files:

FileReader reader =

new FileReader

(“input.txt”);

int next = reader.read()

; // read() will return int

char c;

if (next != -1) // returns

-1 if the end of input

c = (char) next;

FileWriter writer =

new FileWriter

(“output.txt”);

Text input and output

are more convenient

for humans.

To read text data from

a disk file, we create a

FileReader object:

FileReader reader =

new FileReader

(“input.txt”);

To write text data to a

disk file, we use

FileWriter:

FileWriter writer =

new FileWriter

(“Output.txt”);

The Reader class has a

method read to read a

single character at a

time. However, the

read method returns an

int, thus we have to

cast it to a char.

Reader reader = …;

int next = reader.read()

;

char c;

if (next != -1)

c = (char)next;

We use the

InputStream and

OutputStream classes

and their subclasses to

process binary files:

FileInputStream in = new

FileInputStream

(“input.dat”);

int next = in.read();

byte b;

if (next != -1) // returns -1 if

the end of input

b = (byte) next;

FileOutputStream

output = new

FileOutputStream

(“output.dat”);

Binary storage is more

compact and more

efficient.

To read binary data

from a disk file, we

create a

FileInputStream

object:

FileInputStream

inputStream = new

FileInputStream

(“input.dat”);

To write binary data to

a disk file, we use

FileOutputStream:

FileOutputStream

outputStream = new

FileOutputStream

(“output.dat”);

The InputStream class

has a method read to

read a single byte at a

time. The method also

returns an int, thus we

have to cast it to a

byte.

InputStream in = …;

int next = in.read();

byte b;

if (next != -1)

b = (byte)next;

The Writer and

FileOutputStream

classes have a write

method to write a

single character or

byte.

Reading and Writing

Text Files

We construct a

FileWriter object from

the file name:

FileWriter writer =

new FileWriter

(“output.txt”);

We then send a

character at a time to

the file by calling the

write method.

However, the output

we have is in the form

of numbers and strings

so we need another

class whose task is to

break up numbers and

strings into individual

characters and send

them to a writer.

This class is called

PrintWriter.

PrintWriter out = new

PrintWriter(writer);

Next, we can use the

print and println

methods to print

numbers, objects, and

strings:

out.print(29.95);

out.println(new

Rectangle(5, 10, 15, 25)

);

out.println(“Hello.”);

Reading text files is

less convenient, we

have to use the

BufferedReader class,

which has a readLine

method .

After reading a line of

input, we can convert

the strings to integer

or double as needed.

Reading and Writing

Text Files

To write:

FileWriter writer =

new FileWriter

(“output.txt”);

PrintWriter out = new

PrintWriter(writer);

out.print(29.95);

out.println(new

Rectangle(5, 10, 15, 25)

);

out.println(“Hello,

World!”);

To read:

FileReader reader =

new FileReader

(“input.txt”);

BufferedReader in =

new BufferedReader

(reader);

String inputLine =

in.readLine();

double x =

Double.parseDouble

(inputLine);

When we are done

reading/writing from a

file, we should close

the files:

reader.close();

writer.close();

Before we can put

these input/output

classes to work, we

need to know about

exception handling.

All classes for reading

and writing are defined

in the java.io package.

Exception Handling

An exception is an

indication that a

problem occurred

during the program’s

execution.

When a method

detects a problematic

situation, what should

it do?

The methods should

return an indicator

whether it succeeded

or failed.

The exception-

handling mechanism

has been designed to

solve these problems.

When we detect an

error, we only need to

throw an appropriate

exception object.

The programmer

encloses in a try block

the code that may

generate an exception.

The try block is

followed by zero or

more catch blocks.

Each catch block

specifies the type of

exception it can catch

and contains an

exception handler.

An optional finally

block provides code

that always executes

regardless of whether

or not an exception

occurs.

If there is no catch

blocks following a try

block, the finally block

is required.

When an exception is

thrown, program

control leaves the try

block and the catch

blocks are searched.

If the type of the

thrown exception

matches the

parameter type in one

of the catch blocks,

the code for that catch

block is executed.

If a finally block

appears after the last

catch block, it is

executed regardless

of whether or not an

exception is thrown.

An exception can be

thrown from

statements in the

method, or from a

method called directly

or indirectly from the

try block.

The point at which the

throw is executed is

called the throw point.

The throw statement

is executed to indicate

that an exception has

occurred (i.e., a

method could not

complete

successfully).

This is called throwing

an exception.

Throwing an exception

is simple, the Java

library provides many

classes to signal all

sorts of exceptional

conditions.

For example, to signal

an unexpected end of

file, you can use the

EOFException, a

subclass of the

IOException class,

which denotes input/

output errors.

We make an object of

the exception class,

and then throw it.

For example, suppose

we write a method

that reads a product in

from a reader:

public class Product

{ private String name;

private double price;

private int score;

public void read

(BufferedReader in)

{ // read product name

name = in.readLine();

// read product price

String inputLine =

in.readLine();

price =

Double.parseDouble

(inputLine);

// read product score

inputLine = in.readLine

();

score =

Integer.parseInt

(inputLine);

}

}

What happens if we

reach the end of input?

String inputLine =

in.readLine();

if (inputline == null)

// do something

We can throw an

exception as follows:

String inputLine =

in.readLine();

if (inputline == null)

{ EOFException

exception = new

EOFException(“End of

file when reading

price.”);

throw exception;

}

Or we can just throw

the object that the

new operator returns:

String inputLine =

in.readLine();

if (inputline == null)

throw new

EOFException(“End of

file when reading

price.”);

Throwing a new

exception like an

example above is used

when you want to

generate an exception

under your control

rather than letting Java

generate it for you.

Throwing Exceptions

Throwing Exceptions

throw

exceptionObject;

throw new

IllegalArgumentExcept

ion();

...

String input =

in.readLine();

if (input == null)

throw new

EOFException(“EOF

when reading”);

When we throw an

exception, the method

exits immediately.

Execution does not

continue with the

method’s caller but

with an exception

handler.

Catching Exceptions

When an exception is

thrown, an exception

handler needs to catch

it.

We must install

exception handler for

all exceptions that our

program might throw.

We install an

exception handler with

the try statement.

Each try block contains

one or more method

calls that may cause an

exception, and catch

clauses for all

exception types.

Catching Exceptions

try

{ statement

}

catch(ExceptionClass

exceptionObject)

{ statement

}

catch(ExceptionClass

exceptionObject)

{ statement

}

finally

{ ….

}

if use "try block" you

must have whichever

"catch" or "finally"

If a try block has a

corresponding finally

block, the finally block

will be executed even

if the try block is

exited with return,

break or continue; then

the effect of the

return, break or

continue will occur.

When the catch

(IOException e) block

is executed, then

some method in the

try block has failed

with an IOException,

and that exception

object is stored in the

variable e.

try

{ BufferedReader in =

new BufferedReader(

new

InputStreamReader

(System.in));

System.out.println

(“How old are you?”);

String input =

in.readLine();

int age =

Integer.parseInt(input)

;

age++;

System.out.println

(“Next year, you’ll be ”

+ age);

}

catch(IOException e)

{ System.out.println

(“Input/Output error ” +

e);

}

catch(

NumberFormatExcepti

on e)

{ System.out.println

(“Input was not a

number”);

}

The try block contains

six statements with

two potential

exceptions that can be

thrown in this code.

The readLine method

can throw an

IOException, and

Integer.parseInt can

throw a

NumberFormatExcepti

on.

If either of these

exceptions is thrown,

the rest of the

instructions in the try

block are skipped.

Finally

Suppose a method

open a file, calls one

or more methods, and

then close the file:

BufferedReader in;

in = new

BufferedReader(new

FileReader(“input.txt”))

;

readProducts(in);

in.close();

Next, suppose that one

of the methods throws

an exception, then the

call to close is never

executed.

We solve this problem

by placing the call to

close inside a finally

clause:

BufferedReader in =

null;

try

{ in = new

BufferedReader(

new FileReader

(“input.txt”));

readProducts(in);

}

// optional catch

clauses here

finally

{ if (in != null)

in.close();

}

Checked Exception

Exceptions fall into

two categories, called

checked and

unchecked exceptions.

When you call a

method that throws a

checked exception,

you must tell the

compiler what we are

going to do about the

exception if it is

thrown.

We do not need to

keep track of

unchecked exceptions.

Exceptions that belong

to subclasses of

RuntimeException are

unchecked.

Checked Exceptions:

For example: All

subclasses of

IOException;

InterruptedException;

invent yourself by

subclassing Exception.

Unchecked Exceptions:

For example:

RuntimeException and

all subclasses;

ArithmeticException;

IllegalArgumentExcept

ion;

NumberFormatExcetpi

on;

IndexOutOfBoundsExce

ption;

NullPointerException;

invent yourself by

subclassing

RuntimeException

Checked exceptions

must be listed in

method's throws

clause, if we do not

provide catch clause.

Exception Class

Hierarchy

Suppose we want to

throw an IOException

in a method that call

BufferedReader.

readLine.

The IOException is a

checked exception, so

we need to tell the

compiler what we are

going to do about it.

We have two choices:

We can place the call

to the readLine inside a

try block and supply a

catch clause.

We can simply tell the

compiler by tagging

the method with a

throws clause.

Throws Clauses

If we want the

exception to go

uncaught and rely on

the propagation

mechanisms to catch

the exception

elsewhere, we use a

throws clause in the

method header.

Use a throws clause

only if a method will

throw one of the

checked exceptions.

public class Product

{ public void read

(BufferedReader in)

throws IOException

{ ... }

}

The throws clause

signals the caller that

it may encounter an

IOException.

If a method can throw

multiple checked

exceptions, we

separate them by

commas:

public void read

(BufferedReader in)

throws IOException,

FileNotFoundException

Error do not need to be

listed, nor do

RuntimeException

Examples: an out-of-

bounds array subscript,

arithmetic overflow,

division by zero,

invalid method

parameters, memory

exhaustion.

Example

In the next example,

we pass along all

exceptions of type

IOException that

readLine may throw.

When we encounter an

unexpected end of file,

we report it as an

EOFException.

For an expected end of

file, if the end of file

has been reached

before the start of a

record, the method

simply returns false.

If the file ends in the

middle of a record (an

unexpected end of file)

, then we throw an

exception.

public class Product

{ public boolean read

(BufferedReader in)

throws IOException

{ // read product name

name = in.readLine();

if (name == null) return

false;

String inputLine =

in.readLine();

if (inputLine == null)

throw new

EOFException (“EOF

when reading price.”);

price =

Double.parseDouble

(inputLine);

inputLIne = in.readLine

();

if (inputLine == null)

throw new

EOFException (“EOF

when reading score.”);

score =

Integer.parseInt

(inputLine);

return;

}

private String name;

private double price;

private int score;

}

Example

The following method

reads product records

and puts them into a

panel.

It is unconcerned with

any exceptions.

If there is a problem

with the input file, it

simply passes the

exception to its caller.

public void

readProducts

(BufferedReader in)

throws IOException

{ boolean done = false;

while (!done)

{

Product p = new

Product();

if (p.read(in))

panel.addProduct(p);

else

done = true;

}

}

Next, we implement

the user interaction.

We ask the user to

enter a file name and

read the product file.

If there is a problem,

we report the problem.

The program is not

terminated, and the

user has a chance to

open a different file.

public void openFile()

{ BufferedReader in =

null;

try

{ // select file name

. . .

in = new

BufferedReader(new

FileReader(selectFile))

;

readProducts(in);

}

catch(

FileNotFoundException

e)

{ JOptionPane.

showMessageDialog

(null, “Bad filename.

Try again.”);

}

catch(IOException e)

{ JOptionPane.

showMessageDialog

(null, “Corrupted file.

Try again.”);

}

finally

{ if (in != null)

try

{ in.close();

}

catch(IOException e)

{ JOptionPane.

showMessageDialog

(null, “Error closing

file.”);

}

}

}

Example

import java.io.*;

public class StringEx2 {

public static void main

(String args[]) throws

IOException {

FileWriter writer = null;

try {

String input2;

InputStreamReader

reader = new

InputStreamReader

(System.in);

BufferedReader

console = new

BufferedReader

(reader);

System.out.print("Enter

filename ");

input2 =

console.readLine();

writer = new

FileWriter(input2);

PrintWriter out = new

PrintWriter(writer);

double gpa;

System.out.print("Enter

Your GPA ");

input2 =

console.readLine();

gpa =

Double.parseDouble

(input2);

System.out.println

("Your GPA is " + gpa);

out.println(gpa);

}

catch(

NumberFormatExcepti

on e)

{ System.out.println

("Input was not a

number.");

}

catch(

FileNotFoundException

e)

{ System.out.println

("Bad filename. Try

again.");

}

finally {

writer.close();

}

}

}

Example: Reading Input

Data in a Graphical

Program

Recall the BestProduct

program that reads

product data from the

keyboard and then

marks the best buys.

In this example, we

will use a text editor

to write the data

values into a file and

then specify the name

of the file when the

data are to be used.

This program will

display its result in a

graph.

Prices grow in the x-

direction, performance

grows in the y-

direction.

// PlotProducts.java

/**

Reads products and

adds them to the

product panel.

@param in the buffered

reader to read from

*/

public void

readProducts

(BufferedReader in)

throws IOException

{ ...

boolean done = false;

while (!done)

{ Product p = new

Product();

if (p.read(in))

panel.addProduct(p);

else // last product

read

done = true;

}

}

// PlotProducts.java

/**

Handles the open file

menu. Prompts user

for file

name and reads

products from file.

*/

public void openFile()

{ BufferedReader in =

null;

try

{ // show file chooser

dialog

JFileChooser chooser

= new JFileChooser();

if (chooser.

showOpenDialog(null)

==

JFileChooser.APPROVE_

OPTION)

{ // construct reader

and read products

File selectedFile =

chooser.

getSelectedFile();

in = new

BufferedReader(new

FileReader

(selectedFile));

readProducts(in);

}

}

catch(

FileNotFoundException

e)

{ JOptionPane.

showMessageDialog

(null, "Bad filename.

Try again.");

}

catch(IOException e)

{ JOptionPane.

showMessageDialog

(null, "Corrupted file.

Try again.");

}

finally

{ if (in != null)

try

{ in.close();

}

catch(IOException e)

{ JOptionPane.

showMessageDialog

(null, "Error closing

file.");

}

}

}

Command Line

Arguments

There are several

methods of starting a

program:

By selecting “Run” in

the compilation

environment

By clicking on an icon

By typing the name of

the program at a

prompt in a terminal or

shell window

The latter method is

called “invoking the

program from the

command line”.

For the latter method,

we can also type in

additional information

that the program can

use.

These additional

strings are called

command line

arguments.

For example, if we

start a program with

the command line

java Prog –v input.txt

then the program

receives two

command line

arguments: the strings

“-v” and “input.txt”.

Java usually interprets

strings with a – as

options and other

strings as file names.

Command line

arguments are placed

in the args parameter

of the main method:

public static void main

(String[] args)

{ …

}

Thus args contains

two strings

args[0] = “-v”

args[1] = “input.txt”

Encryption

Encryption is a method

used for scrambling a

file so that it is

unreadable except to

those who know the

decryption method and

the secret keyword.

The person performing

any encryption

chooses an encryption

key; here we use a

number between 1 and

25 as the key.

This key indicates the

shift to be used in

encrypting each letter.

For example, if the key

is 3, replace A with a

D, B with an E, and so

on.

Encryption

To encrypt/decrpt data

java Crypt input.txt

encrypt.txt

java Crypt -d -k11

encrypt.txt output.txt

The program takes to

following command

line arguments:

- An optional -d flag to

indicate decryption

- An optional

encryption key, -k flag

- input file name

- output file name

If no key is specified,

then 3 is used.

import java.io.*;

public class Crypt

{ public static void

main(String[] args)

{ boolean decrypt =

false;

int key = DEFAULT_KEY;

FileReader infile = null;

FileWriter outfile =

null;

if (args.length < 2 ||
args.length > 4) usage

();

// gather command line

arguments and open

files

try

{ for (int i = 0; i <
args.length; i++)
{ if (args[i].substring(0,
1).equals("-"))
// it is a command line
option
{ String option = args[i]
.substring(1, 2);
if (option.equals("d"))
decrypt = true;
else if (option.equals
("k"))
{ key =
Integer.parseInt
(args[i].substring(2));
if (key < 1 || key >=

NLETTERS)

usage();

}

}

else

{ if (infile == null)

infile = new FileReader

(args[i]);

else if (outfile == null)

outfile = new

FileWriter(args[i]);

}

}

}

catch(IOException e)

{ System.out.println

("Error opening file");

System.exit(0);

}

if(infile == null || outfile

== null) usage();

// encrypt or decrypt

the input

if (decrypt) key =

NLETTERS - key;

try

{ encryptFile(infile,

outfile, key);

infile.close();

outfile.close();

}

catch(IOException e)

{ System.out.println

("Error processing

file");

System.exit(0);

}

}

public static void

usage()

{ System.out.println

("Usage: java Crypt [-

d] [-kn] infile outfile");

System.exit(1);

}

public static char

encrypt(char c, int k)

{ if ('a' <= c && c <= 'z')

return (char)('a' + (c - 'a'

+ k) % NLETTERS);

if ('A' <= c && c <= 'Z')

return (char)('A' + (c -

'A' + k) % NLETTERS);

return c;

}

public static void

encryptFile(FileReader

in, FileWriter out, int k)

throws IOException

{ while (true)

{ int next = in.read();

if (next == -1) return; //

end of file

char c = (char)next;

out.write(encrypt(c, k))

;

}

}

public static final int

DEFAULT_KEY = 3;

public static final int

NLETTERS = 'z' - 'a' + 1;

}

Random Access

Suppose we want to

change the prices of

some products that we

stored in a file, the

simplest technique is:

read data into an array

Update data

Save data back to a file

What happens if the

data is very large?

There will be a lot of

much reading and

writing.

Up til now, we read to

a file and write to a file

one item at a time, this

access pattern is

called sequential

access.

Next, we will learn

how to access specific

locations in a file and

change just those

locations. This access

pattern is called

random access.

Only disk files support

random access. Each

disk file has a special

file pointer position.

Normally, the file

pointer is at the end of

the file, and any output

is appended to the end.

If we move the file

pointer to the middle

of the file, the output

overwrite what is

already there.

Then the next read

command starts

reading at the file point

location.

In Java, we use a

RandomAccessFile

object a access a file

and move a file

pointer.

We can open a file

either for reading only

(“r”) or for reading and

writing (“rw”).

To open a random-

access file, we supply

a file name and a string

to specify the open

mode.

Random Access File

To open the file

product “product.dat”

for both reading and

writing, we write:

RandomAccessFile f =

new

RandomAccessFile

(“product.dat”, "rw");

To move file pointer

to byte n from the

beginning of the file:

f.seek(n);

To find out the current

position of the file

pointer (counted from

the beginning of the

file):

n = f.getFilePointer();

To find out the number

of bytes in a file:

long filelength =

f.length();

When the new data is

longer than the current

data, the update will

overwrite the old data.

For example, if the

price is increased by

50, the new price has

more digits so it

overwrites the

newline symbol that

separates the fields.

We must give each

field a fixed size that is

sufficiently large.

This also makes it

easy to access the nth

data in a file, without

having to read in the

first n-1 data.

When storing numbers

in a file with fixed

record sizes, it is

easier to store them in

binary format, not in

text format.

The readInt and

writeInt methods read

and write integers as

four-byte quantities.

The readDouble and

writeDouble methods

process double-

precision floating-point

numbers as eight-byte

quantities.

To read:

int n = f.readInt();

double x =

f.readDouble();

char c = f.readChar();

To write:

f.writeInt(n);

f.writeDouble(x);

f.writeChar(c);

Example: See

Database.java

- Name: 30 characters

at two bytes each (60

bytes)

- Price: one double (8

bytes)

- Score: one int (4

bytes)

import

java.io.IOException;

import java.io.

RandomAccessFile;

public class Database

{ public static void

main(String[] args)

{ ConsoleReader

console = new

ConsoleReader

(System.in);

System.out.println

("Please enter the data

file name:");

String filename =

console.readLine();

try

{ RandomAccessFile

file

= new

RandomAccessFile

(filename, "rw");

long nrecord =

file.length() / RECORD_

SIZE;

boolean done = false;

while (!done)

{ System.out.println

("Please enter the

record to update (1 - "

+ nrecord + "), new

record (0), quit (-1)");

int pos =

console.readInt();

if (1 <= pos && pos <=

nrecord) // update

record

{ file.seek((pos - 1) *

RECORD_SIZE);

Product p =

readProduct(file);

System.out.println

("Found " + p.getName

()

+ " " + p.getPrice() + " "

+ p.getScore());

System.out.println

("Enter the new

price:");

double newPrice =

console.readDouble();

p.setPrice(newPrice);

file.seek((pos - 1) *

RECORD_SIZE);

writeProduct(file, p);

}

else if (pos == 0) // add

record

{ System.out.println

("Enter new product:");

String name =

console.readLine();

System.out.println

("Enter price:");

double price =

console.readDouble();

System.out.println

("Enter score:");

int score =

console.readInt();

Product p = new

Product(name, price,

score);

file.seek(nrecord *

RECORD_SIZE);

writeProduct(file, p);

nrecord++;

}

else if (pos == -1)

done = true;

}

file.close();

}

catch(IOException e)

{ System.out.println

("Input/Output

Exception " + e); }

}

public static String

readFixedString

(RandomAccessFile f,

int size) throws

IOException

{ String b = "";

for (int i = 0; i < size; i+

+)

b += f.readChar();

return b.trim();

}

public static void

writeFixedString

(RandomAccessFile f,

String s, int size)

throws IOException

{ if (s.length() <= size)

{ f.writeChars(s);

for (int i = s.length(); i <

size; i++)

f.writeChar(' ');

}

else

f.writeChars

(s.substring(0, size));

}

public static Product

readProduct

(RandomAccessFile f)

throws IOException

{ String name =

readFixedString(f,

NAME_SIZE);

double price =

f.readDouble();

int score = f.readInt();

return new Product

(name, price, score);

}

public static void

writeProduct

(RandomAccessFile f,

Product p) throws

IOException

{ writeFixedString(f,

p.getName(), NAME_

SIZE);

f.writeDouble

(p.getPrice());

f.writeInt(p.getScore()

);

}

public static final int

NAME_SIZE = 30;

public static final int

CHAR_SIZE = 2;

public static final int

INT_SIZE = 4;

public static final int

DOUBLE_SIZE = 8;

public static final int

RECORD_SIZE

= CHAR_SIZE * NAME_

SIZE + DOUBLE_SIZE +

INT_SIZE;

}

Object Streams

We can read and write

complete objects with

the ObjectInputStream

and

ObjectOutputStream

Objects are saved in

binary format; hence

we use streams, not

writers.

For example, we write

a Product object to a

file as follows:

Product p = … ;

ObjectOutputStream out

= new

ObjectOutputStream

(new FileOutputStream

(“products.dat”));

out.writeObject(p);

To read objects:

ObjectInputStream in =

new ObjectInputStream

(new FileInputStream

(“products.dat”));

Product p = (Product)

in.readObject( );

We can store a whole

bunch of objects in an

array or vector, or

inside another object,

and then save that

object:

Vector v = new Vector

();

// now add many

Product objects into v

out.writeObject(v);

We can read all of

objects:

Vector v = (Vector)

in.readObject( );

The objects must

belong to classes that

implement Serializable

interface:

class Product

implements

Serializable

{ … }

To save data to disk, it

is best to put them all

into one object and

save that object.

class Catalog

implements

Serializable

{ public void

addProduct(Product p)

{… }

private Vector

products;

}

class ProductEditor

{ public void saveFile()

{ ObjectOutputStream

out = …;

out.writeObject

(productCatalog);

out.close();

}

public void loadFile()

{ ObjectInputStream in

= … ;

productCatalog =

(Catalog)in.readObject

();

in.close();

}

private Catalog

productCatalog;

}

lesson 8

8. Inheritance and

Interfaces

To learn about

inheritances

To be able to convert

between supertype

and subtype

references

To understand how to

override superclass

methods

To understand the

concept of

polymorphism

To design and use

abstract classes and

interfaces

To learn about

packages and Java

access control

Introduction to

Inheritance

Inheritance is a

mechanism for

enhancing existing,

working class.

For example, suppose

we need to define a

class SavingsAccount

to model an account

that pays a fixed

interest rate on

deposits.

class SavingsAccount

extends BankAccount

{ new instance variables

new methods

}

class SubclassName

extends SuperclassName

{ new instance variables

new methods

}

Inheritance

The more general

class that forms the

basis for inheritance is

called the superclass.

The more specialized

class that inherits from

the superclass is

called the subclass.

One important reason

for inhertance is code

reuse.

Inheritance Diagram

Object <---
BankAccount <----
SavingsAccount
Inheritance Diagram
Which class is a
superclass and which
class is a subclass?
BankAccount is the
superclass and
SavingsAccount is the
subclass.
Suppose we want to
set an interest rate in
the constructor for
SavingsAccount class
and also a method to
apply that interest rate
periodically.
public class
SavingsAccount extends
BankAccount
{ private double
interestRate;
public SavingsAccont
(double rate)
{ constructor
implementation }
public void addInterest
( )
{ method
implementation }
}
public class
BankAccount
{ private double
balance;
public BankAccount( )
{ balance = 0; }
public BankAccount
(double init )
{ balance = init; }
public void deposit
(double amount)
{ balance = balance +
amount; }
public void withdraw
(double amount)
{ balance = balance -
amount; }
public double
getBalance( )
{ return balance; }
}
public class
SavingsAccount
extends BankAccount
{ private double
interestRate; //
instance variable
public SavingsAccont
(double rate) //
constructor
{ interestRate = rate; }
public void addInterest
( ) // instance method
{ double interest =
getBalance() *
interestRate / 100;
deposit(interest);
}
}
// Example Code
SavingsAccount
collegeFund = new
SavingsAccount(10);
collegeFund.deposit
(500); // OK to use
superclass’s method
collegeFund.
addInterest( );
Converting Between
Class Types
A SavingsAccount
object is a special
case of a BankAccount
object. So, you can
store a reference to a
SavingsAccount object
into a BankAccount
object.
SavingsAccount
collegeFund = new
SavingsAccount(10);
BankAccount anAccount =
collegeFund;
Object anObject =
collegeFund;
The three object
references stored in
collegeFund,
anAccount, and
anObject refer to the
same object of type
SavingsAccount.
However, the
anAccount knows less
than the full story
about the object to
which it refers
anAccount.deposit(1000)
; // OK
anAccount.addInterest( )
; // Not OK
Because anAccount is
an object of type
BankAccount, we
cannot use the
addInterest method.
anObject.deposit(1000); //
Not OK
The variable anObject
knows even less,
because it is an object
of type Object and
deposit is not a
method of the object
class.
Why would anyone
want to know less
about an object and
store a reference in an
object variable of a
superclass? Reuse.
Consider the transfer
method
void transfer(BankAccount
other, double amount)
{ withdraw(amount);
other.deposit(amount);
}
We can use this
method to transfer
money from one bank
account to another:
BankAccount
momsChecking = … ;
BankAccount
harrysChecking = … ;
momsChecking.transfer
(harrysChecking, 1000);
We can also use this
method to transfer
money into a
SavingAccount:
SavingsAccount
CollegeFund = … ;
momsChecking.
transfer(collegeFund,
1000);
However, we cannot
convert between
unrelated classes:
Rectangle r =
CollegeFund; // Error
Subclass reference can
be assigned to
superclass reference
Object anObject =
collegeFund;
But, superclass
reference must be
casted to subclass
reference.
SavingsAccount x =
(SavingsAcount)anObject;
as long as we
absolutely sure that
anObject really refers
to a SavingsAccount
object.
To play it safe, we can
use the instanceof
operator to test
whether an object
belongs to a particular
class (or one of its
subclasses).
Object instanceof
ClasssName
Rectangle r;
if (x instanceof
Rectangle)
r = (Rectangle) x;
SavingsAccount x;
if (anObject instanceof
SavingsAccount)
x = (SavingsAccount)
anObject;
else
x = null;
Hierarchies
Hierarchies are
frequently represented
as trees, with the
most general concepts
at the root.
In Java, it is common
to group classes in
inheritance
hierarchies.
Inheritance
Hierarchies
The classes
representing the most
general concepts are
near the root, more
specialized classes
towards the branches.
When designing a
hierarchy of classes,
those common
properties are
collected in a
superclass. More
specialized properties
can be found in
subclasses.
Consider a bank that
offers its customers
three kinds of
accounts:
CheckingAccount
SavingsAccount
TimeDepositAccount
The checking account
has no interest, gives
you a small number of
free transactions per
month, and charges a
transaction fee for
each additional
transactions.
The savings account
compounds interest
monthly.
The time deposit
account has a penalty
for early withdrawal.
The inheritance
hierarchy for these
account classes is:
protected Members
A superclass’s public
members are
accessible anywhere
the program has a
reference to that
superclass type or one
of its subclasses
types.
A superclass’s private
members are
accessible only in
methods of that
superclasses.
A superclass’s
protected members
serve as an
intermediate level of
protection between
public and private
access.
protected Members
A superclass’s
protected members
can be accessed by
methods of the
superclass, by
methods of subclasses
and by methods of
other classes in the
same package
(protected members
have package access).
Subclass methods can
normally refer to public
and protected
members of the
superclass simply by
using the member
names.
Inheritance
// Definition of a class
Point
public class Point {
protected int x, y;
public Point()
{ setPoint(0,0); }
public Point(int a, int b)
{ setPoint(a, b); }
public void setPoint(int
a, int b)
{ x = a;
y = b;
}
public int getX()
{ return x; }
public int getY()
{ return y; }
public String toString()
{ return “[“ + x + “, “ + y
+ “]”; } }
// Definition of class
circle
public class Circle
extends Point {
protected double
radius;
public Circle()
{ // implicit call to
superclass constructor
setRadius(0); }
public Circle(double r,
int a, int b)
{ super(a, b);
setRadius(r);
}
public void setRadius
(double r)
{ radius = (r >= 0.0 ? r :

0.0); }

pubic double getRadius

()

{ return radius; }

public double area()

{ return Math.PI *

radius * radius; }

public String toString()

{ return “Center = “ +

“[“ + x + “,” + y + “]” +

“; Radius = “ + radius;

}

}

// Main program

import java.text.

DecimalFormat;

import javax.swing.

JOptionPane;

public class

InheritanceTest {

public static void main

(String[] args)

{ Point pointRef, p;

Circle circleRef, c;

String output;

p = new Point(30,50);

c = new Circle(2.7, 120,

89);

output = “Point p: “+

p.toString() +

“\nCircle c: “ +

c.toString() ;

pointRef = c;

output += “\n\nCircle c

(via pointRef): “ +

pointRef.toString() ;

circleRef = (Circle)

pointRef;

output += “\n\nCircle c

(via circleRef): “ +

circleRef.toString() ;

DecimalFormat

precision2 = new

DecimalFormat(“0.00”)

;

output += “\n\nArea of

c (via circleRef): “ +

precision2.format

(circleRef.area());

if (p instanceof Circle)

{

circleRef = (Circle) p;

output += “\n\ncast

successful”;

}

else

output += “\n\n p does

not refer to a circle”;

JOptionPane.

showMessageDialog

(null, output,

“Inheritance”,

JOptionPane.

INFORMATION_

MESSAGE);

System.exit(0);

}

}

Inheriting Instance

Variables and Methods

When defining

additional methods for

a subclass, there are 3

options:

1. We can override

methods from the

superclass by

specifying a method

with the same

signature (i.e., the

same name and the

same parameters).

2. We can inherit

methods from the

superclass. If we do

not explicitly override

a superclass method,

we automatically

inherit it.

3. We can define new

methods that does not

exist in the superclass.

When defining

additional instance

variables for a

subclass, there are 2

options:

1. We can inherit

variables from the

superclass.

2. We can define new

variables. These new

variables are only

presented in subclass

objects.

Remember! We can

never override

instance variables.

Shadowing

The newly defined

subclass variable

shadows the

superclass variable.

The superclass

variable is still

present, but it cannot

be accessed.

When you refer to

balance in a

SavingAccount

method, you access

the new instance

variable.

Shadowing instance

variables is harmless.

Shadowing Instance

Variables

A subclass has no

access to the private

instance of the

superclass

public class

CheckingAccount

extends BankAccount

{ public void deposit

(double amount)

{ transactionCount++;

balance = balance +

amount; // ERROR

}

}

To solve the problem

public class

CheckingAccount

extends BankAccount

{ private double

balance; // shadow

variable

public void deposit

(double amount)

{ transactionCount++;

balance = balance +

amount; // OK but

different balance

}

}

Example

public class

BankAccount

{ private double

balance;

public double

getBalance() {…}

public void deposit

(double amount) {…}

public void withdraw

(double amount) {…}

}

public class

CheckingAccount

extends BankAccount

{ private int

transactionCount;

public void deposit

(double amount) {…}

public void withdraw

(double amount) {…}

public void deductFees

() {…}

}

Subclass methods

have no access rights

to the private data of

the superclass.

If we want to modify a

private superclass

variable, we must use

a public method of the

superclass.

Can we write the

deposit method as

public void deposit

(double amount)

{ transactionCount++;

deposit(amount); // Is

it OK?

}

If we define the

method like that, it will

call itself infinitely.

We need to be more

specific that we want

to invoke the

superclass’s deposit

method by using a

special keyword super

for this purpose:

public void deposit

(double amount)

{ transactionCount++;

super.deposit(amount);

}

Calling a Superclass

Methods

public class

CheckingAccount

extends BankAccount

{ private static final int

FREE_TRANSANCTIONS

= 3;

private static final

double TRANSACTION_

FEE = 2.0;

public void withdraw

(double amount) //

override method

{ transactionCount++;

super.withdraw

(amount); // calling a

superclass method.

// what if we call

withdraw(amount);

}

public void deductFees

( )

{ if (transactionCount >

FREE_TRANSACTIONS)

{ double fees =

TRANSACTION_FEE

* (transactionCount -

FREE_TRANSACTIONS);

super.withdraw(fees);

}

}

Now, let consider the

TimeDepositAccount

class, a subclass of the

SavingsAccount:

public class

TimeDepositAccount

extends

SavingsAccount

{ private int

periodsToMaturity;

private static final

double EARLY_

PENALTY= 20.0;

public void addInterest

( )

{ periodsToMaturity- - ;

super.addInterest( );

}

public void withdraw

(double amount)

{ if (periodsToMaturity

> 0)

super.withdraw(EARLY_

PENALTY);

super.withdraw

(amount);

}

}

The

TimeDepositAccount

is two levels away

from the BankAccount.

The BankAccount is a

superclass, but not the

immediate superclass.

The

TimeDepositAccount

inherits two methods

from the BankAccount

class, namely

getBalance, and

deposit.

Methods can be

inherited from an

indirect superclass as

long as none of the

intermediate

superclasses

overrides them.

The method call

super.addInterest in

addInterest method of

the

TimeDepositAccount

refers to the

addInterest method in

SavingsAccount class.

The super.withdraw in

the withdraw method

of the

TimeDepositAccount

refers to the withdraw

method in

BankAccount.

Subclass Construction

Calling a Superclass

Constructor

ClassName

(parameters)

{ super(parameters);



}

Call the superclass

constructor to set the

balance to the initial

balance

public class

CheckingAccount

extends BankAccount

{ public

CheckingAccount

(double init)

{ super(init);

transactionCount = 0;

}

}

The constructor call

must be the first

statement of the

subclass constructor.

Subclass Constructor

When the keyword

super is followed by a

parenthesis, it

indicates a call to the

superclass

constructor.

If super is followed by

a period and a method

name, it indicates a

call to a superclass

method.

Or, we can implement

the CheckingAccount

constructor without

calling the superclass

constructor as can be

seen in the following

example:

public class

CheckingAccount

extends BankAccount

{ public

CheckingAccount

(double init)

{ // use superclass’s

default constructor

super.deposit(init);

transactionCount = 0;

}

}

public class

TimeDepositAccount

extends

SavingsAccount

{ public

TimeDepositAccount

(double rate, int

maturity )

{ super(rate);

periodsToMaturity =

maturity ;

}

}

Subclass Construction

If a subclass

constructor does not

call the superclass

constructor, the

superclass is

constructed with its

default constructor.

If a superclass does

not have a default

constructor, then the

complier reports an

error.

For example,

CheckingAccount can

be implemented

without calling the

superclass

constructor.

The BankAccount class

is constructed with its

default constructor,

which set the balance

to zero.

Then the

CheckingAccount

constructor must

explicitly deposit the

initial balance.

public

CheckingAccount

(double init)

{ // use superclass’s

default constructor

super.deposit(init);

transactionCount = 0;

However, in the case

of

TimeDepositAccount,

the superclass,

SavingsAccount, has

no default constructor.

Thus, we must call the

superclass constructor

explicitly.

public

TimeDepositAccount

(double rate, int

maturity )

{ super(rate);

periodsToMaturity =

maturity ;

}

Polymorphism

“is-a” relationship:

Every object of the

subclass is also a

superclass object, but

with special

properties.

For example, every

CheckingAccount is a

BankAccount.

It is possible to use a

subclass object in

place of a superclass

object.

What is polymorphism?

Let’s consider the

transfer method that

can be used to transfer

money from another

account:

public void transfer

(BankAccount other,

double amount)

{ withdraw(amount);

other.deposit(amount);

}

BankAccount

collegeFund = … ;

CheckingAccount

harrysChecking = … ;

collegeFund.transfer

(harrysChecking, 1000)

;

Which deposit

method?

BankAccount.deposit( )

or CheckingAccount.

deposit( )

Consider the call to the

deposit method, the

other parameter has

type BankAccount.

On the other hand, the

CheckingAccount class

provides its own

deposit method that

updates the

transaction count.

Since the other

variable actually refers

to an object of the

subclass

CheckingAccount, it

would be appropriate if

the CheckingAccount.

deposit method was

called instead.

The principle that the

actual type of the

object determines the

method to be called is

called polymorphism.

In Java, method calls

are always determined

by the type of the

actual object, not the

type of the object

reference.

In Java, all instance

methods are

polymophic.

The term

“polymorphism”

comes from the Greek

words for “many

shapes”.

Program

AccountTest.java

public class AccountTest

{ public static void main

(String[] args)

{ SavingsAccount

momsSavings = new

SavingsAccount(0.5);

TimeDepositAccount

collegeFund =

new TimeDepositAccount

(1, 3);

CheckingAccount

harrysChekcing = new

CheckingAccount(0);

momsSavings.deposit

(10000);

collegeFund.deposit

(10000);

momsSavings.transfer

(harryschecking, 2000);

collegeFund.transfer

(harryschecking, 980);

harrysChecking.withdraw

(500);

harrysChecking.withdraw

(80);

harrysChecking.withdraw

(400);

endOfMonth

(momsSavings);

endOfMonth

(collegeFund);

endOfMonth

(harrysChecking);

printBalance(“mom’s

savings”,

momsSavings);

printBalance(“the

college Fund”,

collegeFund);

printBalance(“Harry’s

checking”,

harrysChecking);

}

public static void

endOfMonth

(SavingsAccount savings)

{ savings.addInterest

( ); }

public static void

endOfMonth

(CheckingAccount

checking)

{ checking.deductFees

( ); }

public static void

printBalance(String

name, BankAccount

account)

{ System.out.println

(“The balance of “ +

name + “ account is $”

+

account.getBalance( ) )

;

}

}

Polymorphism vs.

Overload

Let’s take a look at a

polymorphic method

call such as

other.deposit(amount),

there are several

deposit methods that

can be called.

Both polymorphic

deposit and withdraw

methods are called.

What happens when

the method name is

overloaded;i.e., when

a single class has

several methods with

the same name but

different parameter

types?

For example, we can

have two constructors

BankAccount() and

BankAccount(double).

The compiler selects

the appropriate

method when

compiling a program.

Another example of

overloading, the static

endOfMonth methods

in the AccountTest

class. The compiler

uses the type of the

explicit parameter to

pick the appropriate

method.

The main difference

between

polymorphism and

overloading is the

binding method.

Polymorphism uses a

selection method

called late binding, i.e.,

the compiler doesn’t

make any decision

when translating the

method, it is the virtual

machine that selects

the appropriate

method.

Overloading uses early

binding technique

which compiler picks

an overloaded method

when translating the

program.

Interfaces

Many object-oriented

programming

languages have

multiple inheritance,

i.e.,more than one

superclass.

In Java, a class cannot

have two direct

superclasses.

To support this

feature, we use

interfaces instead of

superclasses.

The purpose of

interfaces is to support

the concept of writing

a single method for

any data type.

Interfaces

An interface is similar

to a class, but

An interface does not

have instance

variables

All methods in an

interface are abstract;

they have a name,

parameters, and a

return type, but they

don’t have an

implementation.

All methods in an

interface are

automatically public.

The interface

declaration lists all

methods that the

interface requires.

For example, the

java.lang package

defines a Comparable

interface as:

public interface

Comparable

{ int compareTo(Object

other);

// no implementation

}

We don’t extend

interfaces; we

implement them, using

the special

implements keyword:

public class

SavingAccount extends

BankAccount

implements

Comparable

{ …

}

Any class that

implements the

Comparable interface

must supply the

compareTo method

public class

SavingsAccount

extends BankAccount

implements

Comparable

{ …

public int compareTo

(Object other)

{ // supply

implementation …

SavingsAccount

otherAcc =

(SavingsAccount)

other;

if (interestRate <
otherAcc.interestRate)
return -1;
if (interestRate >

otherAcc.interestRate)

return 1;

return 0;

} ...

}

Note that the class

must declare the

method as public,

whereas the interface

does not -- all methods

in an interface are

public.

Once a class

implements an

interface, you can

convert a class

reference to an

interface reference:

SavingsAccount

harrysSavings = new

SavingAccount();

Comparable first =

harrysSavings;

However, we can

never construct an

interface:

Comparable second; // OK

second = new

Comparable( ); // ERROR

All interface

references refer to

objects of other

classes-- classes that

implement the

interface.

first.compareTo(second);

A class can have only

one superclass, but it

can implement any

number of interfaces

public class

SavingsAccount

extends BankAccount

implements

Comparable, Cloneable

Constants in

Interfaces

public interface

SwingConstants

{ int NORTH = 1;

int NORTH_EAST = 2;

int EAST = 3;



}

// SwingConstants.

NORTH;

all variables in an

interface are

automatically public

static final

Abstract Classes

Abstract Classes : A

class which we cannot

create objects

public abstract class

BankAccount

{ publicabstract void

deductFees( );



}

The reason for using

abstract classes is to

force programmers to

create subclasses.

BankAccount

anAccount; // OK

anAccount = new

BankAccount(); // Error

anAccount = new

SavingsAccount(); //

OK

anAccount = null; // OK

Note that we can still

have an object

reference whose type

is an abstract class.

Abstarct classes differ

from interfaces -- they

can have instance

variables and concrete

methods.

Final Methods and

Classes: To prevent

others from creating

subclasses or from

overriding certain

methods

public final class String

{ …. }

public class MyApplet

extends Applet

{ publicfinal boolean

checkPasswd(String

passwd)

{ … }

}

Access Control

Java has four levels of

controlling access to

variables, methods,

and classes:

public access

private access

protected access

Package access (the

default, when no

access modifier is

given)

Proteced data can be

accessed by the

methods of a class and

all its subclasses.

public class

BankAccount

{ protected double

balance; }

If a superclass

declares a method to

be publicly accesible,

we cannot override it

to be more private.

public class BankAccount

{ public void withdraw

(double amount) { … } }

public class

TimeDepositAccount

extends BankAccount

{ private void withdraw

(double amount) { … } //

ERROR

}

Overriding Object

Superclass Methods

The methods of the

Object class are very

general:

- String toString( ) //

Returns a string

representation of the

object

- boolean equals

(Object other) // Test

whether the object

equals

// another object

- Object clone( ) //

Makes a full copy of an

object

Overriding the toString

Method

The toString method

returns a string

representation for

each object.

Rectangle x = new

Rectangle(5, 10, 20, 30);

String s = x.toString( ); //

set s to

“java.awt.Rectangle[x=5,

// y=10,

width=20,height=30]”

The toString method is

called whenever we

concatenate a string

with an object.

System.out.println(“x

means ” + x); // will print

“x means

// java.awt.Rectangle

[x=5,y=10,width=20,height

=30]”

Let’s try the toString

method for the

BankAccount class:

BankAccount x = new

BankAccount(5000);

String s = x.toString( ); //

sets s to “BankAccount@

d246bf”

// print the name of the

class and the memory

address of the object

To work better,

overriding toString

method:

public class BankAccount

{ public String toString()

{ return “BankAccount

[balance=” + balance + “]

”; }

}

BankAccount x = new

BankAccount(5000);

String s = x.toString( );

// sets s to

“BankAccount

[balance=5000]”

Overriding the equals

Method

The equals method is

called whenever we

want to compare two

objects:

if (account1.equals

(account2)) …

// contents are the same

Compare to:

if (account1 = = account2)



// test two references are

the same object

public class

BankAccount

{ public boolean equals

(Object otherObj)

{ if (otherObj

instanceof

BankAccount)

{ BankAccount other =

(BankAccount)

otherObj;

return balance = =

other.balance;

}

else

return false;

}

}

Overriding the clone

method

To make a copy of an

object:

public class BankAccount

{ public Object clone( )

{ BankAccount clonedAcc

= new BankAccount

(balance);

return clonedAcc;

}

}

When we call the

method:

BankAccount acc1 = new

BankAccount(1000);

BankAccount acc2 =

(BankAccount)acc1.clone();

Compared to:

BankAccount acc1 =

new BankAccount

(1000);

BankAccount acc2 =

acc1;

Clone Mutable

Instance Variables

Consider the following

class:

public class Customer

{ private String name;

private BankAccount

account;

public Customer(String

aName)

{ name = aName;

account = new

BankAccount();

}

public String getName()

{ return name; }

public BankAccount

getAccount()

{ return account; }

getAccount method

breaks encapsulation

because anyone can

modify the object

state without going

through the public

interface:

Customer harry = new

Customer(“Harry

Handsome”);

BankAccount account =

harry.getAccount();

// anyone can

withdraw money!

account.withdraw

(100000);

So, we should clone

the object reference:

public BankAccount

getAccount()

{ return (BankAccount)

account.clone(); }

The rule of thumb is

that a class should

clone all references to

mutable objects that it

gives out.

The converse is true

as well-- a class

should clone

references that it

receives:

public Customer(String

aName, BankAccount

anAccount)

{ name = aName;

account = (BankAccount)

anAccount.clone();

}

Using Object.clone()

If we have an object

with many instance

variables, it can be

tedious to copy them

all into a new object.

The Object.clone()

simply creates a new

object whose instance

variables are copies of

the original.

public class

BankAccount

{ public Object clone()

{ // not complete

Object clonedAccount

= super.clone();

return clonedAccount;

}

}

Object.clone() checks

that the object being

cloned implements the

Cloneable interface

and do exception

handling.

public class BankAccount

implements Cloneable

{ public Object clone()

{try

{ // clones all instance

variables

Object clonedAccount =

super.clone();

return clonedAccount;

}

catch (

CloneNotSupportedEx

ception e)

{ return null; }

}

}

If an object contains a

reference to another

mutable object, then

we need to call clone

for that reference, in

order to prevent

shallow copy problem

(see Figure 11).

public class Customer

implements Cloneable

{ private String name;

private BankAcount

account;

public Object clone()

{ try

{ Object

clonedCustomer =

(Customer)super.clone

();

clonedCustomer.

account =

(BankAccount)

account.clone();

return

clonedCustomer;

}

catch (

CloneNotSupportedEx

ception e)

{ return null; }

}

}

Packages

A Java package is a

set of related classes.

Table1: Important

Packages in the Java

Library

java.lang Langauge

supoort Math

java.util Utilites

Random

java.io Input/Output

PrintStream

java.awt Abstract

Windowing Color

Toolkit

java.applet Applets

Applet

java.net Networking

Socket

java.sql Database

access ResultSet

javax.swing Swing UI

JButton

To put classes in a

package:

package

packagename;

package

com.horstmann.ccj;

import

java.io.InputStream;

import java.io.

InputStreamReader;

public class

ConsoleReader { … }

….

Importing Packages

import

com.horstmann.ccj.

ConsoleReader;

lesson 7-Arrays & Vectors

7. Arrays and Vectors

To be able to use

arrays and vectors to

collect objects

To implement partially

filled arrays

To be able to pass

arrays to methods

To learn about

common array

algorithms

To build classes

containing arrays and

vectors

To learn how to use

two-dimensional

arrays

Arrays

An array is a collection

of data items of the

same type.

Every element of the

collection can be

accessed separately

by using index.

In Java, array indexing

starts from 0.

Array can be

constructed using

double[ ] data = new

double[10];

An Array Reference

and an Array

Using Arrays to Store

Data

To access the fifth

element in an array,

we use

data[4] = 35.5;

System.out.println

(“The price = ” + data

[4]);

sum = sum + data[4];

double[ ] data; // error :

not initialized

data[0] = 10.5; // assign

a value to data[0]

Bounds Error

double[ ] data = new

double[10];

// we can access data

[0], data[1], … data[9]

data[10] = 35.5; //

cause

ArrayIndexOutOfBound

sException

Size of the array:

arrayRefName.length

double[ ] data = new

double[10];

for (int i = 0; i <
data.length; i++)
if (data[i] < lowest)
lowest = data[i];
Don’t combine array
access and index
increment
x = v[i++]; => x = v[i]; i+

+;

Array Initialization

int[] primes = new int

[5];

primes[0] = 2; primes

[1] = 3; primes[2] = 5;

primes[3] = 7; primes

[4] = 11;

// better to use the

following

int[ ] primes = {2, 3, 5,

7, 11};

Copying Arrays

Reference

double[] data = new

double[10];

// … fill array

double[] prices;

prices = data; // copy

reference of array

Make a true copy of

array

double[] prices = new

double[data.length];

for (int j = 0; j <
data.length; j++)
prices[j] = data[j];
Better if we use the
static
System.arrayCopy
method
System.arrayCopy
(from, fromStart, to,
toStart, count);
System.arrayCopy
(data, 0, prices, 0,
data.length);
Partially Filled Arrays
When we need to set
the size of an array
before you know how
many elements there
are, we can make an
array that is large
enough and partially fill
it.
final int DATA_LENGTH =
1000;
double[] data = new
double[DATA_LENGTH];
then keep a variable
that tells how many
elements are actually
used
int dataSize = 0; // for
collect size of array
and increment this
variable every time
data is added to the
array
double price =
console.readDouble();
data[dataSize] = price;
dataSize++;
Remember! Not to
access the data over
the datasize
for (int j=0; j <
dataSize; j++) // not
data.length
System.out.println(data
[j]);
and not to overfill the
array
if (dataSize <
data.length) // OK
{ data[dataSize] =
price;
dataSize++;
}
else // Array is full
{ System.out.println
(“Sorry, array is full”);
}
If the array fills up, we
can create a new,
larger array; copy all
elements into the new
array; and then attach
the new array to the
old array variable.
if (dataSize >= data.length)

{ //

double[] newData = new

double[2 * data.length];

// copy data

System.arrayCopy(data,

0, newData, 0,

data.length);

//create new reference for

"new data" ่

data = newData;

}

Suppose we want to

write a program that

reads a set of prices

offered by 10 vendors

for a particular product

and then prints them,

marking the lowest

one.

public class BestPrice

{ public static void

main(String[] args)

{ final int DATA_LENGTH =

1000;

double[] data = new

double[DATA_LENGTH];

int dataSize = 0;

// read data

ConsoleReader

console = new

ConsoleReader

(System.in);

boolean done = false;

while (!done)

{ System.out.println

("Enter price, 0 to

quit:");

double price =

console.readDouble();

if (price == 0) // end of

input

done = true;

else if (dataSize <
data.length)
{ // add price to data
array
data[dataSize] = price;
dataSize++;
}
else // array is full
{ System.out.println
("Sorry, the array is
full.");
done = true;
}
}
// compute lowest
price
if (dataSize == 0)
return; // no data
double lowest = data
[0];
for (int i = 1; i <
dataSize; i++)
if (data[i] < lowest)
lowest = data[i];
// print out prices,
marking the lowest
one
for (int i = 0; i <
dataSize; i++)
{ System.out.print(data
[i]);
if (data[i] == lowest)
System.out.print(" <--
lowest price");
System.out.println();
}
}
}
Array Parameters and
Return Values
The method to
compute the average
of an array of floating-
point numbers
public static double
average(double[] data)
{ if (data.length == 0)
return 0;
double sum = 0;
for (int j = 0; j <
data.length; j++)
sum = sum + data[j];
return sum /
data.length;
}
double[] prices =
{ 10.5, 24.5, 30.5, 10.0,
50.4 };
System.out.println
(“Price average = ” +
average(prices));
Array Parameters
When an array is
passed to a method,
the array parameter
contains a copy of the
reference to the
argument array.
A method can modify
the entries of any array
that you pass to it.
The method can return
an array if the returning
result consists of a
collection of values of
the same type.
A method can return an
array
public static int[]
randomData(int length,
int n)
{ Random generator =
new Random();
int[] data = new int
[length];
for (int j = 0; j <
data.length; j++)
data[j] =
generator.nextInt(n);
return data;
}
Array Algorithms
Finding a Value: want
to know the price of
first product that has
price lower or equal
1000
double [] prices;
double targetPrice = 1000;
int j = 0;
boolean found = false;
while (j < prices.length
&& !found)
{ if (prices[j] <=
targetPrice)
found = true;
else
j++;
}
if (found)
System.out.println(“Item”
+ j + “ has a price of” +
prices[j]);
Counting: want to
know the number of
product that has price
lower or equal 1000
double [] prices;
double targetPrice = 1000;
int count = 0;
for (int j = 0; j <
prices.length; j++)
{ if (prices[j] <=
targetPrice)
count++;
}
System.out.println(count
+ “ computers.”);
Removing an Element
from an Unordered
Array
If we want to remove
an element from an
unordered array, we
simply overwrite the
element to be
removed with the last
element of the array.
However, an array
cannot be shrunk to
get rid of the last
element, so we have
to used the technique
of a partially filled
array.
Removing an Element :
Array not sorted
public class Remove1
{ public static void
main(String[] args)
{ ConsoleReader
console = new
ConsoleReader
(System.in);
String[] staff = new
String[5];
staff[0] = "Harry"; staff
[1] = "Romeo"; staff[2]
= "Dick";
staff[3] = "Juliet"; staff
[4] = "Tom";
int staffSize =
staff.length;
print(staff, staffSize);
System.out.println
("Remove which
element? (0 - 4)");
int pos =
console.readInt();
// overwrite the
removed element with
the last element
staff[pos] = staff
[staffSize - 1];
staffSize--;
print(staff, staffSize);
}
/**
Prints an array of
strings
@param s the string
array
@param sSize the
number of strings in
the array
*/
public static void print
(String[] s, int sSize)
{ for (int i = 0; i < sSize;
i++)
System.out.println(i + ":
" + s[i]);
}
}
Remove an Element
from an Ordered Array
After removing an
element, we have to
move all elements
beyond the element to
be removed by one
slot.
Removing from an
Ordered Array
public class Remove2
{ public static void
main(String[] args)
{ ...
int staffSize =
staff.length;
print(staff, staffSize);
System.out.println
("Remove which
element? (0 - 4)");
int pos =
console.readInt();
// shift all elements
above pos down
for (int i = pos; i <
staffSize - 1; i++)
staff[i] = staff[i + 1];
staffSize--;
print(staff, staffSize);
}
}
Inserting an Element
Suppose we want to
insert an element in
the middle of an array,
we must move all
elements beyond the
insertion location by
one slot.
When we insert an
element, we start
moving at the end of
an array, move that
element, then go to
the one before it. This
operation is in reverse
order from removing
operation.
public class Insert
{ public static void
main(String[] args)
{ String[] staff = new
String[6];
staff[0] = “Mary”;
staff[1] = “Ben”;
staff[2] = “Sandy”;
staff[3] = “Janet”;
staff[4] = “Peter”;
int staffSize =
staff.length - 1;
System.out.print
("Insert before which
element? (0 - 4) ");
int pos =
console.readInt();
// shift all element
after pos up by one
for (int i = staffSize; i >

pos; i--)

staff[i] = staff[i - 1];

// insert new element

into freed slot

staff[pos] = "New,

Nina";

staffSize++;

print(staff, staffSize);

}

Parallel Arrays, Arrays

of Objects

and Array as Object

Data

When we want to

analyze a data set that

contains more than

one data item, such as

a data set that contains

the names, prices, and

quality of a collection

of products.

We want to look for

products that give

good quality at low

price.

The problem with this

program is that it

contains three arrays

of the same length.

Bestdata.java

public class BestData

{ public static void

main(String[] args)

{ final int DATA_MAX =

500;

String[] name = new

String[DATA_MAX];

double[] price = new

double[DATA_MAX];

int[] score = new int

[DATA_MAX];

int Size = 0;

// read data from

console

ConsoleReader

console = new

ConsoleReader

(System.in);

Boolean done = false;

while (!done)

{ System.out.println

(“Enter name or leave

blank when done: ”);

String inLine =

console.readLine();

if (inLine == null ||

inLine.equals(“ ”))

done = true;

else if (Size < DATA_
MAX)
{ name[Size] = inLine;
System.out.println
(“Enter price: “);
inLine =
console.readLine();
price[Size] =
Double.parseDouble
(inLine);
System.out.println
(“Enter score: “);
inLine =
console.readLine();
score[Size] =
Integer.parseInt
(inLine);
Size++;
}
else
{ System.out.println
(“Sorry, the array is
full. “);
done = true;
}
}
// compute best buy
if (Size == 0) return; //
no data
double best = score[0]
/ price[0];
for (int j = 0; j < Size; j+
+)
if (score[j] / price[j] >

best)

best = score[j] / price

[j];

final int COLUMN_WIDTH

= 30;

for (int j = 0; j < Size; j+
+)
{ System.out.print
(name[j]);
int pad = COLUMN_
WIDTH - name[j].length();
for (int k = 1; k < = pad; k+
+)
System.out.print(“ “);
System.out.print(“ $” +
price[j] +“ score = “ +
score[j]);
if (score[j] / price[j] ==
best)
System.out.print(“ <--
best buy “);
System.out.println();
}
}
}
Parallel Arrays
The problem with
Bestdata.java is that it
contains three parallel
arrays namely name[j],
price[j], and score[].
We must ensure that
the arrays always have
the same length and
that each slice is filled
with values that
actually belong
together.
We can solve this
problem by turning this
concept into class.
Product.java
class Product
{
private String name;
private double price;
private int score;
public Product(String n,
double p, int s)
{ name = n;
price = p;
score = s;
}
public String getName
()
{ return name;
}
public double getPrice
()
{ return price;
}
public int getScore()
{ return score;
}
}
Bestproduct.java
public class
BestProduct
{ public static void
main(String[] args)
{ final int DATA_MAX =
500;
Product[] data = new
Product[DATA_MAX];
int Size = 0;
// read data from
console
ConsoleReader
console = new
ConsoleReader
(System.in);
Boolean done = false;
while (!done)
{ Product p =
readProduct(console);
if (p == null)
done = true;
else if (Size < DATA_
MAX)
{ data[Size] = p;
Size++;
}
else
{
System.out.println
(“Sorry, the array is
full.”);
done = true;
}
}
// compute best buy
if (Size == 0) return; //
no data
double best = data[0]
.getScore() / data[0]
.getPrice();
for (int j = 1; j < Size; j+
+)
{ double ratio = data[j]
.getScore() / data[j]
.getPrice();
if (ratio > best)

best = ratio;

}

// print out data

for (int j = 0; j < Size; j+

+)

{ printProduct(data[j]);

if (data[j].getScore() /

data[j].getPrice() ==

best)

System.out.print(“ <--

best buy “);

}

}

public static Product

readProduct

(ConsoleReader in)

{ System.out.println

(“Enter name or leave

blank when done:”);

String name =

in.readLine();

if (name == null ||

name.equals(“ “))

return null;

System.out.println

(“Enter price: “);

String inLine =

in.readLine();

double price =

Double.parseDouble

(inLine);

System.out.println

(“Enter score: “);

inLine = in.readLine();

int score =

Integer.parseInt

(inLine);

return new Product

(name, price, score);

}

public static void

printProduct(Product p)

{ final int WIDTH = 30;

System.out.print

(p.getName());

int pad = WIDTH –

p.getName().length;

for (int j = 1; j <= pad; j+

+)

System.out.print(“ “);

System.out.print(“ $” +

p.getPrice() + “ score =

“ +

p.getScore());

}

}

Example:

PolygonTest.java

Arrays as Object Data

import

java.applet.Applet;

import

java.awt.Graphics;

import

java.awt.Graphics2D;

import

java.awt.geom.Line2D;

import

java.awt.geom,Point2D

;

public class

PolygonTest extends

Applet

{ public void paint

(Graphics g)

{ Graphics2D g2 =

(Grahpics2D) g;

Polygon triangle = new

Polygon(3);

triangle.add(new

Point2D.Double(40, 40)

);

triangle.add(new

Point2D.Double(120,

160));

triangle.add( new

Point2D.Double(20,

120));

double x = 200;

double y = 200;

double r = 50;

Polygon pentagon =

new Polygon(5);

for (int j = 0; j < 5; j++)

pentagon.add(new

Point2D.Double(

x + r * Math.cos(2 *

Math.PI * j / 5),

y + r * Math.sin(2 *

Math.PI * j / 5)));

triangle.draw(g2);

pentagon.draw(g2);

}

}

// Polygon class

definition

class Polygon

{ public polygon(int n)

{ corners = new

Point2D.Double[n];

cornerCount = 0;

}

public void add

(Point2D.Double p)

{ if (cornerCount <

corners.length)

{ corners[cornerCount]

= p;

cornerCount++;

}

}

public void draw

(Graphics2D g2)

{ for (int j = 0; j <

cornerCount; j++)

{ Point2D.Double from

= corners[j];

Point2D.Double to =

corners[(j+1) %

corners.length];

g2.draw(new

Line2D.Double(from, to);

}

}

private Point2D.Double

[] corners;

private int

cornerCount;

}

Example

To generate a triangle,

we can use the

following segment of

code:

Polygon triangle = new

Polygon(3);

triangle.add(new

Point2D.Double(40,40))

;

triangle.add(new

Point2D.Double

(120,160));

triangle.add(new

Point2D.Double(20,120)

);

Another kind of

geometric shape is

called a regular

polygon which has all

sides of the same

length.

A regular n-gon with

center (x,y) and radius

r has n corners, c0, c1,

…, cn-1, where

ci = (x+r•cos(2p i/n), y

+r•sin(2p i/n))

A regular polygon can

be generated by:

Polygon pentagon =

new Polygon(5);

for (int j = 0; j < 5; j++)

pentagon.add(new

Point2D.Double(

x +r*Math.cos

(2*Math.PI*j/5),

y+r*Math.sin

(2*Math.PI*j/5)));

PolygonTest.java

import

java.applet.Applet;

import

java.awt.Graphics;

import

java.awt.Graphics2D;

import

java.awt.geom.Line2D;

import

java.awt.geom.Point2D

;

public class

PolygonTest extends

Applet

{ public void paint

(Graphics g)

{ Graphics2D g2 =

(Graphics2D) g;

Polygon triangle = new

Polygon(3);

triangle.add(new

Point2D.Double(40,40))

;

triangle.add(new

Point2D.Double

(120,160));

triangle.add(new

Point2D.Double(20,120)

);

double x = 200;

double y = 200;

double r = 50;

Polygon pentagon =

new Polygon(5);

for (int j = 0; j < 5; j++)

{ pentagon.add(new

Point2D.Double(

x+r*Math.cos

(2*Math.PI*j/5),

y+r*Math.sin

(2*Math.PI*j/5)));

}

triangle.draw(g2);

pentagon.draw(g2);

}

}

// define polygon class

class Polygon

{ public Polygon(int n)

{ corners = new

Point2D.Double[n];

cornersSize = 0;

}

public void add

(Point2D.Double p)

{ if (cornersSize <

corners.length)

{ corners[cornersSize]

= p;

cornersSize++;

}

}

public void draw

(Graphics2D g2)

{ for (int j = 0; j <

cornersSize; j++)

{ Point2D.Double from

= corners[j];

Point2D.Double to =

corners[(j+1) %

corners.length];

g2.draw(new

Line2D.Double(from,

to));

// Line2D.Double line =

new Line2D.Double

(from, to);

// g2.draw(line);

}

}

private Point2D.Double

[] corners;

private int cornersSize;

}

Vector

A Vector is a container

of objects that grows

automatically

A Vector can hold

objects of any types

Internally, the Vector

class keeps an Object

[] array.

There is no limit to the

number of elements

that we add.

We can add new

elements at the end of

the vector with the

add method.

However, vectors are

objects of a class and

not arrays so we

cannot use the []

operator to access

vector.

Instead, we use the

set method to write an

element, and the get

method to read an

element.

products.set(0, p);

Example

// Consider

BestProduct.java

Vector products = new

Vector();

boolean done = false;

while (!done)

{ Product p =

readProduct();

if (p == null) // last

product read

done = true;

else

products.add(p); // add

the object to the end

of the vector

}

Vector positions start

at 0.

The number of

elements stored in a

vector is obtained by

the size method.

int n = products.size();

To read an element

from a vector, we use

the get method:

products.get(i) is the

ith element in the

vector products.

However, because the

return type of the get

method is the class

Object, we must cast

the return value of the

get method to the

correct type.

Product p = (Product)

products.get(i);

An example of a loop

that traverses the

elements of a vector.

for (int j = 0; j <

products.size(); j++)

{ Product p = (Product)

products.get(j);

do something with p;

}

We can also insert an

object in the middle of

a vector by using v.add

(j,p) to add the object

p at position j, move

all elements by one

position, from position

j to the last element in

the vector, and

increase the size of

the vector by 1.

The call v.remove(j)

removes the element

at position j, moves all

elements after the

removed element

down by one position,

and reduce the size of

the vector of the

vector by 1.

Since numbers are not

objects in Java, we

cannot have vectors

of numbers.

To store sequence of

integers, floating-point

numbers, or boolean

values, we must use

wrapper classes.

The classes Integer,

Double, and Boolean

wrap numbers and

truth values inside

objects.

These wrapper

objects can be stored

inside vectors.

The Double class is a

number wrapper.

There is a constructor

that makes a Double

object out of a double

value:

Double d = new Double

(29.74);

Conversely, the

doubleVal method

retrieves the double

value that is stored

inside the Double

object.

double x =

d.doubleValue();

To add a number into a

vector, we first

construct a wrapper

object, then add the

object to the vector:

Vector data = new

Vector();

data.add(new Double

(29.95));

To retrieve the

number, we need to

cast the return value

of the get method to

Double, then call the

doubleValue method:

double x = ((Double)

data.get(0))

.doubleValue();

Converting Vectors to

Arrays

The advantage of

vectors is the dynamic

growth since we need

not know the final size

of the vector.

The disadvantage is

the cumbersome

access syntax.

We can convert a

vector to an array with

the copyInfo method:

// read values into a

vector

vector productVector =

new Vector();

boolean done = false;

while (!done)

{ Product p =

readProduct();

if (p == null)

done = true;

else

productVector.add(p);

}

// allocate an array of

the correct size

Product[] products =

new Product

[productVector.size()];

// copy the elements

from the vector to the

array

productVector.

copyInfo(products);

for (int j = 0; j <

products.length; j++)

do something with

products[j];

Two-Dimensional

Arrays

An arrangement

consisting of rows and

columns of values is

called a two-

dimensional array or

matrix.

To construct a 2D

array, we need to

specify how many ros

and columns we need,

for example

int[][] powers = new

int[10][8];

To access a particular

element in the matrix,

we specify two

subscripts in separate

brackets:

powers[3][4] =

Math.pow(2, 4);

Two-Dimensional

Arrays

In Java, 2D arrays are

stored as arrays of

arrays:

int[][] powers = new

int[10][8];

For example, power is

an array of 10 objects,

each of which is an int

[] array of length 8.

The number of rows is:

int nrows =

powers.length;

The number of

columns is:

int ncols = power[0]

.length;

// See example:

Table2.java

Table2.java

public class Table2

{ public static void

main(String[] agrs)

{ final int COL_WIDTH =

10;

int[][] powers = new

int[10][8];

for (int i = 0; i <

powers.length; i++)

for (int j = 0; j <

powers[i].length; j++)

powers[i][j] = (int)

Math.pow(i+1, j+1);

printTable(powers,

COL_WIDTH);

}

public static void

printTable(int[][] table,

int width)

{ for (int i = 0; i <

table.length; i++)

{ for (int j = 0; j < table

[i].length; j++)

{ System.out.print

(format(table[i][j],

width));

}

System.out.println();

}

}

public static String

format(int n, int width)

{ String nstr = “” + n;

while (nstr.length() <

width)

nstr = “ “ + nstr;

return nstr;

}

}

Twitter Delicious Facebook Digg Stumbleupon Favorites More

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Sweet Tomatoes Printable Coupons