Java程序辅导

C C++ Java Python Processing编程在线培训 程序编写 软件开发 视频讲解

客服在线QQ:2653320439 微信:ittutor Email:itutor@qq.com
wx: cjtutor
QQ: 2653320439
Lab 6 | CS 61BL Summer 2015 Main Course Info Staff Assignments Resources Piazza Lab 6: Inheritance, Interfaces, and Abstract Classes Table of Contents A. Intro Learning Goals B. Inheritance Review of Inheritance from CS 61A Inheritance Terminology Exercise: Extending the Counter Class Exercise: Private Fields and Inheritance Exercise: Extending the Point Class A Note About the TracedPoint Constructor Reminder: Another way to use super C. Static and Dynamic Type Introduction to Polymorphism Polymorphic Data Structures A Problem A Solution? Polymorphic Method Selection Static and Dynamic Type What the Compiler Does What Happens at Run Time Self-test: Identify Static Types Self-test: Polymorphism Puzzles Typing Summary D. Abstract Classes Motivation Abstract classes Abstract Classes in Java Libraries Abstract Dates Exercise: A nextDate Method E. Interfaces Interfaces Motivation for Interfaces Exercise: Sorting Dates F. A Better IntSequence Exercise: A Better IntSequence Exercise: One Last Step ArrayLists G. Conclusion Summary Submission Reading A. Intro Learning Goals The focus of today's lab is inheritance, a mechanism that allows a class to be defined that differs only slightly from an existing class. Inheritance provides numerous benefits. In particular, programmers can take advantage of already written correct code and avoid reinventing the wheel. A related concept is polymorphism, where a variable may store values of its subclasses. The procedure for de-tangling an instance of polymorphism can be somewhat complicated, so there are numerous exercises that provide you with practice. Inheritance can also be used to organize an already existing bunch of similar classes. From this situation emerges the concepts of abstract classes and interfaces. Both provide a way to require that certain methods be included in a given class without specifying how they are implemented. Later, the fully implemented methods can be called "under the table", for example to compare two elements of an array. We think this is neat. To get started , download the code for Lab 6 and create a new Eclipse project out of it. B. Inheritance Review of Inheritance from CS 61A You learned in CS 61A that a programmer can set up one class to inherit characteristics (methods and instance variables) from another. This is typically done to reuse most of an already-defined class that needs an extra method, or that requires a method to behave slightly differently. Inheritance Terminology We will refer to the inheriting class as the subclass of its parent or superclass, and say that the subclass extends the superclass. Methods in the superclass can be redefined in the subclass. This is called overriding the methods. In Java, we set up inheritance in a class's header, using the keyword extends. You may have noticed examples of its use already this semester; it looks something like this: public class SubClass extends SuperClass { ... } or public class Dog extends Animal { ... } or public class Dalmatian extends Dog { ... } Note: If a class has the keyword final in its header, then it cannot have any subclasses. Discussion: Review the Lingo Link to the discussion There was a lot of lingo on the last step. Discuss each of the following terms with your partner to make sure you both understand what they mean. Then post a definition of each in your own words to the discussion. Check out your classmates' posts to see if they match your intuition. subclass superclass extends overrides Exercise: Extending the Counter Class Here's an example of inheritance. Recall the Counter class from earlier in the course. Note: this version is slightly modified from version we used before. public class Counter { int myCount; public Counter ( ) { myCount = 0; } public void increment ( ) { myCount++; } public void reset ( ) { myCount = 0; } public int value ( ) { return myCount; } } Let's revisit the example of the mod N counter. Remember before that to create ModNCounter.java we just wrote over the file Counter.java. Another way to set up ModNCounter.java is to have it inherit from Counter.java. Write a new version of ModNCounter.java that uses inheritance. You only have to replace the constructor and one other method; all others should be inherited. Once you're done, check that you can use all the methods correctly, even ones that you never directly defined in ModNCounter. For instance: ModNCounter modCounter = new ModNCounter(3); modCounter.increment(); System.out.println(modCounter.value()); // prints 1 modCounter.reset(); modCounter.increment(); System.out.println(modCounter.value()); // still prints 1 Also check that the mod functionality works. ModNCounter modCounter = new ModNCounter(3); modCounter.increment(); modCounter.increment(); modCounter.increment(); modCounter.increment(); System.out.println(modCounter.value()); // prints 1 Exercise: Private Fields and Inheritance The Counter class we just considered was modified. The original version is below and has a private instance variable myCount. Edit your Counter.java file so that it matches the code seen below. public class Counter { private int myCount; public Counter ( ) { myCount = 0; } public void increment ( ) { myCount++; } public void reset ( ) { myCount = 0; } public int value ( ) { return myCount; } } Subclasses do not have access to the private variables of their superclasses. So, actually ModNCounter cannot have access to the private instance variable myCount. This restriction makes sense. A programmer defining a variable as private presumably intends that access to the variable be limited. However, if all you had to do to gain access to a private variable was to define a subclass of the class containing it, it would be easy to subvert the limited access. (Note: We can use the keyword protected instead of private if we want to allow subclasses to access the variables, but not allow any other classes. However, this is discouraged because of the problem described above. In general, it is good style to make your variables as restricted as possible.) Modify ModNCounter to work even when Counter's myCount variable is private. Do not create a new myCount variable in ModNCounter, or override any more than the constructor and one method. This may be a bit tricky! Hint: If a subclass overrides a method from its superclass, it can still call the original method (if it is public) by prefacing the method name with the super keyword. Exercise: Extending the Point Class We can extend classes that we haven't written ourselves — such as those in the Java API — provided they aren't declared as final. Here's an example of extending the Point class (which we worked with earlier) from the java.awt library. Some classes provide "setter" methods. Setter methods allow you to change the values of instance variables, even if they are private (because the method is public). A useful debugging aid is to override a setter method to produce informative output every time the object's state changes. The setter method for the Point class is named move; the call p.move (27, 13); changes the x coordinate to 27 and the y coordinate to 13 in the Point referenced by p. Given below is the framework for a TracedPoint class intended to intercept calls to move and print information about the pre- and post-change state of the Point along with doing the move. You are to complete and test the framework after reading a note about super in the next step. import java.awt.*; public class TracedPoint extends Point { public TracedPoint (int x, int y) { super (x, y); } // Your move method goes here. public static void main (String [ ] args) { TracedPoint p1 = new TracedPoint (5, 6); p1.move (3, 4); // prints: "point moved from (5,6) to (3,4) p1.move (9, 10); // prints: "point moved from (3,4) to (9,10) TracedPoint p2 = new TracedPoint (25, 30); p2.move (45, 50); // prints: "point moved from (25,30) to (45,50) System.out.println ("p1 is " + p1); System.out.println ("p2 is " + p2); } } A Note About the TracedPoint Constructor When constructing a subclass object, you must always construct its superclass first. In the constructor of a subclass, Java automatically supplies a call to the superclass constructor with no arguments. For example, If you write a TracedPoint constructor, it will automatically call Point(); before running the first line of the TracedPoint constructor. If you want to call a constructor of the superclass other than the no-argument constructor, use the super keyword as shown below. public class TracedPoint extends Point { public TracedPoint (int x, int y) { super (x, y); } // ... } This calls the two int constructors of Point. The super keyword must be used on the first line of the constructor. An aside: similar to how you use super, you can also use the keyword this as a constructor. this calls other constructor methods within the same class. For example, if you wanted the zero-argument constructor for TracedPoint to initialize a traced point at (0, 0), you could write: public TracedPoint(){ this(0, 0); } Reminder: Another way to use super The super keyword has another use besides for constructors. It also allows you to call superclass methods that the subclass has overriden. Use it similarly to how you would use the this keyword. this.method(); // calls the method in the current class super.method(); // calls the method in the parent class Now implement TracedPoint and take advantage of the superclass's methods and variables as much as possible rather than reinventing the wheel. C. Static and Dynamic Type Introduction to Polymorphism We saw earlier that inheritance provides a way to reuse existing classes (Counter and Point), implementing small changes in behavior by overriding existing methods in the superclass or by adding new methods in the subclass. Inheritance also, however, makes it possible for us to design general data structures and methods using polymorphism. The word "polymorphism" comes from the Greek words for "many" and "forms". In the context of object-oriented programming, it means that a given object can be regarded either as an instance of its own class, as an instance of its superclass, as an instance of its superclass's superclass, and so on up the hierarchy. In particular, where a given reference type is requested for a method argument or needed for a return type, we can supply instead an instance of any subclass of that reference type. That's because inheritance implements an "is-a" relationship: for example, a TracedPoint is a Point with some extra properties. As an example, imagine you have the following method in some class (not necessarily Point or TracedPoint): public static void moveTo79 (Point p) { p.move (7, 9); } We can call moveTo79 and pass in either a Point object or a TracedPoint object. And if we pass in a TracedPoint object, the code will use the move method that you implemented in TracedPoint! Discussion: Thinking about Polymorphism Link to the discussion Would you expect the substitution mechanism to work in reverse? For example, would the following code work? public static void anotherMoveTo79 (TracedPoint tp){ tp.move(7, 9); } ... Point p = new Point(3, 4); anotherMoveTo79(p); Briefly discuss with your partner why you would expect this to work, or not. Then try it out for yourself and see! Polymorphic Data Structures The java.util class library contains several collection classes that take advantage of polymorphism and are therefore able to store a variety of types of objects. We will examine the ArrayList class as an example. It represents an expandable array-like structure. (It's described in chapter 6 of Head First Java.) To declare an ArrayList reference, specify both the ArrayList class name and also the class of objects that the ArrayList will contain in angle brackets. For example, ArrayList values; declares a reference to an ArrayList that contains only String objects. Similarly, to construct an ArrayList object, you need to supply the element class name in angle brackets, ArrayList values = new ArrayList ( ); What happens if you don't specify the angled brackets?: ArrayList values = new ArrayList(); It turns out, this is equivalent to ArrayList. ArrayList methods include the following. // Add an object to the end of the ArrayList. // The return value is always true (and is therefore // usually ignored) since there aren't any circumstances // that the add could fail. boolean add (Object o); // Return the object at the given position in the ArrayList. Object get (int index); // Return the number of elements that have been added // to the ArrayList; similar to the myCount information in // the IntSequence class. int size ( ); // Return true if the ArrayList contains the given object, // and return false if not. boolean contains (Object o); The class Object is the root of the inheritance hierarchy—every class inherits from Object (primitives, however, do not), at least indirectly—so these operations provide a data structure that can store objects of any type. Here's an example: ArrayList a = new ArrayList ( ); a.add (new TracedPoint (5, 6)); a.add (new Point (10, 11)); a.add ("abcd"); // a String object IntSequence seq = new IntSequence (3); seq.add (5); seq.add (4); seq.add (3); a.add (seq); for (int k=0; k a = new ArrayList ( ); a.add (p); a.add (tp); // Move both points to (7, 9). for (int k=0; k a = new ArrayList ( ); a.add (new TracedPoint (5, 6)); a.add (new Point (10, 11)); a.add ("abcd"); // a String object IntSequence seq = new IntSequence (3); seq.add (5); seq.add (4); seq.add (3); a.add (seq); for (int k=0; k points = new ArrayList(); points.add(new TracedPoint(1, 2)); What is the static type of points.get(0)? Point Correct! The triangle brackets tells the ArrayList to expect objects of type Point TracedPoint Incorrect. All the compiler knows is that the ArrayList contains objects of class Point Object Incorrect. The triangle brackets tell the compiler something about what the ArrayList contains! Check Solution What is the static type of (TracedPoint)(points.get(0))? Point Incorrect. The cast temporarily changes the static type. TracedPoint Correct! That's what the cast does. Object Incorrect. Check Solution Self-test: Polymorphism Puzzles Consider the class definitions below. public class Superclass { public void print ( ) { System.out.println ("super"); } } public class Subclass extends Superclass { public void print ( ) { System.out.println ("sub"); } } Now determine whether the following program segment prints "super", prints "sub", results in a compile-time error, or results in a run-time error. Superclass obj1 = new Subclass ( ); obj1.print ( ); Choose one answer. compile-time error Incorrect. Superclass defines a method print so the compiler is satisfied run-time error Incorrect. Subclass defines a method print so nothing breaks. super Incorrect. Remember how we to determine what method is used at runtime? sub Correct! Use the dynamic type to determine which method to use. Check Solution Do the same for the following program segment. Subclass obj2 = new Superclass ( ); obj2.print ( ); Choose one answer. compile-time error Correct! The static type cannot be more specialized that the dynamic type. run-time error Incorrect. super Incorrect. sub Incorrect Check Solution Do the same for the following. Superclass obj3 = new Superclass ( ); ((Subclass) obj3).print ( ); Choose one answer. compile-time error Incorrect. Casting errors aren't caught until runtime, because a cast is telling the compiler to trust the programmer run-time error Correct! A casting error is not caught until runtime. super Incorrect. Is every Superclass object also a Subclass ? sub Incorrect. Is every Superclass object also a Subclass ? Check Solution Do the same for the following. Subclass obj4 = new Subclass ( ); ((Superclass) obj4).print ( ); Choose one answer. compile-time error Incorrect. You are allowed to cast up because casting is just changing the static type, and static type is always allowed to be more general. run-time error Incorrect. You are allowed to cast up because casting is just changing the static type, and static type is always allowed to be more general. super Incorrect. How do we choose which method to use at runtime? sub Correct! The dynamic type is still Subclass , so it calls the Subclass method. Check Solution Typing Summary Every object has a type—its dynamic type. Every container (variable, parameter, literal, return from function call, and operator expression) has a static type. Static types are "known to the compiler" because you declare them. Here's an example. int[] A = new int[2]; Object x = A; // All references are Objects A[k] = 0; // Static type of A is array... x[k+1] = 1; // But static type of x is not an array: ERROR The compiler figures out that not every Object is an array. If we know that x contains an array value, we tell the compiler that with a type cast. ((int [ ]) x)[k+1] = 1; Once the compiler is satisfied, we'll be working with dynamic types at run time. Any object remembers how it was created, and thus its dynamic type is what's used to determine which method to call or variable to use. D. Abstract Classes Motivation In all the cases we've seen so far, we have started with a class that's useful in its own right (Counter, Point, and IntSequence) and used inheritance to produce a class with extra functionality. Consider now the slightly different task of using inheritance to organize an already existing bunch of similar classes. An example is described in chapter 8 of Head First Java; here are the classes. Animal, with methods makeNoise, eat, sleep, and roam Feline, with method roam Canine, with method roam Lion, Tiger, Cat, Wolf, and Dog, all with methods makeNoise and eat The "is a" relationships among these classes suggest the following inheritance structure: Classes Feline and Canine override Animal's roam method and inherit Animal's makeNoise, eat, and sleep methods, taking advantage of duplication among these classes. Lion, Tiger, Cat, Wolf, and Dog override makeNoise and eat, and inherit the sleep (indirectly from Animal) and roam methods from Feline and Canine. Now we have a question. How do Animals eat, or sleep, or make noise? Well, it depends on what kind of animal we are instantiating, because they're all different. This suggests that it doesn't make any sense to instantiate an Animal object. But we need to have the Animal class to take advantage of polymorphism. What to do? Abstract classes Java provides a feature called an abstract class to handle this problem. An abstract class cannot be instantiated; it can only be extended. It typically contains abstract methods that must be overridden by the extending class. In this way, Java allows us to enforce the provision of a class without supplying any details about how that class will work; those details are supplied in the extending class. We declare an abstract class by adding the keyword abstract to the class header, e.g. public abstract class Animal { ... } We similarly declare an abstract method by adding abstract to the method header, and in addition providing no body for the method (we just end the declaration with a semicolon). public abstract class Animal { ... public abstract void eat ( ); public abstract void sleep ( ); public abstract void makeNoise ( ); public abstract void roam ( ); } An abstract class may include non-abstract methods as well. Any class that has an abstract method must be an abstract class, however. Abstract Classes in Java Libraries The various Java libraries contain several abstract classes. For example, the class Number in java.lang is the superclass of Integer and BigInteger (arbitrarily long integers), among others. Here's a declaration for Number: public abstract class Number { public byte byteValue ( ); // Returns the value of the specified number as a byte. public abstract double doubleValue ( ); // Returns the value of the specified number as a double. public abstract float floatValue ( ); // Returns the value of the specified number as a float. public abstract int intValue ( ); // Returns the value of the specified number as an int. public abstract long longValue ( ); // Returns the value of the specified number as a long. public short shortValue ( ); // Returns the value of the specified number as a short. } Most of the abstract classes in java.util are used in connection with collection classes, for example, sets and lists. The Java library javax.swing, which provides facilities for implementing graphical user interfaces, includes a variety of abstract classes that help to design platform-independent interfaces. Abstract Dates As an example, given below is an abstract class to represent calendar dates (in a non-leap year), along with two concrete classes that extend it. public abstract class Date { public abstract int dayOfYear ( ); private int myDayOfMonth; private int myMonth; private int myYear; public Date (int year, int month, int dayOfMonth) { myDayOfMonth = dayOfMonth; myMonth = month; myYear = year; } public int dayOfMonth ( ) { return myDayOfMonth; } public int month ( ) { return myMonth; } public int year ( ) { return myYear; } public String toString ( ) { return "" + myDayOfMonth + "/" + myMonth + "/" + myYear; } } public class FrenchRevolutionaryDate extends Date { // In a nonleap year in the French Revolutionary Calendar, // the first twelve months have 30 days and month 13 has five days. public FrenchRevolutionaryDate (int year, int month, int dayOfMonth) { super (year, month, dayOfMonth); } @Override public int dayOfYear ( ) { return (month()-1) * 30 + dayOfMonth ( ); } } public class GregorianDate extends Date { public static int [ ] monthLengths = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; public GregorianDate (int year, int month, int dayOfMonth) { super (year, month, dayOfMonth); } @Override public int dayOfYear ( ) { int rtnValue = 0; for (int m=0; m interfaces. Interfaces can also extend other interfaces by using the extends keyword. This means that the extending interface is inheriting the behavior of the other interface. Interfaces cannot use the implements keyword because only classes can implement interfaces. Motivation for Interfaces Some of you may know that Apple has requirements for the user interface of programs that run on the Macintosh. For instance, each program that involves editing data is supposed to supply a "File" menu that includes elements "Open", "Close", and "Print". A program that obeys the guidelines presents a consistent interface to the user and is deemed "Mac-like". A program that doesn't obey the guidelines is "un-Mac-like", and may be harder to learn and use as a result. Java interfaces support the same kind of consistency for programmers as the Macintosh user interface guidelines do for users. By specifying method headers, they tell the programmer exactly what to name his or her methods in order to coordinate with other parts of the Java class libraries. For example, there is a sort method in java.util.Arrays. Sorting involves comparing array elements, so if you're sorting an array of objects of a certain class, that class needs to define some way to compare the objects in it. One does this by having the class implement the Comparable interface and supply a method named compareTo to do comparison between elements. A programmer wanting to sort an array would probably not call compareTo directly. Instead, he or she would call Arrays.sort, which in turn would call the user-provided method. This is referred to as a callback, where you call a method of another class that you expect to call a method in your class. Overall, think of an interface as specifiying a contract for any class that implements the interface, which then can be relied upon to supply the relevant methods for users of the class. Exercise: Sorting Dates Create a SimpleDate class to work with the following main method. You only need to implement a simple version that can work with the following main method. public static void main (String [ ] args) { SimpleDate [ ] dArray = new SimpleDate [4]; dArray[0] = new SimpleDate (5, 2); // 5/2 dArray[1] = new SimpleDate (2, 9); // 2/9 dArray[2] = new SimpleDate (6, 3); // 6/3 dArray[3] = new SimpleDate (1, 11); // 1/11 Arrays.sort (dArray); for (int k=0; k (not just Comparable). Consult the Java API to find out what methods the Comparable interface promises. The Arrays.sort method is found in java.util. Don't try to rewrite it; just use the version in the library. You may have to import it with import java.util.Arrays;. F. A Better IntSequence Exercise: A Better IntSequence Recall that when add was called on an IntSequence that did not have any space left, the expected behavior was to print out an error message and then call System.exit(1). We can do better. Create a ResizableIntSequence class that extends your IntSequence class from lab 5. Override the add and insert methods so that whenever either of these methods is called on a full ResizableIntSequence, the ResizableIntSequence increases its capacity to accomodate for the new elements. Remember to write tests before you start coding your methods! Discussion: Increasing Capacity Link to the discussion Once a ResizableIntSequence has reached its maximum capacity, by how many elements should its capacity be increased? 10? 1000? Something else? Explain your reasoning, and add a post about it to the discussion. Discussion: Decreasing Capacity Link to the discussion Once you remove too many elements from a formerly very large ResizableIntSequence , it becomes wasteful for the ResizableIntSequence to keep around all of its unused space. Suppose the remove method decreased a ResizableIntSequence 's maximum capacity by some factor once its capacity reached some threshold (i.e. once it contained less than some small fraction of its maximum capacity). What's a reasonable resizing capacity threshold, and by how much should we decrease a ResizeableIntSequence 's maximum capacity? Exercise: One Last Step Now override the remove method to dynamically decrease a ResizableIntSequence's maximum capacity once its capacity reaches some threshold. ArrayLists Congratulations! You've just implemented a basic version of an ArrayList. ArrayList is Java's implementation of automatically resizing arrays. Note that unlike regular arrays, ArrayLists can only hold objects (so no primitives). We expect that you'll find this data structure incomprehensibly useful in the future. For more details on ArrayLists, you can check out Java's API. G. Conclusion Summary We hit four "high points" in this lab: inheritance, polymorphism, abstract classes, and interfaces. Here are some suggestions for further exploration. Why do toString and equals almost always have to be redefined? The java.util.Stack supports some methods that are decidedly unrelated to stacks (e.g. contains, get, and insertElementAt). How do we fix it? What does the Java Collection Framework contain? Submission Submit as lab06: ModNCounter.java that works with the Counter class that has a private instance variable TracedPoint.java Your four date java files ResizableIntSequence.java and ResizableIntSequenceTest.java. Reading Read the following: HFJ pages 250 through 255, chapter 11, and Appendix B #4

本站部分内容来自互联网,仅供学习和参考