> comp 170 / isom 370 Final Exam Study Guide Dordal > Exam: Monday, May 8, 2006, 4:15 pm > ==================================================================== > > Sample problems > > 1. Here's another variation on inheritance > > Suppose we have > > class Base { > public int x; > public Base(int x) { this.x = x; } > public int f() {return x + g();} > public int g() {return 100;} > } > > class Deriv extends Base { > public Deriv(int x) {super(x);} > public int g() {return 6660;} > } > > Suppose we have the following: > > Base b1 = new Base(4); > Base b2 = new Deriv(5); > Deriv d1 = new Deriv(6); > > (a). What is the output of the following? > > System.out.println(b1.f()); > System.out.println(b2.f()); > System.out.println(d1.f()); Note that Base.f() and Deriv.f() are the SAME! That is, Deriv makes no change in f(). However, f() calls g(), and for Deriv objects it is the new g() that is invoked. b1.f(): 104 b2.f(): 6665 d1.f(): 6666 > (b). What is the output of the following? > > System.out.println(b1.g()); > System.out.println(b2.g()); > System.out.println(d1.g()); 100 6660 6660 > ============== > > 2. Suppose we have a simulator that handles planes and cars. > class Plane has a > Position fly(Weather w, int t) > method that gives the position after time increment t; > class Car has method > Position drive(Traffic tr, int t) > > (a). Can you give a common base class for Plane and Car that > has a single abstract method for fly() and drive()? > If so, give the base class definition; if not, explain why not. abstract class Vehicle { ... public abstract Position move(Weather w, Traffic tr, int t); ... } class Plane extends Vehicle { public Position move(Weather w, Traffic tr, int t) { // ignore Traffic parameter tr ... } } class Car extends Vehicle { ... similar ... } Note that we have to rename the method "move()". The fact that the Plane version appears to have different parameters, however, we can easily fix by having move() take *all* relevant parameters (that is, both Weather w and Traffic tr; Planes ignore tr and Cars ignore w) > (b). Can you give an Interface that both Plane and Car, as > separate classes, could implement? public interface Vehicle { public Position move(Weather w, Traffic tr, int t); } No data can be provided in an interface, but we didn't do that above. You might *assume* that there is a getPosition method that returns the current Position object, that works for both Planes and Cars. The most we could do in the interface, then, would be to supply a getPosition interface listing. But we couldn't implement it. > ============== > > 3.(a). Convert the following loop to a for-loop using iterators. > The variable "items" is an ArrayList. Class Items has two child > classes, Red and Green. > > for(int i = 0; i< items.size(); i++) { > Item itm = (Item) items.get(i); > if (itm instanceof Red) { > Red r = (Red) itm; > r.printRed(); > } else { > itm.printItem(); > } > } Note: the third slot in the "for" parentheses is empty for (Item itm : items) { if (itm instanceof Red) { Red r = (Red) itm; r.printRed(); } else { itm.printItem(); } } > (b). How could inheritance be used to avoid the use of "instanceof"? We could rename class Red's "printRed" method to "printItem". That way, if r is a Red object, a call to r.printItem would do exactly what r.printRed() does now. Thus, we could simplify the loop to for (Iterator it = items.iterator(); it.hasNext() ; ) { Item itm = (Item) it.next(); itm.printItem(); } > (c). Now convert it to a while loop using iterators. Iterator it = items.iterator(); while (it.hasNext()) { Item itm = (Item) it.next(); if (itm instanceof Red) { Red r = (Red) itm; r.printRed(); } else { itm.printItem(); } } > ============= > > 4. Consider the following class: > > public class Foo { > int x; > public Foo(int xx) { x = xx;} > public int f() {return x;} > public int g() {return 0;} > } > > (a). Assume the intent is for derived classes always to implement > class-specific versions of g(). Why can't we leave the body of g() > blank (that is, {} )? It has to return an int. > (b). Rewrite Foo as an abstract class, making g() abstract too; public abstract class Foo { int x; public Foo(int xx) { x = xx; } public int f() {return x;] abstract public int g(); // no body at all, not even { } ; > (c). Rewrite Foo as an interface, to the extent possible. > Just leave out parts that don't translate (like the field x). Note that I create an accessor interface for x (named getX, setX), as I have no other way of specifying that there's an x value present. public interface Foo { public int f(); public int g(); public int getX(); // accessor interface for x public void setX(int x); } > ============= > > 5. Consider the MyShape class from lab 9. > A simplified and abbreviated version of MyShape might be: > > public class MyShape > { > private int xPosition; > private int yPosition; > private String color; > > public MyShape(int x, int y) {...} > > public int getXPos() {return xPosition; } > public int getYPos() {return yPosition; } > public void moveRight() {moveHorizontal(20);} > public void moveLeft () {moveHorizontal(-20);} > public void moveUp() {moveVertical(-20);} > public void moveDown() {moveVertical( 20);} > public void moveHorizontal(int distance) {...} > public void moveVertical(int distance) {...} > public void draw() {} > public String getColor() {return color;} > public void setColor(String c) { color = c;} > } > > (a). What changes would have to be made to make MyShape an > abstract class? Why might you want to do this? Change first line to abstract public class MyShape The only candidate for an abstract method is draw(); it would become: abstract public void draw() ; > (b). What changes would have to be made to make MyShape > an interface? The three (private) fields would have to go away, > as interfaces cannot contain data. Would anything replace these? > Would any part of the interface serve as an indication that > classes implementing the interface would likely have these > fields? Where would these fields have to be moved to? In the MyShape *class*, the three fields each have an accessor; "color" also has a field mutator. These pretty much require that any MyShape have fields for x, y, and color, even if they're named something different. The interface would look like: public interface MyShape { public int getXPos(); public int getYPos(); public void moveRight(); public void moveLeft (); public void moveUp() ; public void moveDown(); public void moveHorizontal(int distance); public void moveVertical(int distance); public void draw(); public String getColor(); public void setColor(String c); } Because there are so many method DEFINITIONS that we can put into MyShape that don't have to be extended or overridden in the derived classes, the abstract class is likely to save more time in the long run. > ============= > > 6. In the ImageViewer project: > > (a). Why is class Filter an abstract class? We can't hope to spell out the implementation of a generic filter, any more than we can spell out how to draw a MyShape without having a specific shape in mind. > (b). The following inheritance relationships are used > (aside from Filter): > > ImagePanel: public class ImagePanel extends JComponent > OFImage: public class OFImage extends BufferedImage > > Explain the purpose of these inheritance relationships, > and in what ways they simplify the project. Making ImagePanel extend JComponent means that we can add ImagePanels to frame.contentPane directly, as they are really "JComponents". Having OFImage extend BufferedImage isn't quite as useful, since at no point do we actually need to pass OFImage objects to some existing library method that is expecting a BufferedImage. We do at one point call panelImage.getGraphics() where panelImage is an OFImage and getGraphics is a method of class BufferedImage; here, therefore, inheritance is used. But it would have been just as easy to have OFImage *contain* a field of type BufferedImage and then handle this via an extra accessor: panelImage.getBufferedImage().getGraphics() Later, in the paint() method, we call g.drawImage(panelImage, 0, 0, null); for a Graphics g. This again is an application of inheritance, as Graphics.drawImage takes a BufferedImage as parameter, but again we could just as easily have achieved this with g.drawImage(panelImage.getBufferedImage()); > (c). Look at class Filter. Why do you think it was *not* > implemented as an interface? What problem comes up if you > try to convert it to an interface? We would then have to implement getName()/setName() in every derived class, explicitly. As things stand, with Filter as an abstract class instead of an interface, we can implement getName/setName just once, in class Filter, and all the child classes just inherit these. > ============= > > 7. Recall the ImageViewer project. Suppose the Undo button > is implemented by setting the image field currentImage > to prevImage. Also, before each filter application, and > before each button application, we save currentImage via > prevImage = currentImage. > > (a). Explain why this works for the rotate, smaller, and larger > buttons, but *fails* for the filters. Actually, it doesn't fail for ALL the filters, only for those that do their translation "in place". Some of the filters, like "fisheye", do make a copy of the original before the transformation begins. For rotate/smaller/larger, we set prevImage=currentImage, which leaves "prevImage" and "currentImage" two REFERENCES to the same actual set of pixels. But we then create a *new* currentImage (eg currentImage = new Image(width*w, height*2)). This leaves currentImage as a reference to an entirely new set of pixels, and prevImage remains the sole reference to the original set of pixels, which never change. For most of the filters, however, we have prevImage == currentImage == the original set of pixels, which the filter then modifies IN PLACE. As prevImage is still a reference to this same now-modified set of pixels, prevImage has in effect been changed. Restoring to prevImage doesn't restore to the original image. > (b). What do you have to do to get it to work for the filters? You have to force prevImage to be a COPY of currentImage. I just did this by making prevImage = new Image(currentImage.getWidth(), currentImage.getHeight()); and then just set each pixel in prevImage using setPixel. > 8. Consider a simple graphics-item container class, MyContainer. > It is to have an ArrayList field called "panes", of items of type > Pane. Panes implement the following interface: > > public interface Paintable { > public void paint(int x, int y); > } > > An outline of MyContainer might be: > > public class MyContainer { > private ArrayList panes; > ... > } > > (a). Implement a method > void add(Pane p) > to add new Panes to the MyContainer. public void add(Pane p) { panes.add(p); // This is ArrayList.add(). } > (b). Implement a method > Pane get(int i) > in MyContainer to get the ith Pane. public Pane get(int i) { return panes.get(i); // again, this is ArrayList.get() } > (c). Implement a paint() method for MyContainer. The first Pane > is to be painted at coordinates (x,y)=(0,0); the second at > coordinates (40,40), the third at (80,80), incrementing both > x and y by 40 for each successive pane. Note that MyContainer.paint() > and Pane.paint(int x, int y) are different; you assume the latter > and are to write the former. > > +------------------+ > | | > | +------------------+ > | | | > | | +------------------+ > | | | | > | | | | > | | | | > | | | | > +---| | | > | | | > +---| | > | | > +------------------+ public void paint() { int x = 0; int y = 0; for (int i = 0; i< panes.size(); i++) { Pane p = (Pane) panes.get(i); p.paint(x,y); x += 40; y += 40; } } > (d). write a declaration of class Pane that implements the interface > Paintable. All I meant was: public class Pane implements Paintable { ... } > ============= > > 9. In the ImageViewer class, suppose we define > undoButton = new JButton("Undo"); > > (a). Add an ActionListener to undoButton, using either an > anonymous or named inner class. From ImageViewer: undoButton = new JButton("Undo"); undoButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { undo(); } }); Broken into steps: ActionListener undoAL = new ActionListener() { public void actionPerformed(ActionEvent e) { undo(); } } undoButton.addActionListener(undoAL); > (b). We added all four buttons to something called "toolbar", > not to contentPane directly. Why? So we could control their layout as a group (that is, so they could be aligned vertically regardless of how other components were aligned).