Post on 18-Dec-2015
transcript
Introduction to Computer Science
• Packages• Polymorphism• Interfaces• Exceptions• Streams – input/output
Unit 12Unit 12
12- 2
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- 3
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- 4
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- 5
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- 6
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- 7
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- 8
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- 9
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- 10
Classes in Different Packages
• Classes in different packages obviously have different fully-qualified names
• Classes in different packages also have different rules regarding the visibility of names
12- 11
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- 12
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- 13
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- 14
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- 15
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- 16
Summary of Visibility
Visibility public default protected private
clients in D D D nonesame package
clients in D none none nonedifferent package
subclass in D & I D & I D & I nonesame package
subclass in D & I none I nonedifferent package
I = inherited access, D = direct access
12- 17
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)
class PreciseTime extends Time {…
public void 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”+ _minute);else System.out.print(“:” + _minute);if (_second < 10) System.out.print(“:0”+ _second);else System.out.print(“:” + _second);
if (_hour < 12) System.out.print(“AM”);else System.out.print(“PM”);
}}
}
Now we overrideprintTime( )
12- 19
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- 20
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- 21
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- 22
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- 23
super( )
• Therefore, if a superclass doesn't have a zero-argument constructor, the subclass must explicitly call the superclass's constructor with arguments:
class C extends B {…public C (…) {
super( B's constructor arguments );
…}
}
12- 24
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- 25
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- 26
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- 27
This is legal, blurring the distinction of Time and PreciseTime
• 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)
Time dawn;dawn = new PreciseTime(3, 45, 30);
12- 29
This is legal, blurring the distinction of Time and PreciseTime
Time dawn;dawn = new PreciseTime(3, 45, 30);
dawn
dawnAttributes: _hour = 3 _minute = 45 _second = 30Methods: …
heap
12- 30
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- 31
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- 32
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- 33
Dynamic Binding
• The actual creation of the object (C or D) only occursat runtime
• Therefore, the compilercan't know, when the object newObj is sent f ( ), whether it will be handled by the C definition or the D definition; we can only know at runtime
if (x == 7) newObj = new C( );else newObj = new D( );
newObj.f( );
Using f( ) from class C or D?
x might come from the user
12- 34
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- 35
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- 36
Array of Animals
• Fill an array with Bird, Dog, Fish – but the array is an array of Animal
Animal
Bird Dog Fish
[0] [1] [2]
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
extendsextends extends
12- 37
PolymorphismPolymorphism
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- 38
PolymorphismPolymorphism (cont’d) (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- 39
PolymorphismPolymorphism
public class Driver { public static void main (String[ ] argv) { Animal[ ] animalArray = new Animal[3]; int index;
animalArray[0] = new Bird( ); animalArray[1] = new Dog( ); animalArray[2] = new Fish( ); for (index = 0; index < animalArray.length; index++) { animalArray[index].makeNoise( ); } // of for } // of main} // of Driver
the Animal class has makeNoise, so any member of the array can makeNoise
Output: Tweet tweet flap flap Sniff sniff woof woof Glug glug gurgle gurgle
12- 40
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- 41
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- 42
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 } // main} // Driver2
Casting with PolymorphismCasting with Polymorphism
We cast before calling bark()because only dogs can bark. Not all Animals can execute the method
12- 43
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- 44
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- 45
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 compile-time and run-time type checking.
12- 46
Why is Casting Necessary Here?
Sourcecode
CompileBytecode
JVMInterpreter
Programruns
errors errors
Compile-time Errors:
• Those that are discernable without the program executing.
• Question of language legality: "Is this a legal statement?" e.g., index = strName;
Statement is not legal.
Run-time Errors:
• Those that are discernable only when the program is running with actual data values.
• Question of execution legality: "Is it legal for this variable to have the actual value assigned to it?", e.g.,
animalArray[<badIndex>] = someAnimal
Statement legal, but particular index value isn’t.
12- 47
Why is Casting Necessary Here?
if (animalArray[i]instanceof Dog) {
animalArray[i].bark();}
if (animalArray[i] instanceof Dog) { d = (Dog) animalArray[i]; d.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 bothperformance and correctness.
• 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- 48
How Objects Are CreatedDog d = new Dog();
An implicit super() calls parent class constructor first.After all, a Dog is-a Animal, && is-a Object
d
Animal
Dog
Object
d
Animal
Dog
Object
d
Animal
Dog
Object
1.1.1.1. 2.2.2.2. 3.3.3.3.
Execution Time
12- 49
Multiple References to Different Types of the Same Instance
a
Animal
Dog
Object
Animal a = new Dog(); Object o = a;
a
Animal
Dog
Objecto
We can create new references that point to different types in the same block of memory.
12- 50
Dynamic Binding
a
Animal
Dog
Objecto
System.out.println(o.toString());
.toString()
.toString()
.toString()
Dynamic binding provides runtime resolution to themost specific implementation possible.
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’.
12- 51
Casting and Polymorphism
o.doYourThing(); // ERROR!
The calling type must have the method, either inits instance, or from its parent.
a
Animal
Dog
Objecto
.doYourThing()
.doYourThing()
No MethodNo Method 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.
12- 52
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.
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?
ObjectObjecttoString()
AnimalAnimalint numLegs = 2String strTypetoString();move();
BirdBirdmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 0String strTypetoString();move();
FishFishmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 3String strTypetoString();move();
DogDogmove();bark();
12- 53
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().
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?
ObjectObjecttoString()
AnimalAnimalint numLegs = 2String strTypetoString();move();
BirdBirdmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 0String strTypetoString();move();
FishFishmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 3String strTypetoString();move();
DogDogmove();bark();
12- 54
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.
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?
ObjectObjecttoString()
AnimalAnimalint numLegs = 2String strTypetoString();move();
BirdBirdmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 0String strTypetoString();move();
FishFishmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 3String strTypetoString();move();
DogDogmove();bark();
12- 55
Multiple References to Instance
ObjectObjecttoString()
AnimalAnimalint numLegs = 2String strTypetoString();move();
BirdBirdmove();
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.
Bird bTemp = new Bird();Object oTemp = (Object) bTemp;Animal aTemp = (Animal) bTemp;
aTemp bTempoTemp
Here, the castingis not needed since we areupcastingupcasting.
It’s shown to be explicit.
12- 56
Array Elements are of a Single Type
ObjectObjecttoString()
AnimalAnimalint numLegs = 2String strTypetoString();move();
BirdBirdmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 0String strTypetoString();move();
FishFishmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 3String strTypetoString();move();
DogDogmove();bark();
Animal [ ]Animal [ ]
final int length = 3
ObjectObject
toString();
[ 0 ] [ 1 ] [ 2 ]
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.
Let’s invoke some methods on these objects.
ObjectObjecttoString()
AnimalAnimalint numLegs = 2String strTypetoString();move();
BirdBirdmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 0String strTypetoString();move();
FishFishmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 3String strTypetoString();move();
DogDogmove();bark();
Animal [ ]Animal [ ]
final int length = 3
ObjectObjecttoString();
Is our picture correct?
What if we executed this code:
Object oTemp;oTemp = animalArray[1];
oTemp
No. The codeNo. The codeworks. But our drawing is works. But our drawing is
pointing to the wrongpointing to the wrongpart of our objectpart of our object
Object
ObjectObjecttoString()
AnimalAnimalint numLegs = 2String strTypetoString();move();
BirdBirdmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 0String strTypetoString();move();
FishFishmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 3String strTypetoString();move();
DogDogmove();bark();
Animal [ ]Animal [ ]
final int length = 3
ObjectObjecttoString();
Is our picture correct?
What if we executed this code:
Object oTemp;oTemp = animalArray[1];
oTemp
Much better. ThisMuch better. Thisfussiness will payfussiness will pay
off shortly.off shortly.
ObjectObjecttoString()
AnimalAnimalint numLegs = 2String strTypetoString();move();
BirdBirdmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 0String strTypetoString();move();
FishFishmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 3String strTypetoString();move();
DogDogmove();bark();
Animal [ ]Animal [ ]
final int length = 3
ObjectObjecttoString();
Now, let’s add another line of code:
Object oTemp;oTemp = animalArray[1];oTemp.move();
oTemp
Does this work?
NO. The class Object
has no method called move()
ObjectObjecttoString()
AnimalAnimalint numLegs = 2String strTypetoString();move();
BirdBirdmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 0String strTypetoString();move();
FishFishmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 3String strTypetoString();move();
DogDogmove();bark();
Animal [ ]Animal [ ]
final int length = 3
ObjectObjecttoString();
The fix is in:
Object oTemp;oTemp = animalArray[1];Animal aTemp = (Animal) oTemp;
oTemp
aTemp
Note the explicitdown castingdown casting
was necessary.
ObjectObjecttoString()
AnimalAnimalint numLegs = 2String strTypetoString();move();
BirdBirdmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 0String strTypetoString();move();
FishFishmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 3String strTypetoString();move();
DogDogmove();bark();
Animal [ ]Animal [ ]
final int length = 3
ObjectObjecttoString();
The fix is in:
Object oTemp;oTemp = animalArray[1];Animal aTemp = (Animal) oTemp;aTemp.move();
oTemp
aTemp
Hmm... Let’s look atthis closely.
ObjectObjecttoString()
AnimalAnimalint numLegs = 2String strTypetoString();move();
BirdBirdmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 0String strTypetoString();move();
FishFishmove();
ObjectObjecttoString()
AnimalAnimalint numLegs = 3String strTypetoString();move();
DogDogmove();bark();
Animal [ ]Animal [ ]
final int length = 3
ObjectObjecttoString();
Object oTemp;oTemp = animalArray[1];Animal aTemp = (Animal) oTemp;aTemp.move();
oTemp
aTemp
ObjectObjecttoString()
FishFishmove();
AnimalAnimalint numLegs = 3String strTypetoString();move();
It looks like bothAnimal and Fishhave move( ) methods.
Which one gets called when the aTemp.move( ) line executes?
The reference typewe are using is an
Animal type. Would thatdetermine whether Animal
or Fish has their method called?
12- 63
Dynamic Binding
ObjectObjecttoString()
FishFishmove();
AnimalAnimalint numLegs = 3String strTypetoString();move();
Object oTemp;oTemp = animalArray[1];Animal aTemp = (Animal) oTemp;aTemp.move();
aTemp
Here, the principle of dynamic bindingdynamic 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.
Understand this term.Understand this term.Understand what is does.Understand what is does.
It is a It is a CORECORE feature of any Object feature of any Object
Oriented language.Oriented language.
12- 64
Sanity Check
ObjectObjecttoString()
FishFishmove();
AnimalAnimalint numLegs = 3String strTypetoString();move();
Object oTemp;oTemp = animalArray[1];Animal aTemp = (Animal) oTemp;System.out.println (oTemp.toString());
oTemp
What about:
System.out.println ( ((Object)oTemp).toString() );
What Happens Here?
Does castingsomehowoverpowerdynamicbinding?
12- 65
Sanity Check
ObjectObjecttoString()
FishFishmove();
AnimalAnimalint numLegs = 3String strTypetoString();move();
oTemp
System.out.println ( ((Object)oTemp).toString( ) );
What Happens Here?
No matterNo matterhow youhow you
cast things,cast things,dynamicdynamic
binding takesbinding takeshold. It’shold. It’slike the like the
law of gravitylaw of gravity..
Object oTemp;oTemp = animalArray[1];Animal aTemp = (Animal) oTemp;System.out.println (oTemp.toString());
What about:
12- 66
Sanity Check
ObjectObjecttoString()
FishFish
move();toString();
AnimalAnimalint numLegs = 3String strTypetoString();move();
oTemp
What if Fish had its owntoString()?
No matterNo matterhow youhow you
cast things,cast things,dynamicdynamic
binding takesbinding takeshold. It’shold. It’slike the like the
law of gravity.law of gravity.
Dynamic binding will always resolve, at run time, to themost specific version of the method. ALWAYS.ALWAYS.
Object oTemp;oTemp = animalArray[1];Animal aTemp = (Animal) oTemp;System.out.println (oTemp.toString());
12- 67
“Always?”
ObjectObjecttoString()
FishFish
move();toString();
AnimalAnimalint numLegs = 3String strTypetoString();move();
Object oTemp;oTemp = animalArray[1];oTemp.move(); // WRONG!
oTemp
Does dynamic bindingalso work miracles?
That is, does it letyou find methods in
extending classes, if thepresent class does nothave such a method?
NO. This would cause a compile time error. Java is strongly typedstrongly 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 dynamic binding does not defeat type safety in Java.does not defeat type safety in Java.
No suchmethod move()
in Object
12- 68
Another example –A Hierarchy Diagram
File
RestrictedFile
Object
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)
Has methods:public boolean isOpen()public void open()public void close()public String getName()
Has method (among others):public String toString()
12- 69
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- 70
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.
• But a RestrictedFile is also a File, so f can also refer to a RestrictedFile object.
• The type of the reference we use determines the point of view we will have on the object.
File f = new File(“story.txt”);
File f = new RestrictedFile(“visa.dat”, 12345);
12- 71
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- 72
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- 73
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- 74
Points of View
RestrictedFile
... isOpen isLocked key
toString() ... isOpen() open() close() lock() unlock(key) isLocked()
12- 75
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
• The type of the values held may change during the running of the algorithm and is not known during compile time
• The run-time type is always some subclass of the compile-time type.
f = new RestrictedFile(“visa.dat”,12345);
f = new File(“visa.dat”);
12- 76
RestrictedFile referenceRestrictedFile point of view
File referenceFile point of view
Widening
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);
12- 77
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- 78
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- 79
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- 80
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- 81
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- 82
Another Example:Mouse in a Maze
public class Mouse {private instance variablespublic 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- 83
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- 84
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- 85
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- 86
abstract Class, subclassed
protected boolean _started;protected int _direction; etc.
public abstract void makeMove( ); etc.protected boolean facingWall( ) { return theMaze.checkWall
(_direction, location); }
abstract class Mouse
extends extends
public RightMouse(…) {…}
public void makeMove( ) {…}
RightMouse
public StraightMouse(…) {…}
public void makeMove( ) {…}
StraightMouse
12- 87
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 enteredprotected Point _location; //location of this mouseprotected int _direction; //direction mouse is facing
public Point tellLocation( ) { return _location; }public int tellDirection( ) { return _direction; }
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;
}}
12- 90
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- 91
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- 92
Dynamic Generationof 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- 93
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- 94
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- 95
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- 96
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- 97
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- 98
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 Bimplements I1, I2 { … }
12- 99
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 Mazeimplements Direction { … }
12- 100
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- 101
interface Imposing a Requirement on Classes
double apply(double x);
interface Function
interface
implements implements
…
double apply(double x ) {…}…
SineFunction EmpiricalFunction
…
double apply(double x ) {…}…
12- 102
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- 103
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- 104
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- 105
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- 106
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- 107
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- 108
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- 109
Exceptions in Java
• Errors and Runtime exceptions will usually cause the program to crash
• Checked exceptions should usually be handled by the programmer
12- 110
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- 112
Runtime exceptions in the Java API
• java.lang.ArithmeticException
• java.lang.NullPointerException
• java.lang.IllegalArgumentException
• java.lang.NegativeArraySizeException
• java.lang.ArrayIndexOutOfBoundsException
• java.lang.ClassCastException
12- 113
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.)
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
}
12- 115
How are throws caught? Recall the runtime stack, and method calls
Method e( )Where we came from: main, line 4
Method main( )
STACK
Method f( )Where we came from: e, line 3
Method g( )Where we came from: f, line 4
top
void g ( ) { System.out.println(“A!”); System.out.println(“B!”); … System.out.println(“C!”); System.out.println(“D!”);}
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 e ( ) {......obj.f( );...}
main (String[ ] args) {.........obj.e();...}
12- 116
throws are handled upthe 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
void g ( ) { System.out.println(“A!”); System.out.println(“B!”); … System.out.println(“C!”); System.out.println(“D!”);}
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 e ( ) {......obj.f( );...}
main (String[ ] args) {.........obj.e();...}
12- 117
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- 118
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- 119
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- 120
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- 121
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- 122
class FileNotFoundException
package java.io;public class FileNotFoundException
extends IOException {
public FileNotFoundException( ) { super( ); }
public FileNotFoundException(String s) {super(s);
}}
12- 123
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- 124
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- 125
GetOuttaHereException definition
public class GetOuttaHereExceptionextends Exception {
public GetOuttaHereException( ) { super( ); }
public GetOuttaHereException(String s) {super(s);
}}
12- 126
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- 127
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- 128
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- 130
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- 131
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- 132
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- 133
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- 134
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- 136
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- 137
IO Streams
12 72 32 17 83 11 7 91 108
43 55 31 37 34 13 17 1 15
Input stream
Output stream
reading direction
writing direction
12- 138
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- 139
Specific input streams
InputStream
ByteArrayInputStream
FileInputStream PipedInputStream
. . .
12- 140
Class InputStream
• Class java.io.InputStream defines several methods that support the abstraction of allowing sequential reading from a stream:
Reads the next byte from the stream. Return -1 if the end of the stream was reached.
Reads up to b.length bytes from the stream into the array b. Returns the number of bytes that were read.
public abstract int read() throws IOException
public int read(byte[] b) throws IOException
12- 141
Input streams
Reads up to length bytes from the stream into the array ‘b’ from the index ‘offset’. Returns the number of bytes that were read.
Closes this input stream and releases any system resources associated with the stream.
• Few additional methods (look up in the API)
public int read(byte[] b, int offset, int length)
throws IOException
public void close() throws IOException
12- 142
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- 143
Specific output streams
OutputStream
ByteArrayOutputStream
FileOutputStream PipedOutputStream
. . .
12- 144
Class OutputStream
• Class java.io.OutputStream defines several methods that support the abstraction of allowing sequential writing to a stream:
Writes the specified byte (given as an int) to this output stream.
Writes b.length bytes from the specified byte array to
this output stream.
public abstract void write(int b)
throws IOException
public void write(byte[] b) throws IOException
12- 145
Input streams
Writes length bytes from the specified byte array starting at offset off to this output stream.
Closes this output stream and releases any system
resources associated with the stream.
• Few additional methods (look up in the API)
public void write(byte[] b, int offset,
int length) throws IOException
public void close() throws IOException
12- 146
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- 147
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- 148
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- 149
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- 150
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- 151
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- 152
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- 153
Writers
Writer writer = new FileWriter(“mail.txt”);
writer.write(‘a’);
writer.write(‘\u0590’); // Hebrew Aleph
Automatic platform
dependent translation
made by the writer
97
97
1424
224
97 224
conversion to
the platform specific
code for aleph
standard ASCII no
conversion needed
12- 154
Readers
Reader reader = new FileReader(“mail.txt”);
char c = reader.read(); // c = ‘\u0590’
c = reader.read(); // c = ‘a’
Automatic platform
dependent translation
made by the reader
97
97
1424
224
97 224
conversion from
the platform specific
code for aleph
standard ASCII no
conversion needed
12- 155
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- 158
java.io.Reader
Read a single character. Returns the character as an int or -1 if the end of the stream was reached.
Reads up to buffer.length characters into ‘buffer’, returns the number of characters read.
Closes the reader.
• Few additional methods (look up in the API)
public abstract int read() throws IOException
public int read(char[] buffer) throws IOException
public void close() throws IOException
12- 159
java.io.Writer
Writes a single character given as an int.
Writes a given char array.
Closes the writer.
• Few additional methods (look up in the API)
public abstract void write(int c) throws IOException
public void write(char[] buffer) throws IOException
public void close() throws IOException
12- 160
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- 161
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- 162
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- 163
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 );
}
}
Reading a Short
12- 164
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- 165
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- 166
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- 167
Example: BufferedReader
Reader
read()
...
...
BufferedReader
readLine()
BufferedReader
(Reader r)
read()
...
...
12- 168
Example: DataInputStream
InputStream
read()
...
...
DataInputStream
readShort()
read()
...
...
12- 169
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- 170
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- 171
Example: Chaining Decorators
readShort()
read() read() read()
BufferedDataFile
try {
DataInputStream input = new DataInputStream(
new BufferedInputStream(
new FileInputStream(args[0])));
} catch (FileNotFoundException fnfe) {
// ...
}