asdsdwdwdfdgfgf

download asdsdwdwdfdgfgf

If you can't read please download the document

description

ghjuuytr

Transcript of asdsdwdwdfdgfgf

  • Exercise 1.3

    Use a negative parameter value to move left, e.g. -70

    Exercise 1.9

    The House Picture

    The main building:

    Create a new Square object Invoke its method makeVisible() Make the square bigger by invoking the method changeSize(newSize) (100 is

    a good size) Move the square down by invoking the method moveVertical(distance) (again

    80 is a good value)

    The window:

    Create a new Square object. Invoke its method makeVisible() Change its color by invoking changeColor() write "black" in the popupwindow Move the square down by invoking the method moveVertical(distance) (100 is

    a good value) Move it to the right by invoking moveRight()

    The roof:

    Create a new triangle object. Invoke its method makeVisible() Change its size with changeSize(newHeight, newWidth) (50,140) moveVertical(70) moveHoizontal(60)

    The Sun:

    Create new Circle object. Invoke its method makeVisible() Change its color by invoking changeColor() (write "yellow" in the popup

    window) Optionally change its size with changeSize(60) Move it to the right by invoking moveHorizontal(180)

    The Hilltop Picture

    The hill:

  • Create a new Circle object. Invoke its makeVisible() method. Change its color by invoking changeColor (write green in the popup

    window) Change its size with changeSize to something like 1000. Move it left with moveHorizontal(-500). Move it down with moveVertical(125).

    The sun:

    Create a Circle. Make it visible. Set its size to 30. Move it right by 150 pixels. Move it down by 50 pixels.

    The larger figure:

    Create a new Person object. Invoke its makeVisible method. Change its size to something like 50 high and 25 wide. Move it left by 30 pixels and up by around 8.

    The smaller figure:

    The size should be around 40 by 20. Move it left by 3 pixels and down by 2.

    Exercise 1.14

    It uses the objects of the classes Circle, Square and Triangle. It then moves these objects to the right places and changes the sizes and colors

    of the obejcts. Essentially calling the same methods as used in exercise 1.9

    Exercise 1.16

    Change:

    sun.changeColor("yellow");

    to be:

    sun.changeColor("blue");

    Note that this change should be made in both the draw() and setColor() methods. Students often forget to do it in the latter. Illustrate the problem by drawing the picture, then calling setBlackAndWhite() then setColor() the sun will have been changed to yellow, rather than blue, if the second change is not made.

  • Exercise 1.17

    The second sun will need to be positioned somewhere different from the first sun to be visible. As with the previous exercise, it is common for students to miss the need to change the setColor and setBlackAndWhite methods for compatibility with the addition. This is an earlier introduction to the need for regression testing!

    Exercise 1.18

    After the line sun.makeVisible() insert the following:

    sun.slowMoveVertical(250); Compile the Picture class (Press compile in the editor window) Create instance of class Picture and invoke its draw() method.

    Exercise 1.19

    Remove the line (if added in the previous exercise): slowMoveVertical(250); Right below the last } after the draw() method, add the sunset() method :

    /** * Animates the sunset. */ public void sunset() { sun.slowMoveVertical(250); } Compile! And run it.

    Exercise 1.20 Define a new field:

    private Person person; Initialize and position them in the draw():

    person = new Person(); person.changeSize(80, 40); // Place them at ground level. person.moveVertical(15); // Make sure they are to the right of the house to start. person.moveHorizontal(200);

    Make them visible and move up to the house in sunset():

    person.makeVisible(); // Walk up to the house. person.slowMoveHorizontal(-150);

    Exercise 1.22

  • When calling the method getName(), the name of the student is displayed in a popup window. The name displayed is the one typed in when the object was created.

    Exercise 1.24 It shows the number of students in the LabClass which is zero.

    Exercise 1.31

    Students looking these values up in the tutorial might not be able to readily identify that the integer types used here are int, as opposed to byte, short or long. Similarly, they may well suggest float rather than double for the final one. Be sure to point out that String always has an initial upper-case letter, because these subtleties are often missed.

    0 int "hello" String 101 int -1 int true boolean "33" String 3.1415 double

    Exercise 1.32

    First you would have to decide which type the field should have. String would be a good type to hold a name, so we add the following line to the source file of Circle: private String name;

    The above line could be placed after this line in the source code of the Circle class:

    private boolean isVisible;

    Exercise 1.33

    public void send(String msg)

    The name msg is arbitrarily chosen.

    Exercise 1.34

    public int average(int firstNumber, int secondNumber)

    Exercise 1.35

    The book is an object because it is a specific instance of the Book class.

    Exercise 1.36

    Yes, an object can belong to several classes. One of the more famous examples are

  • the platypus, which is both a mammal and egg-laying.

  • Exercise 2.2

    Zero.

    Exercise 2.3

    If too much money is inserted the machine takes it all - no refund. If there isn't enough money inserted, it still prints out the ticket.

    Exercise 2.5

    It looks almost completely the same. Only the price on the ticket is different.

    Exercise 2.6

    The outer part of the student class: public class Student { } The outer part of the LabClass class: public class LabClass { }

    Exercise 2.7

    Yes, the order of public and class matters.

    Exercise 2.8

    It is possible to leave out the word public.

    Exercise 2.9

    It is not possible to leave out the word class.

    Exercise 2.10 Fields: price balance total

    Constructors: TicketMachine

    Methods:

  • getPrice getBalance insertMoney printTicket

    Exercise 2.11 It does not have any return type. The name of the constructor is the same as the name of the class.

    Exercise 2.12 int Student Server

    Exercise 2.13 alive tutor game

    Exercise 2.14

    Student, Server, Person and Game

    Exercise 2.15 The exact order matters.

    Exercise 2.16 Yes, it always necessary to have a semicolon after a field declaration.

    Exercise 2.17

    private int status;

    Exercise 2.18

    It belongs to the class Student.

    Exercise 2.19

    It has two parameters. One is of type String and the other of type double.

    Exercise 2.20

    It would be reasonable to expect the types to be the same as the two parameters (String and double).

    Can't really assume anything about the names, but probably something like title and

  • price.

    Exercise 2.21

    name = petsName;

    Exercise 2.22

    public Date(String month, int day, int year)

    Exercise 2.23 Aside from their names, the only difference is that getPrice() returns the value of the price field whereas getBalance() returns the value of the balance field.

    Exercise 2.24 How much money have I inserted into the machine?

    Exercise 2.25 No. There is no direct link between the name of a method and the name of the field. However, it is a convention to use a name for the method that clearly links it to the field.

    Exercise 2.26 public int getTotal() { return total; }

    Exercise 2.27 Missing return statement.

    Exercise 2.28 The header for getPrice() has an int as return type. The header for printTicket() has void as return type.

    Exercise 2.29 No. Because they don't need to return anything. Yes. Both headers have void as return types.

    Exercise 2.31

    It has a return type (void) and constructors do not have return types. It also does not have the same name as the class it is in.

    Exercise 2.32

  • price = cost;

    Exercise 2.33

    score = score + points;

    Exercise 2.34

    It is a mutator.

    Use an inspector to view the current score, then call the increase method with a positive parameter value and observe that score increases by that value.

    Alternatively, if score has an accessor method; call the accessor, then call increase, and then call the accessor once again to verify that it returns the updated value, indicating that the field has been modified.

    Exercise 2.35

    price = price - amount;

    Exercise 2.36 Note that no quote marks are printed, just the following: My cat has green eyes.

    Exercise 2.37 public void prompt() { System.out.println("Please insert the correct amount of money."); }

    Exercise 2.38 Instead of printing out the actual price of the ticket, it displays the word "price": # price cents.

    Exercise 2.39 Prints out the exact same string as in exercise 2.38

    Exercise 2.40 No, because neither uses the value of the price field in the println statement.

    Exercise 2.41 public void showPrice() { System.out.println("The price of a ticket is " + price + " cents."); }

    Exercise 2.42

  • They display different prices. This is because each ticket machine object has its own price field. The price that was set in one ticket machine does not affect the other ticket machines price. The unique value of each ticket machine's price field is substituted into the println statement when the method is called.

    Exercise 2.43 public TicketMachine() { price = 1000; balance = 0; total = 0; } When constructing a TicketMaching object you will not be prompted for a parameter value. The tickets always have a price of 1000 cents.

    Exercise 2.44 public TicketMachine() { price = 1000; balance = 0; total = 0; } public TicketMachine(int ticketCost) { price = ticketCost; balance = 0; total = 0; }

    Exercise 2.45 public void empty() { total = 0; } It needs no parameters. It is a mutator.

    Exercise 2.46 The balance does not change when an error message is printed. Inserting zero results in an error message.

    Exercise 2.47 This version does not print an error message when zero is inserted. Othere than that, it does not change the observable behavior of the method.

  • Exercise 2.48 Note the importance of using budget) { System.out.println("Too expensive. Your budget is only: " + budget); }

  • else { System.out.println("Just right."); }

    Exercise 2.58 Because balance is set to zero and then this new value is returned rather than the old one. The method will always return zero. It can be tested by inserting an amount, and then calling refundBalance(). The original would then return the amount inserted, but the new method returns 0.

    Exercise 2.59 An error is printed: unreachable statement. A return statement ends (exits) the method. Code after a return statement can therefore never be executed.

    Exercise 2.60 The variable price is being re-declared as a local variable in the constructor this is the effect of the word int in front of it. This local variable hides the field of the same name. So the ticket price is never assigned to the price field.

    Exercise 2.61 public int emptyMachine() { int oldTotal = total; total = 0; return oldTotal; }

    Exercise 2.62 public void printTicket() { int amountLeftToPay = price - balance; if(amountLeftToPay

  • You would need fields to store the prices of each of the tickets that the machine can issue.

    You would need a method to select which type of ticket you would want.

    It will not be necessary to modify many of the existing methods, if the price field is updated each time you select a new ticket type. You would probably need to modify the constructor, to allow several ticket prices.

    Exercise 2.64 Name: getCode Return type: String

    Exercise 2.65 Name: setCredits Parameter name: creditValue Parameter type: int

    Exercise 2.66

    public class Person { }

    Exercise 2.67

    private String name; private int age; private String code; private int credits;

    Exercise 2.68

    public Module(String moduleCode) { code = moduleCode; }

    Exercise 2.69

    public Person(String myName, int myAge) { name = myName; age = myAge; }

    Exercise 2.70

    The return type should not be void.

    public int getAge()

  • { return age; }

    Exercise 2.71

    public String getName() { return name; }

    Exercise 2.72

    public void setAge(int newAge) { age = newAge; }

    Exercise 2.73

    public void printDetails() { System.out.println("The name of this person is " + name); }

    Exercise 2.74 student1 : Student name: Benjamin Johnson id: 738321 credits: 0

    Exercise 2.75 "Henr557"

    Exercise 2.76 It opens the editor with the source code for the Student class. It displays a message: StringIndexOutOfBoundsException This happens because the method getLoginName expects the name to be at least 4 characters long and "djb" is only 3 characters.

    Exercise 2.77 public Student(String fullName, String studentID) { if(fullName.length() < 4) { System.out.println("Error! The name should be at least 4 characters long"); } if(studentID.length() < 3) { System.out.println("Error! The studentID should be at least 3 characters long"); } name = fullName; id = studentID;

  • credits = 0; }

    Exercise 2.78 public String getLoginName() { String loginNamePart; if(name.length() < 4) { loginNamePart = name; } else { loginNamePart = name.substring(0,4); } String loginIdPart; if(id.length() < 3) { loginIdPart = id; } else { loginIdPart = id.substring(0,3); } return loginNamePart + loginIdPart ; }

    Exercise 2.79 102 "catfish" "cat9" "12cat" "cat39" "f" StringIndexOutOfBoundsException

    Exercise 2.80 The first call returns 0 and the second returns 500.

    Exercise 2.81 Because t2 refers to the same object as t1, the call will print 500. This example of aliasing is an important one and students should try to ensure that they understand what is going on here.

    Exercise 2.82 The call returns 1000. Even though the change was made via t1, because t2 is referring to the same object, it sees the new value. Note that we have only created a single TicketMachine object in these two exercises, but two variables refer to that one object.

    Exercise 2.83 /** * Returns the author of this book. */ public String getAuthor() {

  • return author; } /** * Returns the title of this book. */ public String getTitle() { return title; }

    Exercise 2.84 /** * Prints the name of the author in the terminal window. */ public void printAuthor() { System.out.println("Author: " + author); } /** * Prints the title of the book in the terminal window. */ public void printTitle() { System.out.println("Title: " + title); }

    Exercise 2.85 Delete the constructor and insert this: private int pages; /** * Set the author and title fields when this object * is constructed. */ public Book(String bookAuthor, String bookTitle, int bookPages) { author = bookAuthor; title = bookTitle; pages = bookPages; } /** * Returns the number of pages in this book. */ public int getPages() { return pages; }

    Exercise 2.86? The objects are immutable because the class contains no methods to change the values of any of the fields once an instance has been created.

    Exercise 2.87? public void printDetails()

  • { System.out.print ("Title: " + title + ", "); System.out.print("Author: " + author + ", "); System.out.println("Pages: " + pages); }

    Exercise 2.88 Delete the constructor and insert: private String refNumber; /** * Set the author and title fields when this object * is constructed. */ public Book(String bookAuthor, String bookTitle, int bookPages) { author = bookAuthor; title = bookTitle; pages = bookPages; refNumber = ""; } /** * Sets the reference number for this book */ public void setRefNumber(String ref) { refNumber = ref; } /** * Gets the reference number for this book */ public String getRefNumber() { return refNumber; }

    Exercise 2.89

    public void printDetails() { System.out.println("Title: " + title); System.out.println("Author: " + author); System.out.println("Pages: " + pages); String refNumberString; if(refNumber.length() > 0 ) { refNumberString = refNumber; } else { refNumberString = "ZZZ"; } System.out.println("Reference number: " + refNumberString); }

  • Exercise 2.90

    public void setRefNumber(String ref) { if(ref.length() >= 3) { refNumber = ref; } else { System.out.println("Error! The reference number must be at least 3 characters long."); } }

    Exercise 2.91 Add the field: private int borrowed; Add the methods: /** * Borrows the book. Increments the number of times the book has been borrowed. */ public void borrow() { borrowed++; } /** * Gets the number of times the book has been borrowed. */ public int getBorrowed() { return borrowed; } Add this line to printDetails method: System.out.println("Borrowed: " + borrowed);

    Exercise 2.92?

    private boolean courseText;

    public boolean isCourseText() { return courseText; }

    Exercise 2.93

    public class Heater { private int temperature; /** * Creates a new Heater with an initial temperature of 15. */

  • public Heater() { temperature = 15; } /** * Increases the temperature by 5 degrees */ public void warmer() { temperature += 5; } /** * Decreases the temperature by 5 degrees */ public void cooler() { temperature -= 5; } /** * Gets the current temperature of the heater */ public int getTemperature() { return temperature; } }

    Exercise 2.94

    public class Heater { private int temperature; private int min; private int max; private int increment; /** * Creates a new Heater with an initial temperature of 15. */ public Heater(int minimum, int maximum) { min = minimum; max = maximum; temperature = 15; increment = 5; } /** * Increases the temperature */ public void warmer() { int newTemperature = temperature + increment; if(newTemperature

  • /** * Decreases the temperature */ public void cooler() { int newTemperature = temperature - increment; if(newTemperature >= min) { temperature = newTemperature; } } /** * Sets the increment, which determines how much the two methods * warmer() and cooler() changes the temperature. */ public void setIncrement(int inc) { if(inc >= 0) { increment = inc; } } /** * Gets the current temperature of the heater */ public int getTemperature() { return temperature; } } If the setIncrement method does not check for negative values, and a negative value is passed, then the program will not work as expected. The minimum and maximum values can be exceeded.

  • Exercise 3.1

    The class diagram contains only 2 elements: LabClass and Student. The LabClass class is linked to the Student class. The object diagram contains 4 elements. 1 LabClass object and 3 Student objects. The LabClass object contains links to the three Student objects.

    Exercise 3.2

    A class diagram changes when you modify the source code. That can be by changing the relations between classes or creating/deleting classes.

    Exercise 3.3

    An object diagram changes when the program is running. It can be changed by creating new objects, calling methods, and making assignments involving object references.

    Exercise 3.4

    private Instructor tutor;

    Exercise 3.6

    Nothing happens. No. It should print out an error message.

    Exercise 3.7

    It would not allow a value of zero to be used as a replacement.

    Exercise 3.8

    The test will be true if one of the conditions is true It will always be true if the limit is larger than or equal to 0. It would also be true if the replacement value is negative, for instance.

    Exercise 3.9

    false true false false true

    Exercise 3.10

  • The long version of this would be:

    (a == true && b == true) || (a == false && b == false)

    This can be simplified to:

    (a && b) || (!a && !b)

    But since both must have identical values, the simplest form is:

    a==b

    Exercise 3.11

    As in the previous exercise, the long version would be:

    (a == true && b == false) || (a == false && b == true)

    This can be simplied to:

    (a && !b) || (!a && b)

    Or:

    (a || b) && (a != b)

    Or even:

    a != b

    Exercise 3.12

    !(!a || !b)

    Exercise 3.13

    No.

    The method assumes that the value will only contain two digits.

    Exercise 3.14

    No.

    Exercise 3.15

    The exact definition can be found in The Java Language Specification Third Edition in section 15.17.3 http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.17.3 The correct answer may not be intuitive when negative values are involved.

  • The key is that the modulus operator works so that (a / b) * b + (a % b) == a rearranging we get: a % b == a (a / b) * b which works even when negative values are involved.

    Exercise 3.16

    2

    Exercise 3.18

    -4, -3, -2, -1, 0, 1, 2, 3, 4

    Exercise 3.19

    Values in the range from -(m-1) to (m-1)

    Exercise 3.20

    As long as value is smaller than limit, it gets incremented by 1 (the modulo can be ignored) When value reaches the limit, the modulo operation will result in value being set to 0. So, the increment method increments value by one, until the limit is reached, at which point it will start over at 0.

    Exercise 3.21

    Many students get this one wrong on the boundaries. A common wrong solution, which results in a value equal to the limit is:

    public void increment() { if(value < limit) { value = value + 1; } else { value = 0; } } A correct, but difficult to visually verify version, which is often the result of fixing the above is: public void increment() { if(value < limit - 1) { value = value + 1; } else {

  • value = 0; } } Best, because it is easy to see that it is correct is: public void increment() { value = value + 1; if(value >= limit) { value = 0; } }

    Both ways of incrementing are equally good. Once the modulus operator is understood, its use is obviously more succinct.

    Exercise 3.23

    The time is initialized to 00.00. The constructor creates two new NumberDisplay which are initialized to 0 (in the constructor for NumberDisplay)

    Exercise 3.24

    It needs 60 clicks Using the method setTime() on the object.

    Exercise 3.26

    public Editor(String fileName, int number)

    Exercise 3.27

    Rectangle window = new Rectangle(3,6);

    Exercise 3.28

    It initializes the time to the values passed to the method. It uses the method setTime to set the time to the initial value.

    Exercise 3.29

    Both constructors creates two new NumberDisplays. The first constructor calls updateDisplay and the second calls setTime(hour, minute). In the second constructor there is no call to updateDisplay because this will be done in the method setTime.

    Exercise 3.30

    p1.print("file1.txt", true);

    p1.print("file2.txt", false);

  • int status;

    status = p1.getStatus(12);

    status = p1.getStatus(34);

    Exercise 3.31 and 3.32

    1) change the updateDisplay in ClockDisplay as this: /** * Update the internal string that represents the display. */ private void updateDisplay() { int hour = hours.getValue(); String suffix = "am"; if(hour >= 12) { hour = hour - 12; suffix = "pm"; } if(hour == 0) { hour = 12; } displayString = hour + "." + minutes.getDisplayValue() + suffix; } 2) public ClockDisplay() { hours = new NumberDisplay(12); //changed minutes = new NumberDisplay(60); updateDisplay(); } public ClockDisplay(int hour, int minute) { hours = new NumberDisplay(12); //changed minutes = new NumberDisplay(60); setTime(hour, minute); } private void updateDisplay() { int hour = hours.getValue(); if(hour == 0) { hour = 12; } displayString = hour + "." + minutes.getDisplayValue(); }

    Exercise 3.38

    Since the debugger shows that: Mailitem item = This indicates that item is not null, and the next line that will be marked is item.print()

  • Exercise 3.39

    This time the item is null. The if-statement will then execute the line: System.out.println("No new mail.");

    Exercise 3.40

    After pressing Step Into and then pressing Step it prints: From: Sophie After the next Step it prints: To: Juan And after another Step: Message: Hi Juan!

    Step Into goes into the method print(). From there on, each line of print is executed by a pressing Step. This results in the lines being printed one at a time instead of just printing all 3 lines as before.

    Exercise 3.45

    A subject field must be added to the MailItem class and set via the constructor. An accessor is also added and the print() method should include it.

    The MailClients sendMailItem() method requires a parameter to receive the subject.

    See 03-45-mail-system.

    Exercise 3.46

    Screen screen = new Screen(1024, 768); if(screen.numberOfPixels() > 2000000) { screen.clear(true); }

  • Exercise 4.4

    private ArrayList library;

    Exercise 4.5 ArrayList cs101;

    Exercise 4.6 private ArrayList tracks;

    Exercise 4.7 library = new ArrayList(); cs101 = new ArrayList(); tracks = new ArrayList(); with Java 7, these can be simplified to: library = new ArrayList(); cs101 = new ArrayList(); tracks = new ArrayList();

    Exercise 4.8 10

    Exercise 4.9 items.get(4);

    Exercise 4.10 14

    Exercise 4.11 files.add(favoriteTrack);

    Exercise 4.12 dates.remove(2);

    Exercise 4.13 5

    Exercise 4.14 public void checkIndex(int index) { if(index < 0 || index >= files.size()) { System.out.println("The valid range is 0 to " +

  • (files.size() 1)); } } If the collection is empty, there is no valid index and the error message will still appear. This special case could be catered for my a separate if statement that checks for an empty collection and prints an error message specific to that case.

    Exercise 4.15 The following are all valid. The first is in the spirit of the previous exercise. The second rewrites to the opposite form and the third gives the most concise representation. public boolean validIndex(int index) { if(index < 0 || index >= files.size()) { return false; } else { return true; } } public boolean validIndex(int index) { if(index >= 0 && index < files.size()) { return true; } else { return false; } } public boolean validIndex(int index) { return index >= 0 && index < files.size(); }

    Exercise 4.16 /** * List a file from the collection. * @param index The index of the file to be listed. */ public void listFile(int index) { if(validIndex(index)) { String filename = files.get(index); System.out.println(filename); } } /** * Remove a file from the collection. * @param index The index of the file to be removed.

  • */ public void removeFile(int index) { if(validIndex(index))) { files.remove(index); } }

    Exercise 4.18 public void listAllFiles()

    Exercise 4.19

    No. We have no idea how many lines we would need.

    Exercise 4.24

    /** * Show a list of all the files in the collection, * along with their index values. */ public void listAllFiles() { // A variable to keep track of the index position. int position = 0; for(String filename : files) { System.out.println(position + ": " + filename); position++; } }

    Exercise 4.26

    /** * List the names of files matching the given search string. * If none are found, print a message. * @param searchString The string to match. */ public void listMatching(String searchString) { // Assume that there will be no matches. boolean noMatch = true; for(String filename : files) { if(filename.contains(searchString)) { System.out.println(filename); // We found at least one match. noMatch = false; } } if(noMatch) { System.out.println("No files matched: " + searchString); } }

  • Exercise 4.27

    /** * Play a sample from all files matching the given search string. * @param artist The string to match. */ public void playSamplesBy(String artist) { int position = 0; for(String filename : files) { if(filename.contains(artist)) { playAndWait(position); } position++; } }

    Exercise 4.28

    for(Track track : tracks)

    Exercise 4.29

    boolean found = false; while(!found) { if(the keys are in the next place) { found = true; } }

    Exercise 4.30

    public void multiplesOfFive() { int multiple = 10; while(multiple

  • */ public int sum(int a, int b) { int sum = 0; int number = a; while(number
  • } }

    Exercise 4.38

    Add:

    stopPlaying();

    to playTrack() once the index has been validated.

    Exercise 4.39

    /** * Remove tracks whose titles match the search string. * A partial match is used. * @param title The string to be matched. */ public void removeTitles(String title) { Iterator it = tracks.iterator(); while(it.hasNext()) { Track t = it.next(); if(t.getTitle().contains(title)) { it.remove(); } } }

    Exercise 4.40-4.42

    import java.util.ArrayList; /** * Store details of club memberships. * * @author (your name) * @version (a version number or a date) */ public class Club { private ArrayList members; /** * Constructor for objects of class Club */ public Club() { members = new ArrayList(); } /** * Add a new member to the club's list of members. * @param member The member object to be added. */

  • public void join(Membership member) { members.add(member); } /** * @return The number of members (Membership objects) in * the club. */ public int numberOfMembers() { return members.size(); } }

    Exercise 4.43

    /** * Select and play a single random track. */ public void randomPlay() { if(tracks.size() > 0) { Random rand = new Random(); int index = rand.nextInt(tracks.size()); playTrack(index); } }

    Exercise 4.45

    The Collections.shuffle() method offers a way to randomly order a collection. This is used in the first version, which does not require a separate random number generator:

    /** * Play all tracks once in a random order. */ public void randomPlayAll() { ArrayList leftToPlay = new ArrayList(tracks); Collections.shuffle(leftToPlay); for(Track t : leftToPlay) { player.playSample(t.getFilename()); } }

    The second version makes a copy of the list and repeatedly removes a random track to be played until the list is empty.

    /** * Play all tracks once in a random order. */ public void randomPlayAll() { Random rand = new Random(); ArrayList leftToPlay = new ArrayList(tracks);

  • while(leftToPlay.size() > 0) { int index = rand.nextInt(leftToPlay.size()); Track t = leftToPlay.remove(index); player.playSample(t.getFilename()); } }

    Exercise 4.47

    boolean successful = selectedLot.bidFor(new Bid(bidder, value));

    Exercise 4.48

    public void close() { for(Lot lot : lots) { System.out.println(lot.getNumber() + ": " + lot.getDescription()); // Include any details of a highest bid. Bid highestBid = lot.getHighestBid(); if(highestBid != null) { System.out.println(" Highest bidder: " + highestBid.getBidder().getName()); System.out.println(" Bid: " + highestBid.getValue()); } else { System.out.println(" Not sold"); } } }

    Exercise 4.49

    /** * Returns a list of unsold lots */ public ArrayList getUnsold() { ArrayList unsoldLots = new ArrayList(); for(Lot lot : lots) { Bid highestBid = lot.getHighestBid(); if(highestBid == null) { unsoldLots.add(lot); } } return unsoldLots; }

    Exercise 4.50

    The getLot method assumes that a Lot is stored at location getLotNumber()-1 in its ArrayList. If lots can be removed then index numbers may be changed. The getLot method always checks for consistency so if there is an inconsistency the an error message is printed in the terminal window.

  • Exercise 4.51

    /** * Return the lot with the given number. Return null * if a lot with this number does not exist. * @param number The number of the lot to return. */ public Lot getLot(int number) { Lot lot = null; if(lots.size() > 0) { lot = lots(0); int nextIndex = 1; while(lot.getNumber() != number && nextIndex < lots.size()) { lot = lots.get(nextIndex); nextIndex++; } } if (lot == null || lot.getNumber() != number) { System.out.println("Lot number: " + number + " does not exist."); return null; } else { return lot; } }

    Exercise 4.52

    /** * Remove the lot with the given lot number. * @param number The number of the lot to be removed * @return The Lot with the given number, or null if * there is no such lot. */ public Lot removeLot(int number) { //First we find the lot with the given number Lot lot = getLot(number); if(lot != null) { //Then we can use the method remove with lot as argument lots.remove(lot); } return lot; }

    Exercise 4.53

    LinkedList has these methods that ArrayList does not have:

    void addFirst(E o) void addLast(E o) E getFirst() E getLast() E removeFirst()

  • E removeLast()

    Where E refers to the type of item stored in the list.

    ArrayList has these methods that LinkedList does not have:

    void ensureCapacity(int minCapacity) void trimToSize()

    Exercise 4.54

    /** * Determine the number of members who joined in the * given month * @param month The month we are interested in. * @return The number of members. */ public int joinedInMonth(int month) { int count = 0; if(month < 1 || month > 12) { System.out.println("Month " + month + " out of range. " + "It must be in the range 1 ... 12"); } else { for(Membership member : members) { if(member.getMonth() == month) { count++; } } } return count; }

    Exercise 4.55

    public ArrayList purge(int month, int year) { ArrayList purged = new ArrayList(); if(month < 1 || month > 12) { System.out.println("Month " + month + " out of range. " + "It must be in the range 1 ... 12"); } else { Iterator it = members.iterator(); while(it.hasNext()) { Membership member = it.next(); if(member.getMonth() == month && member.getYear() == year) { // Must use the remove method from the iterator. // Check the documentation for the Iterator // for more info. it.remove(); purged.add(member); }

  • } } return purged; }

    Exercise 4.56

    public void printProductDetails() { for(Product product : stock) { System.out.println(product.toString()); } }

    Exercise 4.57

    public Product findProduct(int id) { for(Product product : stock) { if(product.getID() == id) { return product; } } return null; }

    Exercise 4.58

    public int numberInStock(int id) { Product product = findProduct(id); if(product != null) { return product.getQuantity(); } else { return 0; } }

    Exercise 4.59

    public void delivery(int id, int amount) { Product product = findProduct(id); if(product != null) { product.increaseQuantity(amount); } }

    Exercise 4.60

    /** * Print details of all the products which has stock * levels below the given amount */ public void printLowStockProducts(int upperLimit) { for(Product product : stock) {

  • if(product.getQuantity() < upperLimit) { System.out.println(product.toString()); } } } /** * Add a product to the list. * @param item The item to be added. */ public void addProduct(Product item) { if( ! stock.contains(item)) { stock.add(item); } } /** * Try to find a product in the stock with the given name. * @return The identified product, or null if there is none * with a matching name. */ public Product findProduct(String name) { for(Product product : stock) { if(product.getName().equals(name)) { return product; } } return null; }

    Exercise 4.61

    The busiest time of day: 18

    Exercise 4.62

    Person[] people;

    Exercise 4.63

    boolean[] vacant;

    Exercise 4.65

    int[] counts;

    boolean[] occupied = new boolean[5000];

    Exercise 4.66

    readings = new double[60]; urls = new String[90]; machines = new TicketMachine[5];

  • Exercise 4.67

    None. It only creates an array to hold String objects.

    Exercise 4.68

    The brackets must be square rather than round.

    double[] prices = new double[50]

    Exercise 4.69

    It throws an ArrayIndexOutOfBoundsException: 24

    Exercise 4.70

    /** * Print the hourly counts. * These should have been set with a prior * call to analyzeHourlyData. */ public void printHourlyCounts() { System.out.println("Hr: Count"); int hour = 0; while(hour < hourCounts.length) { System.out.println(hour + ": " + hourCounts[hour]); hour++; } }

    Exercise 4.71

    public void printGreater(double[] marks, double mean) { for(int index = 0; index < marks.length; index++) { if(marks[index] > mean) { System.out.println(marks[index]); } } }

    Exercise 4.72

    /** * Create an object to analyze hourly web accesses. * @param filename The file to be analyzed. */ public LogAnalyzer(String filename) { // Create the array object to hold the hourly // access counts. hourCounts = new int[24]; // Create the reader to obtain the data. reader = new LogfileReader(filename); }

  • Exercise 4.73

    /** * Return the number of accesses recorded in the log file */ public int numberOfAccesses() { int total = 0; // Add the value in each element of hourCounts to total. for(int hourCount : hourCounts) { total = total + hourCount; } return total; }

    Exercise 4.75

    /** * Return the busiest hour of day */ public int busiestHour() { int busiestHour = 0; for(int hour = 1; hour < hourCounts.length; hour++) { if(hourCounts[hour] > hourCounts[busiestHour]) { busiestHour = hour; } } return busiestHour; }

    Exercise 4.76

    /** * Return the quietest hour of day */ public int quietestHour() { int quietestHour = 0; for(int hour = 1; hour < hourCounts.length; hour++) { if(hourCounts[hour] < hourCounts[quietestHour]) { quietestHour = hour; } } return quietestHour; }

    Exercise 4.77

    In the above implementation, it is the first one that is found.

    Exercise 4.78

    /** * Return the two-hour period which is busiest. */ public int busiestTwoHourPeriod() {

  • int busiestPeriod = 0; int busiestPeriodCount = 0; for(int hour = 0; hour < hourCounts.length - 1; hour++) { int periodCount = hourCounts[hour] + hourCounts[hour+1]; if(periodCount > busiestPeriodCount) { busiestPeriod = hour; busiestPeriodCount = periodCount; } } return busiestPeriod; }

    Exercise 4.82

    Reasons for choosing a fixed size array could be:

    Performance is slightly better. Not so good if students are added and removed from time to time.

    Reasons for keeping the dynamically sized list:

    No need to keep track of the current number of students. Good for future enhancements (for instance if we want to have a method to

    remove a student from the list).

    Exercise 4.83

    /** * Show a list of all the files in the collection. */ public void listAllFiles() { for(int i = 0; i < files.size(); i++) { System.out.println(files.get(i)); } }

    Exercise 4.84

    A do-while loop only tests it condition after executing the statements in the loops body at least once. The loop continues to execute while the condition is true, as with the while loop.

    int i = 1; do { System.out.print(i + " "); i++; } while(i

  • body one-too-many times. The do-while loop should be used sparingly, as it is rarely superior to iteration using a while loop.

    /** * Show a list of all the files in the collection. */ public void listAllFiles() { if(files.size() > 0) { // There is at least one file. int i = 0; do { System.out.println(files.get(i)); i++; } while(i < files.size()); } }

    Exercise 4.86

    /** * Find the index of the first file matching the given * search string. * @param searchString The string to match. * @return The index of the first occurrence, or -1 if * no match is found. */ public int findFirst(String searchString) { int index = 0; // Record that we will be searching until a match is found. boolean searching = true; if(files.size() > 0) { // There is at least one to check. do { String filename = files.get(index); if(filename.contains(searchString)) { // A match. We can stop searching. searching = false; } else { // Move on. index++; } } while(searching && index < files.size()); } if(searching) { // We didn't find it. return -1; } else { // Return where it was found. return index; } }

  • Exercise 5.2

    The documentation contains the following sections:

    Overall description of the class: its purpose and how to use it A brief summary of the fields A brief summary of the constructors A brief summary of the methods A detailed description of the fields A detailed description of the constructors A detailed description of the methods

    Exercise 5.3

    Both check whether the string contains their first argument. The single-argument version of the method starts the match at index 0 within the string. The two-argument version starts the match at the position of the second argument. Both return true if there is a match and false otherwise.

    Exercise 5.4

    Yes:

    public boolean endsWith(String suffix)

    Exercise 5.5

    Yes: public int length()

    Exercise 5.7

    Signature: public String trim() Example: String trimmedText = text.trim();

    Exercise 5.8

    add the line:

    input = input.trim();

    to the start() method of SupportSystem

    Exercise 5.9

    add the line:

    input = input.toLowerCase();

  • to the start() method of SupportSystem

    Exercise 5.10

    boolean

    Exercise 5.11

    if(input.equals("bye")) { finished = true; }

    Exercise 5.12

    Package: java.util It generates random numbers

    An instance is created by using one of the two constructors: Random random = new Random(); Random random = new Random(seed);

    To generate a random integer: random.nextInt();

    Exercise 5.13

    Random random = new Random(); random.nextInt();

    Exercise 5.14 import java.util.Random; public class RandomTester { private Random random; // the random number generator public RandomTester() { random = new Random(); } public void printOneRandom() { System.out.println(random.nextInt()); } public void printMultiRandom(int howMany) { for(int i = 0; i < howMany; i++) { printOneRandom(); }

  • } }

    Exercise 5.15 0,1,2,...,99

    Exercise 5.16 public int throwDice() { return random.nextInt(6) + 1; }

    Exercise 5.17 public String getResponse() { int answer = random.nextInt(3); if(answer == 0) { return "yes"; } else if(answer == 1) { return "no"; } else { return "maybe"; } } A more sophisticated alternative would be: public String getResponse() { String[] responses = { "yes", "no", "maybe", }; return responses[random.nextint(responses.length)]; }

    Exercise 5.18 private ArrayList responses; public RandomTester() // constructor { responses = new ArrayList(); responses.add("yes"); responses.add("don't know"); ... } public String getResponse() { return responses.get(random.nextInt(responses.size())); }

    Exercise 5.19 public int getOneRandom(int max)

  • { return random.nextInt(max) + 1; }

    Exercise 5.20 public int getOneRandom(int min, int max) { return random.nextInt(max - min + 1) + min; } public int getOneRandom(int max) { return getOneRandom(1, max); }

    Exercise 5.22

    When you add more responses these also get shown randomly together with the existing ones. This is because the length of the list with responses is used when generating the random number.

    Exercise 5.24

    Methods in HashMap that depend on the type parameters:

    Set entrySet() V get(Object key) Set keySet() V put(K key, V value) void putAll(Map

  • phoneBook.put(name, number); } public String lookupNumber(String name) { return phoneBook.get(name); } }

    Exercise 5.27

    It overwrites the previous value associated with the key.

    Exercise 5.28

    Both values stay in the map. HashMaps only uses the key to distinguish entries - not the values.

    Exercise 5.29

    phoneBook.containsKey("Homer Jay Simpson");

    Exercise 5.30

    It returns null.

    Exercise 5.31 (duplicates 5.25)

    phoneBook.size()

    Exercise 5.32

    Call the keySet method to return the Set of keys, and then iterate over the set.

    for(String name : phoneBook.keySet()) { System.out.println(name); }

    Exercise 5.34

    Similarities between HashSet and ArrayList Both contains a collection of objects It is possible to add objects (with the add method) It is possible to remove objects (with the remove method) Both have a size() Both have provide an iterator() method to go through all the elements

    Differences: In a HashSet each object can only appear once in the set (because it is a Set). In a ArrayList an Object can appear multiple times. An ArrayList is ordered while a HashSet is not ordered.

  • Exercise 5.35

    You can use regular expression to define how a string should be split.

    Some documentation on regular expressions in Java under the Pattern class in the java.util.regex package.

    Exercise 5.36

    String[] words = s.split("[ \t]");

    String[] words = s.split(":");

    Exercise 5.37

    Using HashSet guaranties that there are no duplicate elements, but it does not keep the order of the words.

    Exercise 5.38

    It creates empty strings - which was probably not the intention. to fix it we could do this:

    String[] words = s.split("[ \t]+");

    Exercise 5.39

    import java.util.Arrays; The Arrays class defines various sort methods: public void sortValues(int[] values) { Arrays.sort(values); for(int value : values) { System.out.print(value + " "); } System.out.println(); }

    Exercise 5.40

    See the modified start() method of SupportSystem in: Code 5.6 and the modified generateResponses() in Responder in: Code 5.7

    Exercise 5.43

    The modifications needed to the Responder class in the project tech-support-complete:

    Add a new field:

    private HashMap synonymMap;

  • Initialize it in the constructor:

    synonymMap = new HashMap();

    Add this to the generateResponse method right after the if-block:

    else { //check if it is a synonym String synonym = synonymMap.get(word); if(synonym != null) { return responseMap.get(synonym); } }

    To create an example replace the responseMap.put("crashes","Well....); with: synonymMap.put("crashes", "crash");

    Exercise 5.47

    Keyword examples:

    @author @version @param @return

    These keywords get special attention so they stand out in the documentation.

    Exercise 5.53

    Color.BLUE is used to set the pen color in drawSquare() Color.RED is used in drawWheel()

    Exercise 5.54

    Other colors available in the Color class are BLACK, GREEN, MAGENTA, ORANGE, etc. These are available via both upper-case and lower-case names.

    Exercise 5.56

    Use the clear() method to clear the whole canvas.

    Exercise 5.57

    /** * Draw a triangle on the screen. */ public void drawTriangle() { Pen pen = new Pen(320, 260, myCanvas);

  • pen.setColor(Color.GREEN); triangle(pen); }

    /** * Draw a triangle in the pen's color at the pen's location. */ private void triangle(Pen pen) { for(int i = 0; i < 3; i++) { pen.move(100); pen.turn(120); } }

    Exercise 5.58

    /** * Draw a pentagon on the screen. */ public void drawPentagon() { Pen pen = new Pen(320, 260, myCanvas); pen.setColor(Color.MAGENTA); pentagon(pen); }

    /** * Draw a pentagon in the pen's color at the pen's location. */ private void pentagon(Pen pen) { for(int i = 0; i < 5; i++) { pen.move(100); pen.turn(360 / 5); } }

    Exercise 5.59

    /** * Draw a polygon with the given number of sides. * @param n The number of sides. */ public void drawPolygon(int n) { Pen pen = new Pen(320, 260, myCanvas); pen.setColor(Color.MAGENTA); polygon(pen, n); }

    /** * Draw a polygon with the given number of side * in the pen's color at the pen's location. * @param sides The number of sides. */ private void polygon(Pen pen, int sides) { for(int i = 0; i < sides; i++) {

  • pen.move(100); pen.turn(360 / sides); } }

    Exercise 5.60

    See 05-60-spiral:

    /** * Draw a spiral in the pen's color at the pen's location. */ private void spiral(Pen pen) { // The number of arms. int arms = 63; // The current length of the arm being drawn. int armLength = 3; // How much longer to make each arm. int armIncrement = 2; // Start in the middle. pen.penUp(); Dimension size = myCanvas.getSize(); pen.moveTo(size.width / 2, size.height / 2); // Face downwards. pen.turnTo(90); pen.penDown(); // Draw arms of increasing length. for(int arm = 0; arm < arms; arm++) { pen.move(armLength); pen.turn(90); armLength += armIncrement; } }

    Exercise 5.62

    public void bounce(int numberOfBalls) { int ground = 400; // position of the ground line myCanvas.setVisible(true); // draw the ground myCanvas.drawLine(50, ground, 550, ground); // create and show the balls HashSet balls = new HashSet(); for(int i=0; i < numberOfBalls; i++) { BouncingBall ball = new BouncingBall(50+32*i, 50, 16, Color.blue, ground, myCanvas); balls.add(ball); ball.draw(); } // make them bounce boolean finished = false; while(!finished) {

  • myCanvas.wait(50); // small delay for(BouncingBall ball : balls) { ball.move(); // stop once ball has travelled a certain distance on x axis if(ball.getXPosition() >= 550 + 32*numberOfBalls) { finished = true; } } } for(BouncingBall ball : balls) { ball.erase(); } }

    Exercise 5.63

    HashSet is most suitable, because it guaranties that we only have one of each ball in the collection. The HashMap could be used for this as well, but we do not need a map, so it would be a bad choice.

    Exercise 5.64

    // create and show the balls Random random = new Random(); HashSet balls = new HashSet(); for(int i=0; i < numberOfBalls; i++) { Dimension size = myCanvas.getSize(); int x = random.nextInt((int) size.getWidth()); int y = random.nextInt((int) size.getHeight()); BouncingBall ball = new BouncingBall(x, y, 16, Color.blue, ground, myCanvas); balls.add(ball); ball.draw(); }

    Exercise 5.65+5.66

    Download: 05-65-balls-inabox.zip

    Exercise 5.68

    public static final double TOLERANCE = 0.001;

    private static final int PASS_MARK = 40;

    public static final char HELP_COMMAND = 'h';

    Exercise 5.69

    Five constants are defined. They are used to index the positions of data in an array. It is a good use of constants.

  • Exercise 5.70

    You would only have to modify the values of the constants which are all defined in one place. If these numbers had not been placed in constant fields, but instead used directly, it would have required changes to several different parts of the code.

    Exercise 5.71

    public class NameGenerator { public String generatorStarWarsName(String firstName, String lastName, String mothersMaidenName, String cityOfBirth) { String swFirstName = lastName.substring(0,3) + firstName.substring(0,2); String swLastName = mothersMaidenName.substring(0,2) + cityOfBirth.substring(0,3); return swFirstName + " " + swLastName; } }

    Exercise 5.72

    Strings are immutable and therefore can not be changed. The method that is called does not change the instance 's' but returns a new object with the string in upper case. The correct way to do it is:

    String upperCaseS = s.toUpperCase(); System.out.println(upperCaseS);

    Exercise 5.73

    The variable a and b contains values. When these values are passed as arguments to the method, the values get copied into the variables i1 and i2. So we now have two copies of the values in a and b. In the method, we then swap the values stored in the variables i1 and i2. This has no effect outside the method as i1 and i2 are local variables in the method. After calling the method the variables a and b will still contain the same values as before the method call.

  • Exercise 6.1

    a) What does this application do? "World of Zuul" is a very simple, text based adventure game. Users can walk around some scenery. That's all.

    b) What commands does the game accept? help quit go "somewhere"

    c) What does each command do? help: Gives information about the commands available quit: Exits the game go "somewhere": Goes through the door in the specified direction. Directions can be one of these: north, east, south, and west.

    d) How many rooms are in the scenario? There are 5 rooms.

    e) Draw a map of the existing rooms.

    Exercise 6.2 The descriptions below are taken from the documentation in the source code of the classes Parser: This parser reads user input and tries to interpret it as an "Adventure" command. Every time it is called it reads a line from the terminal and tries to interpret the line as a two-word command. It returns the command as an object of class Command. The parser has a set of known command words. It checks user input against the known commands, and if the input is not one of the known commands, it returns a command object that is marked as an unknown command. Game:

  • This class is the main class of the "World of Zuul" application. To play this game, create an instance of this class and call the "play" method. This main class creates and initializes all the others: it creates all rooms, creates the parser and starts the game. It also evaluates and executes the commands that the parser returns.

    Command: This class holds information about a command that was issued by the user. A command currently consists of two strings: a command word and a second word (for example, if the command was "take map", then the two strings obviously are "take" and "map"). The way this is used is: Commands are already checked for being valid command words. If the user entered an invalid command (a word that is not known) then the command word is . If the command had only one word, then the second word is .

    CommandWords: This class holds an enumeration of all command words known to the game. It is used to recognize commands as they are typed in.

    Room: A "Room" represents one location in the scenery of the game. It is connected to other rooms via exits. The exits are labeled north, east, south, west. For each direction, the room stores a reference to the neighboring room, or null if there is no exit in that direction.

    Exercise 6.5

    Add the method printLocationInfo() from Code 6.2 to the class Game. Then replace the corresponding lines from the method printWelcome() and goRoom() with a call to the method: printLocationInfo()

    Exercise 6.7

    Add this method to the Room class:

    /** * Return a string describing the room's exits, for example * "Exits: north west". */ public String getExitString() { String returnString = "Exits: "; if(northExit != null) { returnString += "north "; } if(eastExit != null) { returnString += "east "; } if(southExit != null) { returnString += "south "; } if(westExit != null) {

  • returnString += "west "; } return returnString; }

    Modify printLocationInfo() in the Game class like this:

    private void printLocationInfo() { System.out.println("You are " + currentRoom.getDescription()); System.out.print(currentRoom.getExitString()); System.out.println(); }

    Exercise 6.8

    See the zuul-better project included on the CD.

    Exercise 6.9

    Taken from the API documentation: Returns a Set view of the keys contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation), the results of the iteration are undefined. The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll, and clear operations. It does not support the add or addAll operations.

    Exercise 6.10

    First, a string called returnString is created with the initial text "Exits: ". We will then add the exits to this string and finally return it. The names of the available exits are added by retrieving the set of keys from the HashMap of exits. We then iterate through the set of keys and in each iteration we add the key of the exit to returnString.

    Exercise 6.11

    See the zuul-better project included on the CD.

    Exercise 6.12

    The objects are: game1:Game -->parser:Parser --> commands:CommandWords -->outside:Room -->theatre:Room -->lab:Room -->office:Room -->pub:Room

  • Exercise 6.13

    The reference from game1:Game to the outside:Room is changed to the new room that we have moved into. If we use the command go east the reference will be to theatre:Room.

    Exercise 6.14

    See page 216 of the fifth edition for the implementation details.

    Exercise 6.15

    private void eat() { System.out.println(You have eaten now and you are not hungry any more): } adding:

    else if(commandWord.equals("eat")) { eat(); }

    to the command-testing statements.

    Exercise 6.17

    No, you don't need to change Game class. The list of commands which are printed out is generated from the array of validCommands, and will therefore automatically include any new commands that have been added to this array.

    Exercise 6.18

    Modify the printHelp() method in Game so the last lines is:

    System.out.println(parser.getCommandList());

    Add the following method to Parser:

    public String getCommandList() { return commands.getCommandList(); }

    And remove the now obsolete showCommands() from Parser (if you implemented this in Exercise 6.16)

    In CommandWords add this method:

    public String getCommandList()

  • { String commandList = ""; for(String command : validCommands) { commandList += command + " "; } return commandList; }

    And remove the now obsolete showCommands() from CommandWords (if you implemented this in Exercise 6.16)

    Exercise 6.19

    Information about the model-view-control (MVC) pattern can be found here: http://www.enode.com/x/markup/tutorial/mvc.html A simple example of a Java program that uses MVC: http://csis.pace.edu/~bergin/mvc/mvcgui.html For more examples of the MVC pattern look at the Java Swing implementation which makes heavy use of the MVC pattern.

    The MVC pattern is related to the discussion in this chapter because it is a pattern that decouples objects into three types of objects: Model objects which represent the data; View objects which handle the display; and Control objects which handle events that modify the View or Model objects. In this chapter we only discussed the separation of View and Model - adding another level of decoupling makes the design even more flexible.

    To apply the MVC pattern to the Zuul game, we need to split the application into a model, view and control. We might do something like this:

    Model: The Game and Room classes represent the model. We might split the Game class into two classes one which represents the model and one which does the rest. The changes we make to the model while playing the game, is to change the game object's reference to the current room. Whenever we change this reference the model should fire an event to all registered listeners (the View).

    View: We should create a new class which handles the view of the model - that is, printing the text to the screen when an update is received from the model.

    Controller: As it is now, the control of the game is done from the Game class in the play() and processCommand(Command command) methods.

    An example of Zuul with the MVC pattern applied can be downloaded here: 06-19-zuul-mvc.zip

    Exercise 6.20

  • See Exercise 6.22. (Although the rooms can hold several items)

    Exercise 6.21

    a) How should the information about an item present in a room be produced? The items are in the rooms, and hence the room should produce the information about items present.

    b) Which class should produce the string describing the item? The Item class should produce the string.

    c) Which class should print the description of the item? The Game class is responsible for printing, and hence should also print the description of an item. It is, however, not necessary to explicitly print the item description in the game class if the description of the room includes the description of the item in the room.

    Exercise 6.22

    Download: 06-22-zuul-with-items.zip

    Exercise 6.23

    Add the command "back" to the CommandWords.

    The rest of the modifications are in the Game class: Add a field:

    private Room previousRoom;

    In processCommand() add:

    else if (commandWord.equals("back")) { goBack(command); }

    Introduce a new method enterRoom, which stores the previousRoom. Update the method goRoom() to use this method.

    /** * Enters the specified room and prints the description. */ private void enterRoom(Room nextRoom) { previousRoom = currentRoom; currentRoom = nextRoom; System.out.println(currentRoom.getLongDescription()); }

  • Add this method:

    /** * Go back to the previous room. */ private void goBack(Command command) { if(command.hasSecondWord()) { System.out.println("Back where?"); return; } if (previousRoom == null) { System.out.println("You have nowhere to go back to!"); } else { enterRoom(previousRoom); } }

    Exercise 6.24

    When a second word is typed after back, it prints an error message: "Go where?"

    Another case of negative testing: When the game is just started, there is no previous room. In the above implementation this is handled by printing a message to the user: "You can't go back to nothing!"

    Exercise 6.25

    If back is typed in twice you end up in the same room as where you were when you typed back the first time. Yes this is sensible, but it might be more useful to be able to go back several steps - see the next exercise.

    Exercise 6.26

    Download: 06-26-zuul-back.zip

    Exercise 6.27

    There are many possible tests for the zuul project. It is important to have both positive and negative tests.

    Some of the tests could be:

    - testing that the rooms are properly connected. - testing that all the commands are recognised and works as expected. - testing the back command as explained in the solution to Exercise 6.24

    Exercise 6.28

    Download: 06-28-zuul-refactored.zip

  • Exercise 6.29 - 6.33

    All the modifications suggested in Exercises 6.29 through 6.33 is implemented in this project:

    Download: 06-33-zuul-with-player.zip

    Exercise 6.35

    Add this in Game.processCommand:

    else if (commandWord == CommandWord.LOOK) { look(); }

    And add this method to Game:

    private void look() { System.out.println(currentRoom.longDescription()); }

    And finally, modify the CommandWord to include the new value LOOK:

    public enum CommandWord { // A value for each command word, plus one for unrecognised // commands. GO, QUIT, HELP, LOOK, UNKNOWN; }

    Oh, and don't forget to specify the text associated with the command in the CommandWords constructor:

    validCommands.put("look", CommandWord.LOOK);

    Exercise 6.36

    Using different command words only requires changes in the CommandWords class.

    Exercise 6.37

    When the command word for help is changed it is NOT changed in the welcome message.

    Exercise 6.38

    public enum Position { TOP, MIDDLE, BOTTOM }

  • Exercise 6.39

    Almost. You also need to add the functionality of it to the Game class. Compared to Exercise 6.35 you have one less class to modify in this exercise.

    Exercise 6.40

    Yes. It is just using the enum itself: CommandWord.HELP. This will return the command string because toString() has been overridden in CommandWord.

    Exercise 6.41

    Download: 06-41-zuul-with-timelimit.zip

    Exercise 6.42

    To implement a trapdoor (one way door), simply remove one of the exits. For instance, you could remove the exit from the pub to the outside by removing this line:

    pub.setExit("east", outside);

    Exercise 6.43

    Download: 06-43-zuul-with-beamer.zip

    Exercise 6.44

    Download: 06-44-zuul-with-doors.zip

    Exercise 6.45

    Download: 06-45-zuul-with-transporter.zip

    Exercise 6.46

    Download: 06-46-zuul-even-better.zip

    Exercise 6.49

    The method signature is:

    static int max(int a, int b);

    Exercise 6.50

    The methods in the Math class are static because they implement mathematical function operations their results do not depend on an object's state and they always return the same results given the same arguments. Therefore we do not need an object with state to use them. It is also more convenient that you do not have to create an object before calling the method.

  • Yes, they could have been instance methods, but that would require that you create an instance of the Math class before you could use the methods. The object would have no useful mutable state, only methods.

    Exercise 6.51

    public static long testLoopTime() { long startTime = System.currentTimeMillis(); for(int i = 1; i

  • { private static int instanceCount = 0; public Test() { instanceCount++; } public Test(String something) { instanceCount++; } public static int numberOfInstances() { return instanceCount; } }

    It is actually possible to avoid the incrementation in each constructor. You can use an initialiser block which is invoked before the constructor call. This is not a structure that is used very often, and you might be best off without telling your students about it. But if someone should ask you about it, here is how it looks:

    public class Test { private static int instanceCount = 0; { instanceCount++; } public Test() { } public Test(String something) { } public static int numberOfInstances() { return instanceCount }

  • Exercises 7.1-7.5

    The functionality tested here should all work correctly.

    Exercise 7.6

    It is possible to give a rating of zero.

    Exercise 7.7

    It is possible to down-vote an item to a negative number of votes.

    Exercise 7.8

    The functionality tested here should work correctly, with the exception of the problem exposed in Exercise 7.9.

    Exercise 7.9

    The findMostHelpfulComment() method fails if there are no comments. There error is a NoSuchElementException.

    Exercise 7.10

    The downVote() method should protect its field from going negative:

    public void downvote() { if(votes > 0) { votes--; } }

    The ratingInvalid() method should correctly test its boundaries:

    private boolean ratingInvalid(int rating) { return rating < 1 || rating > 5; }

    The findMostHelpfulComment() method should not assume that there is at least one comment:

    /** * Return the most helpful comment. The most useful comment is the one with the highest vote * balance. If there are multiple comments with equal highest balance, return any one of * them. * Return null if there are no comments. */ public Comment findMostHelpfulComment() {

  • Comment best = null; if(comment.size() > 0) { Iterator it = comments.iterator(); best = it.next(); while(it.hasNext()) { Comment current = it.next(); if(current.getVoteCount() > best.getVoteCount()) { best = current; } } } return best; } Any change to the code could have knock-on effects on existing code, or introduce additional errors, so it is not safe to assume that previous tests will still be passed.

    Exercise 7.11

    Test Positive or Negative Exercise 7.1 positive Exercise 7.2 positive Exercise 7.3 positive Exercise 7.4 negative Exercise 7.5 positive Exercise 7.6 negative Exercise 7.7 positive and negative (downvoting below zero) Exercise 7.8 positive Exercise 7.9 negative

    Exercise 7.14

    The methods setUp() and tearDown() are created automatically.

    Exercise 7.15

    Start recording. Create a SalesItem object. Call the addComment() method to add a comment. Assert that the result

    should be true. Call the addComment() method again to add a comment use the same author

    name as in the previous comment. Assert that the result should be false. Select the End button to finish the recording.

    Exercise 7.17

    An error diagnostic appears in the lower panel of the Test Results window. The first line is:

    expected: but was:

  • This is followed by a stack-trace which is not particularly informative, but selecting the Show Source button highlights which assertion has failed in the source of the test class.

    Exercise 7.21

    The terminal window shows:

    Testing the addition operation. The result is: 7 Testing the subtraction operation. The result is: 5 All tests passed.

    There is no way to know (just from the test output) that the tests passed, because we only get the test result value. So we should not trust it.

    Exercise 7.22

    Calling testPlus() returns the value 1.

    It is not the same result as was returned by testAll().

    Calling testPlus() one more time returns 7.

    It should always give the same answer.

    According to the source code it should return 7.

    Exercise 7.23

    No.

    Exercise 7.24

    The testMinus() method is similar in structure to the testPlus() method. Making a walk through of testMinus() obviously makes us want to take a closer look at the minus() method. Furthermore we could make a note to check that negative values are handled correctly.

    Exercise 7.25

    Method called displayValue leftOperand previousOperator initial state 0 0 ' ' clear() 0 0 ' ' numberPressed(3) 3 0 ' ' plus() 0 3 '+' numberPressed(4) 4 3 '+' equals() 7 0 '+'

  • Exercise 7.26

    No. The equals() method does not does not explicitly check the value of the previousOperator when it is '-'. Therefore anything other than a '+' sign will result in a subtraction.

    Exercise 7.27

    Method called displayValue leftOperand previousOperator initial state 0 0 ' ' clear() 0 0 ' ' numberPressed(3) 3 0 ' ' plus() 0 3 '+' numberPressed(4) 4 3 '+' equals() 7 0 '+' clear() 0 0 '+'

    It is not in the same state as the previous clear() (the previousOperator differs).

    This could have a big impact on subsequent calls. This is most likely the source of the inconsistent result we saw in Exercise 7.22.

    Exercise 7.28

    Two things has come to our attention while doing the walk through:

    1. equals() does not explicitly test for the '-' value of previousOperator. 2. clear() does not clear all the fields.

    The clear() method should be changed to this:

    public void clear() { displayValue = 0; leftOperand = 0; previousOperator = ' '; }

    The equals() method should be changed to this:

    public void equals() { if(previousOperator == '+') { displayValue = leftOperand + displayValue; } if(previousOperator == '-') { displayValue = leftOperand - displayValue;

  • } else { //do nothing } leftOperand = 0; }

    Exercise 7.29

    Method called displayValue leftOperand previousOperator initial state 0 0 ' ' clear() 0 0 ' ' numberPressed(9) 9 0 ' ' plus() 0 9 '+' numberPressed(1) 1 9 '+' minus() 0 10 '-' numberPressed(4) 4 10 '-' equals() 6 0 '-'

    The result should be 6, which is indeed what is in the displayValue at the end of the walk through.

    Exercise 7.31

    Yes. The output shows the same information as we collected in the table in the previous exercises.

    Exercise 7.33

    Debug statements have to be removed again.

    Debug statements might be less error prone than the manual walk through.

    Debug statements might be easier/faster to do (this is probably subjective)

    Debug statements are easier to use when you need to verify a correction.

    The activity of doing the manual walk through might give a better understanding of the program.

    Exercise 7.35

    See the project from the cd: calculator-full-solution

  • Exercise 7.37

    The bugs in the bricks project are:

    class Brick:

    getSurfaceArea(): side1 should be side2 in sum() getWeight(): 1000 should be 1000.0

    class Pallet:

    getHeight(): % should be * getWeight(): + baseWeight is missing

  • Exercise 8.2

    After creating a comment on the MessagePost object it is also displayed when listing the news feed, even though the MessagePost was added to the news feed before setting the comment.

    This is because the NewsFeed has a reference to the MessagePost object and uses this reference to get the information about the object each time it prints the list. Only one MessagePost object has been created so the NewsFeed must be storing the one that has the comment.

    Exercise 8.4 When the 'extends Item' is removed from the source of the MessagePost class, then the inheritance arrow in the diagram disappears.

    Exercise 8.5

    Yes, it is possible to call inherited methods through the sub-menu called 'inherited from Post'

    Exercise 8.6

    Add the getUserName method to Post: public String getUserName() { return username; } Define printShortSummary in MessagePost: public void printShortSummary() { System.out.println("Message post from " + getUserName()); }

    Exercise 8.7

    First, the Step Into button takes us to the superclass constructor, which on the subsequent Step Into initializes the fields: username, timestamp, likes and comments. Then it returns back to the MessagePost constructor and initializes the last field: message.

    Exercise 8.8

    The EventPost:

    /** * This class stores information about a post in a social network news feed. * The main part of the post consists of a (possibly multi-line) * text message. Other data, such as author and time, are also stored. * * @author Michael Klling and David J. Barnes * @version 0.2 */

  • public class EventPost extends Post { // The type of event. private String eventType; /** * Constructor for objects of class EventPost * @param author The author of the post. * @param eventType The type of event. */ public EventPost(String author, String eventType) { super(author); this.eventType = eventType; } /** * Return the type of event. * * @return The type of event. */ public String getEventType() { return eventType; } }

    Exercise 8.9.

    One possible hierarchy:

    Exercise 8.10

    A touch pad and mouse are both input devices for a computer. They are very similar and they could either have a common superclass (InputDevice) or one could be a superclass of the other.

    Exercise 8.11

  • Argument for a square being a subclass of a rectangle:

    - a square is just a rectangle where the sides are restricted to be of equal length.

    Argument for a rectangle being a subclass of a square:

    - a rectangle is a square that just has an extra attribute: the ratio between the sizes of the width and height

    Argument for neither:

    - a rectangle has two attributes determining its shape and a square has just one.

    If the two attributes of a Rectangle have the same value, is it equivalent to a Square object?

    Exercise 8.12

    a) Which of the following assignments are legal, and why or why not?

    Person p1 = new Student();

    - This is legal because Student is a subclass of Person.

    Person p2 = new PhDStudent();

    - This is legal because PhDStudent is a subclass of Person (because it is a subclass of Student which is subclass of Person)

    PhDStudent phd1 = new Student();

    - This is not legal, because Student is not a subclass of PhDStudent.

    Teacher t1 = new Person();

    - This is not legal because Person is not a subclass of Teacher.

    Student s1 = new PhDStudent();

    - This is legal, because PhDStudent is a subclass of Student.

    b) Assume that the two illegal lines above are changed to:

    PhDStudent phd1; Teacher t1;

    s1 = p1;

    - This is not legal, because erson is not a subclass of Student. The compiler only knows the static type o p1 which is Person - it does not know the dynamic type which is Student.

  • s1 = p2;

    - This is not legal, because a Person is not a subclass of Student (same arguments the previous case).

    p1 = s1;

    - This is legal because Student is a subclass of Person.

    t1 = s1;

    - This is not legal because Student is not a subclass of Teacher.

    s1 = phd1;

    - This is legal because PhDStudent is a subclass of Student.

    phd1 = s1;

    - This is not legal because Student is not a subclass of PhDStudent.

    Exercise 8.14

    Nothing has to change in the NewsFeed class when we add a new Post subclass. This is because the NewsFeed never worries about the actual subclass, but treats all objects as Posts.

    Exercise 8.15

    From the JDK API documentation, the following class hierarchies can be drawn:

  • Exercise 8.16

  • The solution is in: 08-16-lab-classes

    Exercise 8.17

    An example of a class hierarchy of some of the components in a computer. Note that the question refers to a DVD drive rather than a CD drive, but the change is trivial.

    Or maybe this:

  • Exercise 8.18

    The legal statements tells us the following:

    a) m = t This tells us that T is subclass of M

    b) m = x This tells us that X is a subclass of M

    c) o = t This tells us that T is a subclass of O. But T was also a subclass of M, and Java does not allow multiple inheritance. Therefore M must be a subclass of O or vice versa.

    And the illegal statements gives us:

    d) o = m M is not a subclass of O. Hence from c) we have that O is a subclass of M.

    e) o = x X is not a subclass of O

    f) x = o O is not a subclass of X

    From this information we can be sure that the following relations exist:

  • Exercise 8.19

    See the diagram in the solution to exercise 8.15.

  • Exercise 9.1

    The project no longer compiles. The display() method tries to access the private fields of the Post class, which are not accessible from subclasses. This can be corrected by creating accessor methods in Post and calling these from the subclasses.

    If we try to compile after these modifications it still does not work. This time it is in the compilation of the NewsFeed class that fails, because it is trying to invoke the display() method on a variable of type Post. But Post no longer has a method called display() and hence it fails.

    Exercise 9.2

    The display() method in the Post class is never called. If the object is a MessagePost the display() method in the MessagePost class is called. If the object is a PhotoPost the display() method in the PhotoPost class is called. This is because the dynamic types of the items are used.

    Exercise 9.3

    Yes, it behaves as expected by first calling the display() method from the Post class and then calling the display() method in the actual class (dynamic type).

    One problem is that you can't enforce the call