Download PowerPoint

Document related concepts
no text concepts found
Transcript
Introduction to Computer Science
Unit 12
• Packages
• Polymorphism
• Interfaces
• Exceptions
• Streams – input/output
Packages
• Java classes are placed into directories (or folders)
on the computer
• The classes in each directory form a package
• This helps organize classes, and also gives another
way of controlling access among classes
• Example: java.applet is the package of classes in
subdirectory "applet" under the directory "java"
(whose location varies depending on the system)
12- 2
Sample Packages that come with the
Java API (continually evolving)
java.applet
Classes for implementing applets
java.awt
For graphics, windows, GUIs
java.awt.event For AWT event-handling model
java.awt.image Classes for image processing
java.awt.peer Interface defs, platform-indep. GUIs
java.io
Classes for input and output
java.lang
Basic language classes (String, Math)
java.net
Classes for networking
java.util
Useful auxiliary classes, like Date
12- 3
Direct Use of Java API Class
• To use, for example, the class Math in
the package java.lang, it is possible
to use the fully-qualified name:
x = java.lang.Math.sqrt(3);
12- 4
Importing Classes
• Of course, it's more convenient to do it
the way we've been doing it, using the
import statement; either
import package_name.class_name;
or
import package_name.*;
12- 5
Importing
import package_name.class_name;
allows class_name to be used without
giving the full package name
import package_name.*;
allows all classes in the package to be
used without qualifying their names
12- 6
Example of import
java.util.Date d = new java.util.Date( );
java.awt.Point p = new java.awt.Point(1, 2);
java.awt.Button b = new java.awt.Button( );
can be abbreviated as
import java.util.Date;
import java.awt.*;
…
Date d = new Date( );
Point p = new Point(1, 2);
Button b = new Button( );
12- 7
It's Always There
• Java always assumes that the
classes in java.lang (basic language
classes, such as String and Math) are
available
• It's as if you have the statement
import java.lang.*;
at the beginning of every program
12- 8
Packages You Define
• All of the .class files placed in one directory
belong to the same, unnamed package
• To cause a class to be placed in a particular
named package:
–Put the .class file in the appropriate directory
–Compile the class with the package statement, which
must be the first non-comment line in the Java
source file:
package package-name;
12- 9
Classes in Different Packages
• Classes in different packages
obviously have different fullyqualified names
• Classes in different packages also
have different rules regarding the
visibility of names
12- 10
Example:
Visibility of Instance Variables
• A public instance variable is visible to all other
classes
• A private instance variable is visible only to the
methods of its class
• If it is declared neither public nor private, then it has
"package visibility"; it is visible to methods defined
in other classes in the same package as its class
• Same rules apply to static variables and instance
and static methods
12- 11
Similarly for Classes
• A class declared public is visible to
all classes
• A class not declared public is visible
to the classes in its own package
• A class cannot be declared private
12- 12
private, public, protected
• Private variables and methods: no access by
clients or by subclasses
• Public variables and methods: accessed by
clients and by subclasses
• Default (no label): variables and methods
have package visibility, accessible only to
clients and subclasses in the same package
12- 13
Protected
• We might want to give subclasses access to
variables and methods without allowing
clients to have access
• That's the purpose of another category of
accessibility: protected
• Members declared protected are visible to
other classes in the same package, and to
subclasses in other packages, but not to
clients in other packages
12- 14
Two Kinds of Visibility
• Inherited Visibility and Direct Access Visibility:
class A {
int _x;
…
}
class B extends A {
… _x … // inherited visibility of x
… A._x … // direct access visibility of x
}
12- 15
Summary of Visibility
Visibility
public
clients in
D
same package
default
D
protected private
D
none
clients in
D
different package
none
none
none
subclass in D & I
same package
D&I
D&I
none
subclass in D & I
different package
none
I
I = inherited access, D = direct access
none
12- 16
Using Protected
• When there's a possibility that a class will have
subclasses (and you want the attributes and
methods to be usable in the inheritance
hierarchy), you should use protected
• Inherited protected variables and methods are
considered to be protected members of the
subclass (visible to further subclasses, and
hidden from clients)
• Inherited public variables and methods are
considered to be public members of the subclass
(visible to everyone)
12- 17
class PreciseTime extends Time {
Now we override
…
public void printTime ( ) {
printTime( )
if ((_hour == 0) && (_minute == 0))
System.out.print(“midnight”);
else if ((_hour == 12) && (_minute == 0))
System.out.print(“noon”);
else {
if
(_hour == 0)
System.out.print(12);
else if (_hour > 12) System.out.print(_hour - 12);
else
System.out.print(_hour);
if (_minute < 10) System.out.print(“:0”+
else
System.out.print(“:” +
if (_second < 10) System.out.print(“:0”+
else
System.out.print(“:” +
if (_hour < 12)
else
}
}
}
System.out.print(“AM”);
System.out.print(“PM”);
_minute);
_minute);
_second);
_second);
Doesn't Work
• Problem is, it doesn't work: the new printTime
accesses _hour and _minute, private instance
variables of class Time
• So we need to change the definition of class Time:
class Time {
protected int _hour, _minute;
…
}
• Still no access to _hour and _minute from regular
clients of Time, just to PreciseTime and other
subclasses of Time
12- 19
Constructors for Subclasses
• Java guarantees that a class’s
constructor method is called whenever
an instance of that class is created
• It also guarantees that the constructor is
called whenever an instance of any
subclass is created
• Therefore, every constructor method
must call (explicitly or implicitly) its
superclass constructor method
12- 20
Constructors for Subclasses
• If we have an inheritance hierarchy:
class B
|
subclass C of B
|
subclass D of C
…
subclass F of …
|
subclass G of F
If a new object of class G is created, the constructors will be
called in order B, C, D, … , F, G (i.e., G calls F, which calls E,…)
12- 21
Constructor Chaining
• If the first statement in a constructor is not an explicit
call to a constructor of the superclass (using super),
or an explicit call to another constructor in the same
class (using this), then Java implicitly inserts the call
super( ) (i.e., super with no arguments)
• Even if this is used to invoke another constructor in
the same class, eventually some constructor will
(explicitly or implicitly) invoke the superclass
constructor
• If the superclass has no zero-argument constructor,
the implicit super( ) causes a compilation error
12- 22
super( )
• Therefore, if a superclass doesn't have a zeroargument constructor, the subclass must explicitly
call the superclass's constructor with arguments:
class C extends B {
…
public C (…) {
super( B's constructor arguments );
…
}
}
12- 23
super( )
• The call to super(…) must be the first
statement in the body of C's constructor
• The constructor for PreciseTime made use
of this feature, calling super(h, m) to allow
the Time constructor to do initialization
public PreciseTime(int h, int m, int s) {
super(h, m);
_second = s;
}
12- 24
Dynamic Binding
• I said that a PreciseTime object is also
(kind of) a Time object
• It's a useful way of thinking about it, and
it is the basis for a very powerful feature
of Java, dynamic binding
• A PreciseTime object can be used
almost anywhere that a Time object can
be used
12- 25
Several Passes at Polymorphism
• Polymorphism means “taking many forms”:
a reference of a given class can adapt take
the form of any of its subclasses.
• First we will look at the polymorphism and
dynamic binding quickly – a few key facts
• Then we will look at it in depth – this set of
slides adapted (with permission) from:
www.cc.gatech.edu/classes/AY2002/cs1322_spring/slides/
current/CS2_22_PolymorphismDynamicBinding.ppt
12- 26
This is legal, blurring the distinction of
Time and PreciseTime
Time dawn;
dawn = new PreciseTime(3, 45, 30);
• A Time variable (like dawn) can contain a
reference to a PreciseTime object
• More generally, a CCC variable can contain
a reference to any object of any class in
CCC's subclass hierarchy (down the tree –
but not up the tree)
12- 27
There's an order to this
Time dawn;
dawn
heap
12- 28
This is legal, blurring the distinction of
Time and PreciseTime
Time dawn;
dawn = new PreciseTime(3, 45, 30);
dawn
dawn
Attributes:
_hour = 3
_minute = 45
_second = 30
Methods:
…
heap
12- 29
So now what?
• What happens if we send dawn the
printTime( ) message?
dawn.printTime( );
printTime( ) is defined in both Time and
PreciseTime classes
• dawn was declared as a Time variable, but
the actual object in dawn is a PreciseTime
object
• So the printTime( ) defined in the
PreciseTime class will be used
12- 30
Static Binding of Methods
• Before we had subclasses, life was simple
• The Java compiler could always figure
out, without running the program, which
instance method would be invoked
• The ability to know the exact method that
will be invoked every time a message is
sent is called static binding of methods
12- 31
Dynamic Binding
• This is no longer true when we
have subclasses
• It is possible to specify in a
program that there's an object
of some class, B (i.e., the object
is defined as being referenced
by a variable of type B)
• B has subclasses C and D
• C and D each provide their own
definition of method f ( )
B newObj;
B
C
D
12- 32
Dynamic Binding
• The actual creation of the
object (C or D) only occurs
at runtime
x might come from the user
if (x == 7)
newObj = new C( );
else
newObj = new D( );
• Therefore, the compiler
can't know, when the object
newObj is sent f ( ), whether
newObj.f( );
it will be handled by the C
Using f( ) from
definition or the D definition;
class C or D?
we can only know at runtime
12- 33
Polymorphism Pass 2:
More In Depth
• Polymorphism is an important concept that is a
part of Object Oriented Programming
• We often would like to deal with a collection of
various types of objects. We want to process
members of that group in a generic way. Yet in
the end, we’d like specific and appropriate
behavior to still occur.
• This set of slides adapted (with permission) from:
www.cc.gatech.edu/classes/AY2002/cs1322_spring/slides/current/
CS2_22_PolymorphismDynamicBinding.ppt
12- 34
Polymorphism
• Example: We have an array of animals, each of
which is an object of one subclass out of several
possible subclasses of Animal. The array is
declared to have Animal as its element type.
Now we’d like to process through the array and
have each element invoke a makeNoise() method.
• Luckily when a method call is made, the compiler
isn’t too concerned about the specifics of the
method being called. It’s question is: “is there a
method with a matching signature?”
12- 35
Array of Animals
Animal
extends
Bird
extends
Dog
extends
Fish
• Fill an array with Bird, Dog, Fish – but
the array is an array of Animal
An array of Animal – we want to
fill it with different instances of
animals, but send the same
message to each – they each
will respond differently
[0]
[1]
[2]
12- 36
Polymorphism
class Animal {
public void makeNoise ( ) {
System.out.println("I am an animal.");
} // of makeNoise
} // of Animal
class Fish extends Animal {
public void makeNoise( ) {
System.out.println("Glug glug gurgle gurgle");
} // of makeNoise
} // of Fish
class Bird extends Animal {
public void makeNoise( ) {
System.out.println("Tweet tweet flap flap");
} // of makeNoise
} // of Bird
12- 37
Polymorphism (cont’d)
class Dog extends Animal {
public void makeNoise( ) {
System.out.println("Sniff sniff woof woof");
} // of makeNoise
public void bark( ) {
System.out.println("Arf Arf");
} // of bark
}
// of Dog
12- 38
Polymorphism
public class Driver {
public static void main (String[ ] argv) {
Animal[ ] animalArray = new Animal[3];
int index;
Output:
Tweet tweet flap flap
animalArray[0] = new Bird( );
Sniff sniff woof woof
animalArray[1] = new Dog( );
Glug glug gurgle gurgle
animalArray[2] = new Fish( );
for (index = 0; index < animalArray.length; index++) {
animalArray[index].makeNoise( );
} // of for
the Animal class has
} // of main
makeNoise, so any
} // of Driver
member of the array
can makeNoise
12- 39
Polymorphism and Dynamic Binding
• Polymorphism & Dynamic Binding together insure
that the correct makeNoise( ) method will always
be called.
• An object of a subclass can be substituted for its
superclass, e.g., a bird for an animal.
“A bird is a animal.” Yes.
• The reverse is not true: can’t substitute superclass
for a subclass, e.g., CANNOT substitute an animal
for a bird.
“An animal is a bird?” No. Not necessarily.
12- 40
instanceof
• The keyword instanceof is used to
ask an object if it is an instance of
the specified class, e.g., "Is this
particular animal of class Dog?"
(d instanceof Dog)
• It’s a boolean relation, returning true
or false:
if (d instanceof Dog) {
…
}
12- 41
Casting with Polymorphism
public class Driver2 {
public static void main(String[ ] argv) {
Animal[ ] = animalArray[3];
Dog d;
int i;
animalArray[0] = new Bird( );
animalArray[1] = new Dog( );
animalArray[2] = new Fish( );
for (i = 0; i < animalArray.length; i++)
if (animalArray[i] instanceof Dog){
d = (Dog) animalArray[i];
d.bark( );
} // if
We cast before calling bark()
} // main
because only dogs can bark.
Not all Animals can execute the method
} // Driver2
12- 42
Upcasting
• Why didn’t we have to explicitly cast
Bird, Dog and Fish to Animal when we
put the instances into the array on the
previous slide?
• Because this is upcasting – casting
from a derived class to a base class –
and Java does it for us automatically
• You can also write it explicitly if you
want (no harm done)
12- 43
Casting a Superclass to a Subclass
• Casting used here to give an object of a superclass the form
of the appropriate subclass. If we just wrote:
if (animalArray[i] instanceof Dog) {
animalArray[i].bark();
}
it would produce an error because objects of class Animal
have no method called bark. So, we first cast the object that
instanceof tells us is indeed a Dog object, as a Dog.
if (animalArray[i] instanceof Dog) {
d = (Dog) animalArray[i]
d.bark( );
}
12- 44
Why is Casting Necessary Here?
• If Java can determine that a given Animal
is or is not a Dog (via instanceof), then
why do we need to cast it to a Dog object
before Java can recognize that it can
bark?
• Why can’t Java do it for us automatically?
• Answer: the difference between compiletime and run-time type checking.
12- 45
Why is Casting Necessary Here?
Source
code
Byte
code
Compile
errors
JVM
Interpreter
Program
runs
errors
Compile-time Errors:
Run-time Errors:
• Those that are discernable
without the program executing.
• Those that are discernable only when the
program is running with actual data values.
• Question of language legality:
"Is this a legal statement?"
e.g.,
index = strName;
• Question of execution legality:
"Is it legal for this variable to have the
actual value assigned to it?", e.g.,
Statement is not legal.
animalArray[<badIndex>] = someAnimal
Statement legal, but particular index value isn’t.
12- 46
Why is Casting Necessary Here?
if (animalArray[i]
instanceof Dog) {
animalArray[i].bark();
}
• 1st line is legal.
2nd line isn’t (unless array has Dog).
We can see that 1st line guarantees
2nd is legal.
• Compiler cannot see inter-statement
dependencies… unless compiler
runs whole program with all possible
data sets!
• Runtime system could tell easily. . .
BUT. . . We want most checking at
compile-time for reasons of both
performance and correctness.
if (animalArray[i]
instanceof Dog) {
d = (Dog) animalArray[i];
d.bark( );
}
• Here, legality of each line of code can be
evaluated at compile time.
• Legality of each line discernable without
worrying about inter-statement dependencies,
i.e., each line can stand by itself.
• Can be sure that code is legal (not
sometimes-legal).
A Good Use for Casting:
Resolving polymorphic ambiguities
for the compiler.
12- 47
How Objects Are Created
Dog d = new Dog();
1.
d
2.
3.
Object
Object
Object
Animal
Animal
Animal
Dog
d
Dog
d
Dog
Execution Time
An implicit super() calls parent class constructor first.
After all, a Dog is-a Animal, && is-a Object
12- 48
Multiple References to Different
Types of the Same Instance
We can create new references that point to different
types in the same block of memory.
Object
o
Animal
a
Dog
Animal a = new Dog();
Object
Animal
a
Dog
Object o = a;
12- 49
Dynamic Binding
o
a
Object
.toString()
Animal
.toString()
Dog
.toString()
When calling a method
on a reference, the
method must be present
in the type (or inherited).
However, the specific
implementation called is
determined at runtime.
That’s ‘dynamic binding’.
System.out.println(o.toString());
Dynamic binding provides runtime resolution to the
most specific implementation possible.
12- 50
Casting and Polymorphism
o
Object
Animal
a
Dog
.doYourThing()
.doYourThing()
o.doYourThing(); // ERROR!
Dynamic binding
does not work
miracles. The
reference type must
have the method
available (in the
present class or
inherited), or else a
compilation error
occurs.
The calling type must have the method, either in
its instance, or from its parent.
12- 51
What Should Our Array Elements Be?
So, we have these three blocks, representing objects in memory, each
different, holding unique references and primitive values. How can these
disparate objects be held in an array, which must be heterogeneous?
Object
Object
toString()
Animal
int numLegs = 2
String strType
toString();
move();
Bird
move();
Object
toString()
Animal
int numLegs = 0
String strType
toString();
move();
Fish
move();
toString()
Animal
int numLegs = 3
String strType
toString();
move();
Dog
move();
bark();
The organizing principle is the shared inherited relationship with
Animal. Since Fish, Dog and Bird all extend from Animal, we can
make an Animal array to hold different expressions of this class.
12- 52
What Should Our Array Elements Be?
So, we have these three blocks, representing objects in memory, each
different, holding unique references and primitive values. How can these
disparate objects be held in an array, which must be heterogeneous?
Object
Object
toString()
Animal
int numLegs = 2
String strType
toString();
move();
Bird
move();
Object
toString()
Animal
int numLegs = 0
String strType
toString();
move();
Fish
move();
toString()
Animal
int numLegs = 3
String strType
toString();
move();
Dog
move();
bark();
We could also have made an array of Object types. But we then will
have problems invoking methods on members of this array, since Object
lacks key methods--like move().
12- 53
What Should Our Array Elements Be?
So, we have these three blocks, representing objects in memory, each
different, holding unique references and primitive values. How can these
disparate objects be held in an array, which must be heterogeneous?
Object
Object
toString()
Animal
int numLegs = 2
String strType
toString();
move();
Bird
move();
Object
toString()
Animal
int numLegs = 0
String strType
toString();
move();
Fish
move();
toString()
Animal
int numLegs = 3
String strType
toString();
move();
Dog
move();
bark();
So we select Animal as our common type. It’s the most specific type,
and yet is still held in common by all the members we plan to hold in
the array.
12- 54
Multiple References to Instance
Bird bTemp = new Bird();
Object oTemp = (Object) bTemp;
Animal aTemp = (Animal) bTemp;
Object
toString()
Animal
Here, the casting
is not needed
since we are
upcasting.
It’s shown to
be explicit.
int numLegs = 2
String strType
toString();
move();
Bird
move();
oTemp
aTemp
bTemp
Recall that we can have many reference types pointing to the same Fish or
Dog or Bird instance in memory. Thus, since arrays must be of a single
type, we just polymorph any references we have into Animal references.
12- 55
Array Elements are of a Single Type
Object
toString();
Animal [ ]
final int length = 3
[1]
[0]
Object
Object
int numLegs = 2
String strType
toString();
move();
Bird
move();
Object
toString()
toString()
toString()
Animal
[2]
Animal
int numLegs = 0
String strType
toString();
move();
Fish
move();
Thus, when we have
many objects in
memory, we polymorph
our references to the
instances. This gives
us an array of Animal
types, even though
each instance is a
different subclass.
Animal
int numLegs = 3
String strType
toString();
move();
Dog
move();
bark();
Let’s invoke some
methods on these
objects.
12- 56
Object
toString()
Is our
picture correct?
Animal
int numLegs = 2
String strType
toString();
move();
Bird
What if we executed this code:
Object oTemp;
oTemp = animalArray[1];
move();
Object
toString();
Object
toString()
Animal [ ]
Animal
int numLegs = 0
String strType
toString();
move();
final int length = 3
Object
oTemp
Fish
move();
Object
toString()
Animal
int numLegs = 3
String strType
toString();
move();
Dog
move();
bark();
No. The code
works. But our drawing is
pointing to the wrong
part of our object
Object
toString()
Is our
picture correct?
Animal
int numLegs = 2
String strType
toString();
move();
Bird
What if we executed this code:
Object oTemp;
oTemp = animalArray[1];
move();
Object
toString();
Object
toString()
Animal [ ]
Animal
int numLegs = 0
String strType
toString();
move();
final int length = 3
oTemp
Fish
move();
Object
toString()
Animal
int numLegs = 3
String strType
toString();
move();
Dog
move();
bark();
Much better. This
fussiness will pay
off shortly.
Object
toString()
Does this work?
Animal
int numLegs = 2
String strType
toString();
move();
Bird
move();
Object
Now, let’s add another line of
code:
Object oTemp;
oTemp = animalArray[1];
oTemp.move();
toString();
Object
toString()
Animal [ ]
Animal
int numLegs = 0
String strType
toString();
move();
final int length = 3
Fish
oTemp
move();
Object
toString()
Animal
int numLegs = 3
String strType
toString();
move();
Dog
move();
bark();
NO.
The class Object
has no method
called move()
Object
toString()
Animal
int numLegs = 2
String strType
toString();
move();
Bird
move();
Object
toString();
Object
The fix is in:
Object oTemp;
oTemp = animalArray[1];
Animal aTemp =
(Animal) oTemp;
toString()
Animal [ ]
Animal
int numLegs = 0
String strType
toString();
move();
final int length = 3
Fish
oTemp
move();
Object
toString()
aTemp
Animal
int numLegs = 3
String strType
toString();
move();
Dog
move();
bark();
Note the explicit
down casting
was necessary.
Object
toString()
Animal
int numLegs = 2
String strType
toString();
move();
Bird
move();
Object
toString();
Object
The fix is in:
Object oTemp;
oTemp = animalArray[1];
Animal aTemp =
(Animal) oTemp;
aTemp.move();
toString()
Animal [ ]
Animal
int numLegs = 0
String strType
toString();
move();
final int length = 3
Fish
oTemp
move();
Object
toString()
aTemp
Animal
int numLegs = 3
String strType
toString();
move();
Dog
move();
bark();
Hmm... Let’s look at
this closely.
Object oTemp;
oTemp = animalArray[1];
Animal aTemp =
(Animal) oTemp;
aTemp.move();
Object
Object
toString()
toString()
Animal
int numLegs = 2
String strType
toString();
move();
Animal
Bird
move();
Object
toString();
Object
Animal
int numLegs = 0
String strType
toString();
move();
It looks like both
Animal and Fish
have move( ) methods.
Which one gets called
when the
aTemp.move( ) line
executes?
Fish
toString()
Animal [ ]
final int length = 3
oTemp
int numLegs = 3
String strType
toString();
move();
aTemp
move();
Fish
move();
Object
toString()
Animal
int numLegs = 3
String strType
toString();
move();
Dog
move();
bark();
The reference type
we are using is an
Animal type. Would that
determine whether Animal
or Fish has their method called?
Dynamic Binding
Object oTemp;
oTemp = animalArray[1];
Animal aTemp = (Animal) oTemp;
aTemp.move();
Object
aTemp
toString()
Animal
Understand this term.
Understand what is does.
It is a CORE
feature of any Object
Oriented language.
int numLegs = 3
String strType
toString();
move();
Fish
move();
Here, the principle of dynamic binding will ensure that at run time, the
most specific behavior will be invoked. Here, the Fish move() method
is more specific than its parent method. So, the Fish’s move() method
gets called with the aTemp.move() line.
12- 63
Sanity Check
Object oTemp;
oTemp = animalArray[1];
Animal aTemp = (Animal) oTemp;
System.out.println
(oTemp.toString());
What Happens Here?
oTemp
Object
toString()
Animal
int numLegs = 3
String strType
toString();
move();
Fish
Does casting
somehow
overpower
dynamic
binding?
move();
What about:
System.out.println (
((Object)oTemp).toString()
);
12- 64
Sanity Check
Object oTemp;
oTemp = animalArray[1];
Animal aTemp = (Animal) oTemp;
System.out.println
(oTemp.toString());
What Happens Here?
Object
oTemp
toString()
Animal
int numLegs = 3
String strType
toString();
move();
Fish
move();
No matter
how you
cast things,
dynamic
binding takes
hold. It’s
like the
law of gravity.
What about:
System.out.println (
((Object)oTemp).toString( )
);
12- 65
Sanity Check
Object oTemp;
oTemp = animalArray[1];
Animal aTemp = (Animal) oTemp;
System.out.println
(oTemp.toString());
What if Fish had its own
toString()?
Object
oTemp
toString()
Animal
int numLegs = 3
String strType
toString();
move();
Fish
move();
toString();
No matter
how you
cast things,
dynamic
binding takes
hold. It’s
like the
law of gravity.
Dynamic binding will always resolve, at run time, to the
most specific version of the method. ALWAYS.
12- 66
“Always?”
Object oTemp;
oTemp = animalArray[1];
oTemp.move(); // WRONG!
Does dynamic binding
also work miracles?
That is, does it let
you find methods in
extending classes, if the
present class does not
have such a method?
Object
oTemp
toString()
Animal
int numLegs = 3
String strType
toString();
move();
No such
method move()
in Object
Fish
move();
toString();
NO. This would cause a compile time error. Java is strongly typed, meaning that
each time you invoke a method, the method MUST be present in the class--even if
dynamic binding would later find a more specific version. So: no, dynamic binding
does not defeat type safety in Java.
12- 67
Another example –
A Hierarchy Diagram
Object
File
RestrictedFile
Has method (among others):
public String toString()
Has methods:
public boolean isOpen()
public void open()
public void close()
public String getName()
Has methods:
public boolean isLocked()
public void lock()
public void unlock(long key)
Redefines open() (only open file if it is
unlocked; it’s locked at creation)
12- 68
Sub-classes as Sub-types
• We can view a RestrictedFile object from
3 different points of views:
–As a RestrictedFile. This is the most narrow
point of view (the most specific). This point of
view ‘sees’ the full functionality of the object.
–As a File. This is a wider point of view (a less
specific one). We forget about the special
characteristics the object has as a
RestrictedFile (we can only open and close
the file).
–As a plain Object.
12- 69
Variables can Reference Sub-class
Values
• We view an object by using an object reference.
• A variable of type ‘reference to File’ can only
refer to any object which is a File.
File f = new File(“story.txt”);
• But a RestrictedFile is also a File, so f can
also refer to a RestrictedFile object.
File f = new RestrictedFile(“visa.dat”, 12345);
• The type of the reference we use determines the
point of view we will have on the object.
12- 70
RestrictedFile point of view
• If we refer to a RestrictedFile object using a
RestrictedFile reference we have the
RestrictedFile point of view – we see all the
methods that are defined in RestrictedFile and
up the hierarchy tree.
RestrictedFile f = new RestrictedFile(“visa.dat”, 12345);
f.close();
f.lock();
f.unlock(12345);
String s = f.toString();
12- 71
File point of view
• If we refer to a RestrictedFile object using a File
reference we have the File point of view – which
lets us use only methods that are defined in class
File and up the hierarchy tree.
File f = new RestrictedFile(“visa.dat”, 12345);
f.close();
f.lock(); //Can’t use this method
f.unlock(12345); //Can’t use this method
String s = f.toString();
12- 72
Object point of view
• If we refer to a RestrictedFile object using an
Object reference we have the Object point of
view – which let us see only methods that are
defined in class Object.
Object f = new RestrictedFile(“visa.dat”, 12345);
f.close(); //Can’t use this method
f.lock();
//Can’t use this method
f.unlock(12345); //Can’t use this method
String s = f.toString();
12- 73
Points of View
RestrictedFile





