introduction to computer science packages polymorphism interfaces exceptions streams –...

of 172 /172
Introduction to Computer Science Packages Polymorphism Interfaces Exceptions Streams – input/output Unit 12

Author: ruth-tate

Post on 18-Dec-2015

221 views

Category:

Documents


4 download

Embed Size (px)

TRANSCRIPT

  • Slide 1
  • Introduction to Computer Science Packages Polymorphism Interfaces Exceptions Streams input/output Unit 12
  • Slide 2
  • 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)
  • Slide 3
  • 12- 3 Sample Packages that come with the Java API (continually evolving) java.appletClasses for implementing applets java.awtFor graphics, windows, GUIs java.awt.eventFor AWT event-handling model java.awt.imageClasses for image processing java.awt.peerInterface defs, platform-indep. GUIs java.ioClasses for input and output java.lang Basic language classes (String, Math) java.netClasses for networking java.utilUseful auxiliary classes, like Date
  • Slide 4
  • 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);
  • Slide 5
  • 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.*;
  • Slide 6
  • 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
  • Slide 7
  • 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( );
  • Slide 8
  • 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
  • Slide 9
  • 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;
  • Slide 10
  • 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
  • Slide 11
  • 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
  • Slide 12
  • 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
  • Slide 13
  • 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
  • Slide 14
  • 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
  • Slide 15
  • 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 }
  • Slide 16
  • 12- 16 Summary of Visibility Visibility publicdefaultprotectedprivate clients in D D Dnone same package clients in Dnone nonenone different package subclass in D & ID & I D & Inone same package subclass in D & Inone Inone different package I = inherited access, D = direct access
  • Slide 17
  • 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)
  • Slide 18
  • 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); elseSystem.out.print(PM); } } } Now we override printTime( )
  • Slide 19
  • 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
  • Slide 20
  • 12- 20 Constructors for Subclasses Java guarantees that a classs 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
  • Slide 21
  • 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,)
  • Slide 22
  • 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
  • Slide 23
  • 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 ); } }
  • Slide 24
  • 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; }
  • Slide 25
  • 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
  • Slide 26
  • 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
  • Slide 27
  • 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);
  • Slide 28
  • 12- 28 There's an order to this Time dawn; dawn heap
  • Slide 29
  • 12- 29 This is legal, blurring the distinction of Time and PreciseTime Time dawn; dawn = new PreciseTime(3, 45, 30); dawn Attributes: _hour = 3 _minute = 45 _second = 30 Methods: heap
  • Slide 30
  • 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
  • Slide 31
  • 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
  • Slide 32
  • 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
  • Slide 33
  • 12- 33 Dynamic Binding The actual creation of the object (C or D) only occurs at runtime Therefore, the compiler can'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
  • Slide 34
  • 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, wed 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
  • Slide 35
  • 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 wed like to process through the array and have each element invoke a makeNoise() method. Luckily when a method call is made, the compiler isnt too concerned about the specifics of the method being called. Its question is: is there a method with a matching signature?
  • Slide 36
  • 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 extends
  • Slide 37
  • 12- 37 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
  • Slide 38
  • 12- 38 Polymorphism (contd) 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
  • Slide 39
  • 12- 39 Polymorphism 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
  • Slide 40
  • 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: cant substitute superclass for a subclass, e.g., CANNOT substitute an animal for a bird. An animal is a bird? No. Not necessarily.
  • Slide 41
  • 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) Its a boolean relation, returning true or false: if (d instanceof Dog) { }
  • Slide 42
  • 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 Polymorphism We cast before calling bark() because only dogs can bark. Not all Animals can execute the method
  • Slide 43
  • 12- 43 Upcasting Why didnt 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)
  • Slide 44
  • 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( ); }
  • Slide 45
  • 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 cant Java do it for us automatically? Answer: the difference between compile- time and run-time type checking.
  • Slide 46
  • 12- 46 Why is Casting Necessary Here? Source code Compile Byte code JVM Interpreter Program runs 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[ ] = someAnimal Statement legal, but particular index value isnt.
  • Slide 47
  • 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 isnt (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. 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.
  • Slide 48
  • 12- 48 How Objects Are Created Dog 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. 2.2.3.3. Execution Time
  • Slide 49
  • 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 Object o We can create new references that point to different types in the same block of memory.
  • Slide 50
  • 12- 50 Dynamic Binding a Animal Dog Object o System.out.println(o.toString());.toString() Dynamic binding provides runtime resolution to the most 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. Thats dynamic binding.
  • Slide 51
  • 12- 51 Casting and Polymorphism o.doYourThing(); // ERROR! The calling type must have the method, either in its instance, or from its parent. a Animal Dog Object o.doYourThing() No 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.
  • Slide 52
  • 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?Object toString() Animal int numLegs = 2 String strType toString(); move(); Bird Object toString() Animal int numLegs = 0 String strType toString(); move(); Fish Object toString() Animal int numLegs = 3 String strType toString(); move(); Dog bark();
  • Slide 53
  • 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?Object toString() Animal int numLegs = 2 String strType toString(); move(); Bird Object toString() Animal int numLegs = 0 String strType toString(); move(); Fish Object toString() Animal int numLegs = 3 String strType toString(); move(); Dog bark();
  • Slide 54
  • 12- 54 So we select Animal as our common type. Its 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?Object toString() Animal int numLegs = 2 String strType toString(); move(); Bird Object toString() Animal int numLegs = 0 String strType toString(); move(); Fish Object toString() Animal int numLegs = 3 String strType toString(); move(); Dog bark();
  • Slide 55
  • 12- 55 Multiple References to InstanceObject toString() Animal int numLegs = 2 String strType toString(); move(); Bird 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; aTempbTempoTemp Here, the casting is not needed since we are upcasting upcasting. Its shown to be explicit.
  • Slide 56
  • 12- 56 Array Elements are of a Single TypeObject toString() Animal int numLegs = 2 String strType toString(); move(); Bird Object toString() Animal int numLegs = 0 String strType toString(); move(); Fish Object toString() Animal int numLegs = 3 String strType toString(); move(); Dog bark(); Animal [ ] final int length = 3 Object 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. Lets invoke some methods on these objects.
  • Slide 57
  • Object toString() Animal int numLegs = 2 String strType toString(); move(); Bird Object toString() Animal int numLegs = 0 String strType toString(); move(); Fish Object toString() Animal int numLegs = 3 String strType toString(); move(); Dog bark(); Animal [ ] final int length = 3 Object toString(); Is our picture correct? What if we executed this code: Object oTemp; oTemp = animalArray[1]; oTemp No. The code works. But our drawing is pointing to the wrong part of our object Object
  • Slide 58
  • Object toString() Animal int numLegs = 2 String strType toString(); move(); Bird Object toString() Animal int numLegs = 0 String strType toString(); move(); Fish Object toString() Animal int numLegs = 3 String strType toString(); move(); Dog bark(); Animal [ ] final int length = 3 Object toString(); Is our picture correct? What if we executed this code: Object oTemp; oTemp = animalArray[1]; oTemp Much better. This fussiness will pay off shortly.
  • Slide 59
  • Object toString() Animal int numLegs = 2 String strType toString(); move(); Bird Object toString() Animal int numLegs = 0 String strType toString(); move(); Fish Object toString() Animal int numLegs = 3 String strType toString(); move(); Dog bark(); Animal [ ] final int length = 3 Object toString(); Now, lets 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()
  • Slide 60
  • Object toString() Animal int numLegs = 2 String strType toString(); move(); Bird Object toString() Animal int numLegs = 0 String strType toString(); move(); Fish Object toString() Animal int numLegs = 3 String strType toString(); move(); Dog bark(); Animal [ ] final int length = 3 Object toString(); The fix is in: Object oTemp; oTemp = animalArray[1]; Animal aTemp = (Animal) oTemp; oTemp aTemp Note the explicit down casting was necessary.
  • Slide 61
  • Object toString() Animal int numLegs = 2 String strType toString(); move(); Bird Object toString() Animal int numLegs = 0 String strType toString(); move(); Fish Object toString() Animal int numLegs = 3 String strType toString(); move(); Dog bark(); Animal [ ] final int length = 3 Object toString(); The fix is in: Object oTemp; oTemp = animalArray[1]; Animal aTemp = (Animal) oTemp; aTemp.move(); oTemp aTemp Hmm... Lets look at this closely.
  • Slide 62
  • Object toString() Animal int numLegs = 2 String strType toString(); move(); Bird Object toString() Animal int numLegs = 0 String strType toString(); move(); Fish Object toString() Animal int numLegs = 3 String strType toString(); move(); Dog bark(); Animal [ ] final int length = 3 Object toString(); Object oTemp; oTemp = animalArray[1]; Animal aTemp = (Animal) oTemp; aTemp.move(); oTemp aTemp Object toString() Fish move(); Animal int numLegs = 3 String strType toString(); move(); It looks like both Animal and Fish have move( ) methods. Which one gets called when the aTemp.move( ) line executes? The reference type we are using is an Animal type. Would that determine whether Animal or Fish has their method called?
  • Slide 63
  • 12- 63 Dynamic Binding Object toString() Fish move(); Animal int numLegs = 3 String strType toString(); move(); Object oTemp; oTemp = animalArray[1]; Animal aTemp = (Animal) oTemp; aTemp.move(); aTemp dynamic binding 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. Understand this term. Understand what is does. It is a CORE feature of any Object Oriented language.
  • Slide 64
  • 12- 64 Sanity Check Object toString() Fish move(); Animal int numLegs = 3 String strType toString(); 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 casting somehow overpower dynamic binding?
  • Slide 65
  • 12- 65 Sanity Check Object toString() Fish move(); Animal int numLegs = 3 String strType toString(); move(); oTemp System.out.println ( ((Object)oTemp).toString( ) ); What Happens Here? No matter how you cast things, dynamic binding takes hold. Its like the law of gravity. Object oTemp; oTemp = animalArray[1]; Animal aTemp = (Animal) oTemp; System.out.println (oTemp.toString()); What about:
  • Slide 66
  • 12- 66 Sanity Check Object toString() Fish move(); toString(); Animal int numLegs = 3 String strType toString(); move(); oTemp What if Fish had its own toString()? No matter how you cast things, dynamic binding takes hold. Its like the law of gravity. Dynamic binding will always resolve, at run time, to the ALWAYS. most specific version of the method. ALWAYS. Object oTemp; oTemp = animalArray[1]; Animal aTemp = (Animal) oTemp; System.out.println (oTemp.toString());
  • Slide 67
  • 12- 67 Always? Object toString() Fish move(); toString(); Animal int numLegs = 3 String strType toString(); move(); Object oTemp; oTemp = animalArray[1]; oTemp.move(); // WRONG! oTemp 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? strongly typed dynamic binding does not defeat type safety in Java. 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. No such method move() in Object
  • Slide 68
  • 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; its locked at creation) Has methods: public boolean isOpen() public void open() public void close() public String getName() Has method (among others): public String toString()
  • Slide 69
  • 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.
  • Slide 70
  • 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);
  • Slide 71
  • 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();
  • Slide 72
  • 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(); //Cant use this method f.unlock(12345); //Cant use this method String s = f.toString();
  • Slide 73
  • 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(); //Cant use this method f.lock(); //Cant use this method f.unlock(12345); //Cant use this method String s = f.toString();
  • Slide 74
  • 12- 74 Points of View RestrictedFile ... isOpen isLocked key toString() ... isOpen() open() close() lock() unlock(key) isLocked()
  • Slide 75
  • 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);
  • Slide 76
  • 12- 76 RestrictedFile reference RestrictedFile point of view File reference File point of view 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);
  • Slide 77
  • 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 }
  • Slide 78
  • 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 }
  • Slide 79
  • 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);
  • Slide 80
  • 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.
  • Slide 81
  • 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?
  • Slide 82
  • 12- 82 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 ( ) { } }
  • Slide 83
  • 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
  • Slide 84
  • 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
  • Slide 85
  • 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
  • Slide 86
  • 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 public RightMouse() {} public void makeMove( ) {} RightMouse public StraightMouse() {} public void makeMove( ) {} StraightMouse
  • Slide 87
  • 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 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; }
  • Slide 88
  • 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); }
  • Slide 89
  • 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; } }
  • Slide 90
  • 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; } } }
  • Slide 91
  • 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; } } }
  • Slide 92
  • 12- 92 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
  • Slide 93
  • 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); } } }
  • Slide 94
  • 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
  • Slide 95
  • 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
  • Slide 96
  • 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
  • Slide 97
  • 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
  • Slide 98
  • 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 B implements I1, I2 { }
  • Slide 99
  • 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 Maze implements Direction { }
  • Slide 100
  • 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
  • Slide 101
  • 12- 101 interface Imposing a Requirement on Classes double apply(double x); interface Function interface implements double apply(double x ) {} SineFunctionEmpiricalFunction double apply(double x ) {}
  • Slide 102
  • 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
  • Slide 103
  • 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) { } }
  • Slide 104
  • 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));
  • Slide 105
  • 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
  • Slide 106
  • 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
  • Slide 107
  • 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
  • Slide 108
  • 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
  • Slide 109
  • 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
  • Slide 110
  • 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