...
isOpen
isLocked
key







toString()
...
isOpen()
open()
close()
lock()
unlock(key)
isLocked()
12- 74
Compile time-type vs.
run-time type
• A variable of a reference type has a declared type that is
known at compile time and never changes.
File f;
• A reference variable may hold values of any subclass of
its declared type
f = new RestrictedFile(“visa.dat”,12345);
• The type of the values held may change during the
running of the algorithm and is not known during compile
time
f = new File(“visa.dat”);
• The run-time type is always some subclass of the
compile-time type.
12- 75
Widening
• Changing our point of view of an object, to a wider
one (a less specific one) is called widening.
File file;
file = new RestrictedFile(“visa.dat”, 1234);
File reference
File point of view
RestrictedFile reference
RestrictedFile point of view
Widening
12- 76
Point – distanceFrom
/**
* A point on a grid.
*/
public class Point {
/**
* Computes the distance from another point
* @param p The given point.
*/
public double distanceFrom(Point p) {
int dx = x-p.x;
int dy = y-p.y;
return Math.sqrt(dx*dx+dy*dy);
}
// ... more methods
}
12- 77
Pixel
/**
* Represents a pixel on a graphical area.
*/
public class Pixel extends Point {
// The color of the pixel
private Color color;
/**
* Constructs a new pixel.
* @param x,y The coordinates of the pixel.
* @param color The color of the pixel.
*/
public Pixel(int x, int y, Color color) {
super(x,y);
this.color = color;
}
// ... more methods
}
12- 78
Widening parameters
• In the following example, the method
distanceFrom() expects a ‘reference to Point’ and
gets ‘a reference to Pixel’, we are thus widening our
point of view of the Pixel object.
Point p1;
Pixel p2;
p1 = new Point(2, 3);
p2 = new Pixel(5, 6, Color.red);
double d = p1.distanceFrom(p2);
12- 79
Compile-time vs. run-time: method
invocation
• When we invoke a method on an object we always do it
through a reference
• The implementation of the method which is most specific will
be chosen.
• Java methods are virtual, i.e. the method which will be invoked
is determined by the run-time type of object and not on the
compile-time type of reference.
• The identity of the invoked method is determined at runtime.
• There are languages that use different mechanisms for method
invocation.
12- 80
Type of Method is Determined at
Runtime
File file;
if (Math.random() >= 0.5)
file = new File(“visa.dat”);
else
file = new RestrictedFile(“visa.dat”, 76543);
file.open();
Will the file be opened if the number randomly
generated is less than 0.5?
12- 81
Another Example:
Mouse in a Maze
public class Mouse {
private instance variables
public Point tellLocation( ) { … }
public int tellDirection( ) { … }
public Mouse(Maze m) { … }
public void makeMove( ) { … }
private boolean outside ( ) { … }
private boolean facingWall( ) { … }
private void stepForward( ) { … }
private void turnLeft( ) { … }
private void turnRight ( ) { … }
}
12- 82
Specialization through Inheritance
• So now we want to create two kinds of mice; only
makeMove( ) will change
• RightMouse will have one strategy (right paw on
wall)
• StraightMouse will have another strategy (go
straight, turn right when can't go straight)
• No need to duplicate code; just make Mouse be a
superclass, and RightMouse and StraightMouse
only need to provide their own makeMove( ) code
12- 83
abstract
• We'll let the user specify which kind of mouse he
wants at runtime
• The Mouse class will have all the methods and
instance variables, except makeMove( )
• The Mouse class isn't intended to be used directly;
we expect it to be subclassed
• To enforce this, we explicitly specify in Mouse that
makeMove( ) is supposed to be implemented in a
subclass
12- 84
abstract
public abstract void makeMove( );
• This “prototype” is included in the Mouse class
• "abstract" tells Java that makeMove( ) is expected
to be defined in a subclass
• Any class that includes an abstract method is itself
abstract, and has to be declared abstract itself
• Such an abstract class cannot be instantiated by a
client, you just have to subclass it and define its
abstract methods
• So the Mouse class will be abstract
12- 85
abstract Class, subclassed
abstract class Mouse
protected boolean _started;
protected int _direction; etc.
public abstract void makeMove( );
etc.
protected boolean facingWall( ) { return theMaze.checkWall
(_direction, location); }
extends
extends
RightMouse
StraightMouse
public RightMouse(…) {…}
public void makeMove( ) {…}
public StraightMouse(…) {…}
public void makeMove( ) {…}
12- 86
The new class Mouse
abstract class Mouse {
public final int
NORTH=0, EAST=1, SOUTH=2, WEST=3;
protected Maze _theMaze;
protected boolean _started = false;
//true once the maze is entered
protected Point _location; //location of this mouse
protected int _direction; //direction mouse is facing
public Point tellLocation( ) { return _location; }
public int tellDirection( ) { return _direction; }
12- 87
public Mouse (Maze m) {
// Where do I start?
_location = m.getStartLocation( );
// In what direction do I face initially?
_direction = m.getStartDirection( );
_theMaze = m;
}
public abstract void makeMove( );
protected boolean outside ( ) {
// Am I outside the maze?
return _theMaze.outside(_location);
}
protected boolean facingWall ( ) {
return _theMaze.checkWall(_direction, _location);
}
protected void stepForward( ) {
switch (direction) {
case NORTH:
_location.y--; break;
case EAST:
_location.x++; break;
case SOUTH:
_location.y++; break;
case WEST:
_location.x--; break;
}
}
protected void turnLeft( ) {
_direction = (_direction + 3) % 4;
}
protected void turnRight( ) {
_direction = (_direction + 1) % 4;
}
}
Definition of class RightMouse
class RightMouse extends Mouse {
public RightMouse (Maze aMaze ) { super(aMaze); }
public void makeMove( ) {
if (_started) {
if ( !outside( ) ) {
turnRight( );
while ( facingWall( ) ) {
turnLeft( );
}
stepForward( );
}
}
else {
stepForward( );
_started = true;
}
}
}
12- 90
Definition of class StraightMouse
class StraightMouse extends Mouse {
public StraightMouse (Maze aMaze ) { super(aMaze); }
public void makeMove( ) {
if (_started) {
if ( !outside( ) ) {
if ( facingWall( ) ) {
turnRight( );
makeMove( );
}
else stepForward( );
}
}
else {
stepForward( );
_started = true;
}
}
}
12- 91
Dynamic Generation
of the Kind of Mouse
• Now, the main( ) method lets the user
dynamically specify whether the
mouse will be a RightMouse object or
a StraightMouse object
• The variable referencing the mouse
will be of class "Mouse", but the
actual generation of the object (either
type) occurs at runtime
12- 92
Runtime Selection
public class MouseMaze {
public static void main (String[ ] args) {
Maze theMaze = new Maze( );
Mouse speedy = selectMouse(theMaze);
…
}
private static Mouse selectMouse(Maze theMaze) {
SimpleInput sinp = new SimpleInput(System.in);
while (true) {
System.out.print("Choose RightMouse (0) "
+ "or StraightMouse (1): ");
int i = sinp.readInt( );
if ( i == 0 ) return new RightMouse(theMaze);
if ( i == 1 ) return new StraightMouse(theMaze);
}
}
}
12- 93
Class Inheritance plus Dynamic
Method Binding
• speedy is a Mouse, but it might be a
RightMouse or a StraightMouse
• When speedy is sent the makeMove( )
message, it will do whatever is appropriate
for the kind of mouse it is
• The combination of Class Inheritance plus
Dynamic Method binding is very powerful,
allowing reuse of code, but flexible
response to messages
12- 94
Interfaces
• Java has a way of specifying "classes" that
contain nothing but declarations of abstract
methods
• These provide no code, just a list of
methods that every subclass has to define
• It allows clients to define a method having
formal parameters of the abstract "class",
but whose actual parameters can belong to
any class in its hierarchy
12- 95
Interface Declaration
• This is so common that Java provides a special way of
specifying it: interface declarations
• Interface declarations are like abstract classes, but are
restricted to containing abstract method declarations
and symbolic constant definitions:
interface interface_name {
definitions of symbolic constants, and
declarations of abstract methods
}
• Like classes, interfaces are placed in separate files,
with the .java extension
12- 96
Syntax Differences
• Classes that contain real definitions of these
abstract methods write "implements
interface_name" instead of "extends…"
• All the methods in the interface are abstract,
so you don't write "abstract" in front of them
• All symbolic constants are assumed to be
public, static, and final, so don't write those
keywords, either
12- 97
More Importantly!
• A class can implement more than one
interface, while it can only be a subclass
of one class; this allows us to use
interfaces more flexibly
• We might have interfaces I1 and I2, with
methods that class C defines; even if C is
a subclass of B, we could still write:
class C extends B
implements I1, I2 { … }
12- 98
One Use for Interfaces
• Sometimes interfaces are used to give
definitions of symbolic constants to be
used in several classes
public interface Direction {
int NORTH = 0, EAST = 1, …
}
• Then several other classes implement this
interface:
public class Maze
implements Direction { … }
12- 99
Another use for interfaces
• Define a plotting function that accepts a function as
one of its arguments:
void plot (double x0, double x1,
double delta, Function f) {
// plot f on values x0, x0+delta, …, x1
…
}
• We can't pass a function as an argument
• But we can define different objects that respond to
the message "apply( )", and each different kind of
object contains a function
12- 100
interface Imposing a Requirement
on Classes
interface Function
double apply(double x);
implements
SineFunction
…
double apply(double x ) {…}
…
interface
implements
EmpiricalFunction
…
double apply(double x ) {…}
…
12- 101
The Role of Interfaces
• Interfaces play a role like the abstract
classes we saw in previous slides
• Interfaces are data types in Java, just
like classes are
• When a class implements an
interface, instances of the class can
be assigned to variables of the
interface type
12- 102
What it Looks Like (these are in
different files)
void plot (double x0, double x1, double delta, Function f) {
// plot f on values x0, x0+delta, …, x1
…
}
interface Function{
double apply(double x);
}
class SineFunction implements Function {
double apply(double x) { return Math.sin(x); }
}
class EmpiricalFunction implements Function {
double apply(double x) { … }
}
12- 103
Calling them
• Then these are legal calls (assuming
appropriate constructors for SineFunction
and EmpiricalFunction):
plot(0.0, 10.0, 0.1, new SineFunction( ));
and
plot(0.0, 10.0, 0.1,
new EmpiricalFunction(60, 0.0, 59.0));
12- 104
The Point
• The point is, we can use objects of type
SineFunction and of type EmpiricalFunction in the
same context (e.g., as an argument of the plot( )
method)
• They'll both implement the interface Function;
they both provide a definition of apply( )
• But they may not belong in the same class
hierarchy, logically, and we need not require that
they be in the same hierarchy
12- 105
Interfaces can also Inherit
• Interfaces can also be organized
conveniently into inheritance hierarchies
interface I extends J …
• I actually consists of all the methods and
constants in I itself together with those in J
• A class implementing I has to implement all
those methods and constants
12- 106
Exception Handling
• Java provides us with a relatively clean way of
catching run-time errors — exceptions
• An exception is an object
• An exception is a signal that some unusual
situation (like an error) has occurred
• When "something goes wrong", an exception
object is generated and passed back in a
special way
12- 107
Exceptions in Java
• Java actually uses the notion of exception for 3
related (but different) purposes:
– Errors: an internal Java implementation error was
discovered
» E.g: out of memory
– Runtime exceptions: a programming logic error was
discovered
» E.g. division by 0
– Checked Exceptions: an exceptional case was discovered
» E.g. file not found
12- 108
Exceptions in Java
• Errors and Runtime exceptions will
usually cause the program to crash
• Checked exceptions should usually
be handled by the programmer
12- 109
Occurrence of a runtime exception
public class ExceptionExample {
public static void main(String[] args) {
int[] a = {2, 4, 6, 8};
for(int j = 0; j <= a.length ; j++)
System.out.println(a[j]);
}
}
12- 110
Program Crash due to a runtime
exception
12- 111
Runtime exceptions in the Java
API
•
•
•
•
•
java.lang.ArithmeticException
java.lang.NullPointerException
java.lang.IllegalArgumentException
java.lang.NegativeArraySizeException
java.lang.ArrayIndexOutOfBoundsExcepti
on
• java.lang.ClassCastException
12- 112
try, catch, finally
• The try clause establishes a block of code
that might have exceptions or abnormal exits
• The try block is followed by zero or more
catch clauses that specify code to handle
various types of exceptions
• the finally clause specifies code that will
always be performed, if any part of the try
block is executed (good for cleanup, closing
files, etc.)
12- 113
try {
// Normally this code runs from top of block to bottom
// without problems. But it sometimes may raise
// exceptions or exit the block via a break, continue, or
// return statement
}
catch (SomeException e1) {
// Handle an exception object e1 of type SomeException
// or of a subclass of that type
}
catch (AnotherException e2) {
// Handle an exception object e2 of type AnotherException
// or of a subclass of that type
}
finally {
// Always execute this code, after we leave the try clause,
// regardless of whether we leave it, normally, with an
// exception that is caught or not caught, or because of a
// break, continue, or return statement
}
How are throws caught? Recall the
runtime stack, and method calls
main (String[ ] args) {
...
...
...
obj.e();
...
}
top
void e ( ) {
...
...
obj.f( );
...
}
void f ( ) {
System.out.println(“Hi there!”);
System.out.println(“Nice weather!”);
...
obj.g( );
System.out.println(“That was fun!”);
System.out.println(“Time to move on!”);
}
void g ( ) {
System.out.println(“A!”);
System.out.println(“B!”);
…
System.out.println(“C!”);
System.out.println(“D!”);
}
Method g( )
Where we came from: f, line 4
Method f( )
Where we came from: e, line 3
Method e( )
Where we came from: main, line 4
Method main( )
STACK
12- 115
throws are handled up
the calling hierarchy
• If an exception object were generated in g( ) (like
an array index was out of bound), the system
would first look if it is caught in g( )
• If it's not caught there, the system sees if it is
caught in f( ); then in e( ); finally in main( )
• If not caught at all, the exception object causes
the Java interpreter to print an error message
and a stack trace and exit
main (String[ ] args) {
...
...
...
obj.e();
...
}
void e ( ) {
...
...
obj.f( );
...
}
void f ( ) {
System.out.println(“Hi there!”);
System.out.println(“Nice weather!”);
...
obj.g( );
System.out.println(“That was fun!”);
System.out.println(“Time to move on!”);
}
void g ( ) {
System.out.println(“A!”);
System.out.println(“B!”);
…
System.out.println(“C!”);
System.out.println(“D!”);
}
12- 116
Exception Objects
• An exception in Java is an object that is an instance of
some subclass of java.lang.Throwable
• Throwable has two standard subclasses,
java.lang.Error and java.lang.Exception.
• Exceptions that are subclasses of Error are generally
unrecoverable and need not be caught
• Exceptions that are subclasses of Exception indicate
conditions that may be caught and recovered from
12- 117
Exception Objects
• Since exceptions are objects, they can contain data
and define methods
• The Throwable object (at the top of the exception
hierarchy) includes a String message to describe the
exception, and this is inherited by all its descendants;
the message is extracted via the method getMessage( )
• A few descendants add their own data (e.g.,
java.io.InterruptedIOException adds the field
public int bytesTransferred;
to signify how much of the I/O was complete before the
exception occurred)
12- 118
Exception life-cycle
When a program performs an illegal operation the following
happens:
– The regular flow of the program stops
– An exception object is created, which encapsulates the
information about the problem that occurred
– The method may try to catch and handle the exceptional
situation
– If the method ignores the exception the method execution
ceases.
– An exception then appears at the place in which the method
was called
– If the exception is not handled anywhere, the program
crashes.
12- 119
Declaring Exceptions
• Certain kinds of exceptions need to be declared in a
method’s declaration, if they are not handled inside the
method:
public void open_file( ) throws IOException {
// Statements that might generate an
// uncaught java.io.IOException
}
• You only need to declare exceptions that are not
subclasses of Error or of RuntimeException; these are
just too common to require declaring
• An example that does not need to be declared is
ArrayIndexOutOfBoundsException
12- 120
Creating our own Exceptions
• We can declare a new exception class,
and put it in the hierarchy of the class
Exception
• We need two constructors: one with no
argument, and one with a single String
argument giving a description of the
fault
• Let's look at an existing example from
the Java API, to understand how to
define our own
12- 121
class FileNotFoundException
package java.io;
public class FileNotFoundException
extends IOException {
public FileNotFoundException( ) { super( ); }
}
public FileNotFoundException(String s) {
super(s);
}
12- 122
How would we use it?
package java.io;
public class FileInputStream extends InputStream {
}
public FileInputStream(String name)
throws FileNotFoundException {
…
try {
fd = new FileDescriptor( );
open(name);
}
catch (IOException e) {
throw new FileNotFoundException(name);
}
}
12- 123
OK, so let's create our own
• Declare a new class,
GetOuttaHereException, and have it
extend the Exception class
• Provide it with two constructors, one that
takes no arguments and one that takes a
string argument (and both call super)
• throw new GetOuttaHereException with or
without a string argument
12- 124
GetOuttaHereException definition
public class GetOuttaHereException
extends Exception {
public GetOuttaHereException( ) { super( ); }
}
public GetOuttaHereException(String s) {
super(s);
}
12- 125
Now, use the exception in a
method, gateKeeper( )
void gateKeeper (Person candidate)
throws GetOuttaHereException {
…
if ( isBum(candidate) )
throw new GetOuttaHereException("You're a bum!");
if ( isBroke(candidate) )
throw new GetOuttaHereException("You're broke!");
if ( doesNotKnowJava(candidate) )
throw
new GetOuttaHereException("You don't know Java!");
…
}
12- 126
We will catch the exception in the
calling method, joinClub
void joinClub (Person candidate) {
try {
gateKeeper(candidate);
}
catch (GetOuttaHereException e) {
System.out.println("No, you can't join the club because "
+ e.getMessage( ));
return;
}
System.out.println("Welcome to the club!");
}
12- 127
Exceptions Hierarchy
• All the classes for indicating run-time errors are derived
from the class java.lang.Throwable.
• The object you deliver to the throw statement must be an
instance of class Throwable
• The constructor of class Throwable initializes all the
information about the location where the exception
occurred, the state of the run-time stack etc. In this way this
information is set for every exception object.
• The following diagram explains the inheritance hierarchy
for exceptions.
12- 128
Throwable class hierarchy
Throwable
Error
Exception
RuntimeException
12- 129
Input / Output
• A program often needs to communicate with
other devices. In other words it should
receive input and send output.
• There are many types of input sources:
– Reading a file from a local disk / diskette
– Receiving a web page from a remote server
– Receiving a communication message through a network.
Receiving a signal from a sensor of a robot
– Scanner, video camera, ...
– Mouse, keyboard, joystick, ...
12- 130
Input / Output
• Similarly, there are many types of output
destinations:
– Writing to a file on a local disk / diskette
– Sending query information to a remote web server
– Sending communication message to a remote host.
Sending a command to a robot controller.
– Printing a document to a printer / fax
– Displaying graphics on the screen
– ...
12- 131
GUI inputs and outputs
• GUI related inputs and outputs are
usually treated separately. They are
given special API
• GUI inputs and outputs include
receiving mouse, keyboard and
similar events, and displaying
graphics on the screen
12- 132
IO API - design goal
• We want to make a distinction
between the content of the data an
application receives/sends and the
source/destination of the data
• The same kind of data can be stored
on different types of media
• Similarly a given media can store
different types of data
12- 133
Scenario
• Suppose we have an image processing
application. It can read images, manipulate them
and store them on a permanent storage.
• We want our application to be able to read images
from different types of sources:
– local image files, remote images from the web, receiving
an image from a scanner, ...
• We want to be able to output the image to various
types of destinations:
– save the image to a local file, print the image on a
printer, send the image to a fax recipient, ...
12- 134
Scenario
Application
12- 135
IO Streams
• We can achieve the separation by designing a
common interface for reading any kind of data,
and common interface for writing any kind of data.
• This interface is implemented by the notion of
input and output streams.
• Any input can be represented as a sequence of
bits. For convenience we divide the sequence into
a sequence of bytes.
• Similarly any output can be represented as a
growing sequence of bytes.
12- 136
IO Streams
12
72
32
17
83
11
7
91
108
Input stream
reading direction
43
55
writing direction
31
37
34
13
17
1
15
Output stream
12- 137
Input streams
• An input stream is a sequence of bytes that is
attached to some input source.
• You can read data from the stream in a sequential
order. One byte at a time or several bytes at a time.
• Input streams are represented by the abstract class
java.io.InputStream.
• Subclasses of InputStream defines input streams that
are related to various data sources
• Class InputStream gives a common interface for
receiving data from various types of data sources
12- 138
Specific input streams
InputStream
...
FileInputStream
PipedInputStream
ByteArrayInputStream
12- 139
Class InputStream
• Class java.io.InputStream defines several methods that
support the abstraction of allowing sequential reading from a
stream:
public abstract int read() throws IOException
Reads the next byte from the stream. Return -1 if the
end of the stream was reached.
public int read(byte[] b) throws IOException
Reads up to b.length bytes from the stream into the array b.
Returns the number of bytes that were read.
12- 140
Input streams
public int read(byte[] b, int offset, int length)
throws IOException
Reads up to length bytes from the stream into
the array ‘b’ from the index ‘offset’. Returns the
number of bytes that were read.
public void close() throws IOException
Closes this input stream and releases any
system resources associated with the stream.
• Few additional methods (look up in the API)
12- 141
Output streams
• An output stream is attached to an output destination to
which you can write data.
• You can write data to the stream in a sequential order. One
byte at a time or several bytes at a time.
• Output streams are represented by the abstract class
java.io.OutputStream.
• Subclasses of OutputStream defines output streams that are
related to various data destinations
• Class OutputStream gives a common interface for sending
data to various types of data destinations
12- 142
Specific output streams
OutputStream
...
FileOutputStream
PipedOutputStream
ByteArrayOutputStream
12- 143
Class OutputStream
• Class java.io.OutputStream defines several methods that
support the abstraction of allowing sequential writing to a
stream:
public abstract void write(int b)
throws IOException
Writes the specified byte (given as an int) to this output
stream.
public void write(byte[] b) throws IOException
Writes b.length bytes from the specified byte array to
this output stream.
12- 144
Input streams
public void write(byte[] b, int offset,
int length) throws IOException
Writes length bytes from the specified byte array
starting at offset off to this output stream.
public void close() throws IOException
Closes this output stream and releases any
system
resources associated with the stream.
• Few additional methods (look up in the API)
12- 145
Reading/Writing from/to files
• java.io.FileInputStream is a subclass of
InputStream that let you read a file (viewed
as a sequence of bytes)
• java.io.FileOutputStream is a subclass of
OutputStream that let you write data to a file
(as a sequence of bytes)
• Both classes have constructors that get the
path of the file as a parameter
12- 146
Writing to a file
import java.io.*;
class GenerateDiceData {
static final int NUMBER_OF_TOSSES = 100000;
public static void main(String[] args) {
try {
OutputStream output = new FileOutputStream(“dice.dat”);
for (long i=0; i<NUMBER_OF_TOSSES; i++) {
int randomThrow = (int)(Math.random()*6)+1;
output.write(randomThrow);
}
output.close();
} catch (IOException ioe) {
System.err.println(“Couldn’t write to file”);
}
}
}
12- 147
Reading from a file
import java.io.*;
public class Count6Occurrences {
static final int LOOK_FOR = 6;
public static void main(String[] args) {
long count = 0;
try {
InputStream input = new FileInputStream(“dice.dat”);
int result;
while ((result = input.read()) != -1)
if (result == LOOK_FOR)
count++;
input.close();
System.out.println(count + “ occurrences”);
} catch (IOException ioe) {
System.err.println(“Couldn’t read from file”);
}
}}
12- 148
Downloading a file from the web
page
import java.io.*;
import java.net.URL;
// This program downloads a file from a given url
// and saves it to the local file
// Usage: java Download <url> <filename>
public class Download {
public static void main(String[] args) {
try {
download(args[0], args[1]);
} catch (ArrayIndexOutOfBoundsException aioobe) {
System.err.println(“Wrong usage.”);
} catch (IOException ioe) {
System.err.println(“Download failed”);
}
}
12- 149
Downloading a file from the web
(cont.)
// Downloads a remote file to the local disk.
// source - The url of the remote file
// filename - The name of the target file.
private static void download(String source,
String filename) throws IOException {
InputStream input =(new URL(source)).openStream();
OutputStream output=new FileOutputStream(filename);
int b;
while ((b=input.read())!=-1) {
output.write(b);
}
output.close();
}
}
12- 150
Textual vs. binary data
• We often make a distinction between textual data and
other kind of data
• We refer to files that stores text as ‘text files’ and to other
files as ‘binary files’.
• Binary files stores their information in various formats. In
order to understand the content of a binary file you need
to have a viewer that knows how to read the format the file
is written with.
• The structure of text files is more simple. It uses an
encoding that gives a numeric code for each symbol and
the text is stored as a list of numbers.
12- 151
Java & Unicode
• One of the important aspects of Java is its platform
independence
• Therefore Java uses Unicode
• However, many environments don’t support
Unicode yet but only use ASCII.
• Unicode uses two bytes per character while ASCII
uses one byte
• Java IO library overcomes this problem using
Readers and Writers that translate between internal
Unicode representation and external ASCII
representation (with local extensions).
12- 152
Writers
Writer writer = new FileWriter(“mail.txt”);
writer.write(‘a’);
writer.write(‘\u0590’); // Hebrew Aleph
97
1424
Automatic platform
dependent translation
made by the writer
standard ASCII no
conversion needed
97
97
224
224
conversion to
the platform specific
code for aleph
12- 153
Readers
Reader reader = new FileReader(“mail.txt”);
char c = reader.read(); // c = ‘\u0590’
c = reader.read();
// c = ‘a’
97
1424
Automatic platform
dependent translation
made by the reader
standard ASCII no
conversion needed
97
97
224
224
conversion from
the platform specific
code for aleph
12- 154
Readers & Writers
• java.io.Reader is an abstract class that defines a
common interface for reading textual data
• It is the counterpart of InputStream
• You can read from a reader characters in a
sequential manner. One character at a time, or
several characters at a time.
• Similarly, java.io.Writer is an abstract class that
defines a common interface for reading textual
data.
• It is the counterpart of OutputStream
12- 155
Specific readers
Reader
...
FileReader
CharArrayReader
PipedReader
StringReader
12- 156
Specific writers
Writer
...
FileWriter
CharArrayWriter
PipedWriter
StringWriter
12- 157
java.io.Reader
public abstract int read() throws IOException
Read a single character. Returns the character as an int
or -1 if the end of the stream was reached.
public int read(char[] buffer) throws IOException
Reads up to buffer.length characters into ‘buffer’, returns
the number of characters read.
public void close() throws IOException
Closes the reader.
• Few additional methods (look up in the API)
12- 158
java.io.Writer
public abstract void write(int c) throws IOException
Writes a single character given as an int.
public void write(char[] buffer) throws IOException
Writes a given char array.
public void close() throws IOException
Closes the writer.
• Few additional methods (look up in the API)
12- 159
ToUpper
import java.io.*;
// This class reads a text file and writes it into
// another text file after converting all letters to
// uppercase.
// Usage: java ToUpper <source> <target>
class ToUpper {
public static void main(String[] args) {
if (args.length!=2) {
System.err.println(“Invalid usage.”);
return;
}
String sourceName = args[0];
String targetName = args[1];
12- 160
ToUpper (cont.)
try {
Reader reader = new FileReader(sourceName);
Writer writer = new FileWriter(targetName);
int c;
while ((c=reader.read())!=-1) {
c = Character.toUpperCase((char)c);
writer.write(c);
}
write.close(); //very important !!!
} catch (IOException ioe) {
System.err.println(“Copying failed.”);
}
}
}
12- 161
Reading “non-primitive” data
• The data we want to read/write usually has
more complex structure: primitive data types
other than char or short, lines, or even more
complex: tables, images,
compressed/encrypted data...
• Basic solution: Extend existing input or
output streams
– Provide methods for handling the non-primitive
data
12- 162
Reading a Short
public class ShortInputStream extends
SomeInputStream{
// ...
public short readShort() throws EOFException {
int hi,low;
if ((hi = this.read()) == -1)
throw new EOFException();
if ((low = this.read()) == -1)
throw new EOFException();
return (short)(hi << 8 | low );
}
}
12- 163
Reading a Line
public class LineReader extends SomeReader {
// ...
public String readLine() throws EOFException {
StringBuffer line = new StringBuffer();int c;
while ((c = this.read())!=-1) {
if (c!=‘\n’)
line.append((char)c);
else
return line.toString();
}
if (line.equals(“”))
throw new EOFException();
}
}
12- 164
Design Problem
• There are many enhancements for reading/writing data
– Reading complex types of data (lines, objects, ints)
– Buffering
– “pushing back” something that was already read
• There are many types of input/output streams
• If we would include all enhancements in all types of
streams we will end up with a lot of duplicated code and it
would be hard to add new enhancements or new types of
streams.
• We usually don’t need all combinations at once
12- 165
Solution - Decorator Pattern
• Use a “decorator”: a class that is derived from Reader, and
has another Reader object as a member (received by the
constructor of the new class).
• All Reader methods are “forwarded” to the inner Reader
object.
• New attributes (methods) use the inner Reader object as well.
• We gain two things: The “old” interface is preserved, and we
can “chain” several functionalities.
• Same solution concept for Writer, InputStream and
OutputStream.
• In Java, “decorators” are called “Filters”, and the base class
for adding attributes is FilterXXX.
12- 166
Example: BufferedReader
BufferedReader
BufferedReader
(Reader r)
readLine()
read()
...
...
Reader
read()
...
...
12- 167
Example: DataInputStream
DataInputStream
readShort()
read()
...
...
InputStream
read()
...
...
12- 168
Printing a text file
public class type {
public static void main(String[] args) {
try {
BufferedReader reader =
new BufferedReader(new FileReader(args[0]));
String line;
while ((line=reader.readLine())!=null)
System.out.println(line);
} catch (IOException ioe) {
System.err.println(“Reading failed.”);
}
}
}
12- 169
Filters in java.io.*
• DataInputStream & DataOutputStream
– Read and write all primitive Java data types
• ObjectInputStream & ObjectOutputStream
– Read and write full objects
– Objects must be “Serializable”
• BufferedReader/Writer/InputStream/OutputStream
– Provide buffering
– BufferedReader/Writer allow also reading complete lines
• LineNumberReader & LineNumberInputStream
– Allow access to input line numbers
12- 170
Example: Chaining Decorators
try {
DataInputStream input = new DataInputStream(
new BufferedInputStream(
new FileInputStream(args[0])));
} catch (FileNotFoundException fnfe) {
// ...
}
read()
Data
read()
Buffered
read()
File
readShort()
12- 171
InputStreamReader
• InputStreamReader bridges InputStream
and Reader classes:
URL url = new URL(“...“);
BufferedReader reader =
new BufferedReader(
new InputStreamReader(url.openStream()));
String line;
while ((line = reader.readLine())!=null) {
System.out.println(line);
}
12- 172