6.8 Graphics Supplement ■ You can add buttons and icons to applets. ■ In event-driven programming, certain actions—like clicking a button—fire events. The events are received by listeners that perform actions, the details of which depend on the event fired. ■ An action listener is a class that has the phrase implements ActionListener at the end of its heading and defines a method actionPerformed. The method has one parameter of type ActionEvent. ■ You can use the method setVisible to make components, such as labels and buttons, visible or invisible. Exer c i ses 1. Create a class that will bundle together several static methods for tax computations. This class should not have a constructor. Its attributes are basicRate—the basic tax rate as a static double variable that starts at 4 percent luxuryRate—the luxury tax rate as a static double variable that starts at 10 percent Its methods are computeCostBasic(price)—a static method that returns the given price plus the basic tax, rounded to the nearest penny. computeCostLuxury(price)—a static method that returns the given price plus the luxury tax, rounded to the nearest penny. changeBasicRateTo(newRate)—a static method that changes the basic tax rate. changeLuxuryRateTo(newRate)—a static method that changes the luxury tax rate. roundToNearestPenny(price)—a private static method that returns the given price rounded to the nearest penny. For example, if the price is 12.567, the method will return 12.57. 2. Consider a class Time that represents a time of day. It has attributes for the hour and minute. The hour value ranges from 0 to 23, where the range 0 to 11 represents a time before noon. The minute value ranges from 0 to 59. a. Write a default constructor that initializes the time to 0 hours, 0 minutes. b. Write a private method isValid(hour, minute) that returns true if the given hour and minute values are in the appropriate range. c. Write a method setTime(hour, minute) that sets the time if the given values are valid. 473 474 CHAPTER 6 / More About Objects and Methods d. Write another method setTime(hour, minute, isAM) that sets the time if the given values are valid. The given hour should be in the range 1 to 12. The parameter isAm is true if the time is an a.m. time and false otherwise. 3. Write a default constructor and a second constructor for the class RatingScore, as described in Exercise 9 of the previous chapter. 4. Write a constructor for the class ScienceFairProjectRating, as described in Exercise 10 of the previous chapter. Give this constructor three parameters corresponding to the first three attributes that the exercise describes. The constructor should give default values to the other attributes. 5. Consider a class Characteristic that will be used in an online dating service to assess how compatible two people are. Its attributes are description—a string that identifies the characteristic rating this characteristic in another person a. Write a constructor that sets the description of the characteristic to a given string and sets the rating to zero to indicate that it has not yet been determined. b. Write a private method isValid(aRating) that returns true if the given rating is valid, that is, is between 1 and 10. c. Write a method setRating(aRating) that sets the rating to aRating if it is valid. d. Write a method setRating that reads a rating from the keyboard, insisting that the rating supplied by the user be valid. 6. Create a class RoomOccupancy that can be used to record the number of people in the rooms of a building. The class has the attributes numberInRoom—the number of people in a room totalNumber—the total number of people in all rooms as a static variable The class has the following methods: addOneToRoom—adds a person to the room and increases the value of totalNumber removeOneFromRoom—removes a person from the room, ensuring that numberInRoom does not go below zero, and decreases the value of totalNumber as needed getNumber—returns the number of people in the room getTotal—a static method that returns the total number of people 7. Write a program that tests the class RoomOccupancy described in the previous exercise. 6.8 Graphics Supplement 8. Sometimes we would like a class that has just a single unique instance. Create a class Merlin that has one attribute, theWizard, which is static and of type Merlin. The class has only one constructor and two methods, as follows: Merlin—a private constructor. Only this class can invoke this constructor; no other class or program can create an instance of Merlin. summon —a static method that returns theWizard if it is not null ; if theWizard is null, this method creates an instance of Merlin using the private constructor and assigns it to theWizard before returning it. consult—a non-static method that returns the string "Pull the sword from the stone". 9. Create a program that tests the class Merlin described in the previous exercise. toString method to verify that a unique instance has been created. 10. In the previous chapter, Self-Test Question 16 described a class Person to repa string, and an integer age. These variables are name and age, respectively. a. Write a default constructor for Person that sets name to the string "No name yet" and age to zero. b. Write a second constructor for Person that sets name to a given string and age to a given age. c. Write a static method createAdult for Person that returns a special instance of this class. The instance represents a generic adult and has the name "An adult" and the age 21. 11. Create a class Android whose objects have unique data. The class has the following attributes: tag—a static integer that begins at 1 and changes each time an instance is created name—a string that is unique for each instance of this class Android has the following methods: Android —a default constructor that sets the name to "Bob" concatenated with the value of tag . After setting the name, this constructor changes the value of tag by calling the private method changeTag . getName—returns the name portion of the invoking object. isPrime(n)—a private static method that returns true if n is prime—that is, if it is not divisible by any number from 2 to n − 1. changeTag—a private static method that replaces tag with the next prime number larger than the current value of tag. 12. Create a program that tests the class Android described in the previous exercise. 475 476 CHAPTER 6 / More About Objects and Methods PRACTICE PROGRAMS Practice Programs can generally be solved with a short program that directly applies the programming principles presented in this chapter. 1. Modify the definition of the class Species in Listing 5.19 of Chapter 5 by removing the method setSpecies and adding the following methods: eters for the three instance variables, and a default constructor. Be sure that each constructor sets all of the instance variables. set that can reset values: one is the same as the method setSpecies in Listing 5.16, and the other three each reset one of the instance variables. Then write a test program to test all the methods you have added. Finally, repeat Practice Program 1 in Chapter 5, but be sure to use some constructor other than the default constructor when you define new objects of the class Species. 2. Repeat Programming Project 2 in Chapter 5. This time, add the following four constructor methods: one for each instance variable, one with two parameters for the two instance variables, and a default constructor. Be sure that each constructor sets all of the instance variables. Write a driver program to test each of the methods, including each of the four constructors and at least one true and one false case for each of the test methods. Pet from Listing 6.1, write a program to read data for five pets and display the following data: name of smallest pet, name of largest pet, name of oldest pet, name of youngest pet, average weight of the five pets, and average age of the five pets. to initialize the Trivia object with a question and answer. 5. The following class displays a disclaimer every time an instance is created using the default constructor. However, we would like the disclaimer to appear only once when the very first Vehicle object is created. Any future Vehicle objects that are created should display no disclaimer. Modify the code to use a static boolean variable that is initialized to false when it is defined. Once the disclaimer is displayed the variable should be set to true, and an if statement added around the display so the disclaimer is only output if the variable has the value false. This should force the program to display the disclaimer only once. Add a main method and test code to verify that the disclaimer is only displayed once. 6.8 Graphics Supplement public class Vehicle { public Vehicle() { System.out.println(“You should not operate this vehicle under the”); System.out.println(“influence of alcohol!”); } } the user to initialize the name and alcoholic content of the beer. 7. We can improve the Beer class from the previous Practice Program by using principles of information hiding. The instance variable percent holds the percent of alcohol in the beer. If this variable is public then someone might enter the alcohol percentage the wrong way. For example, if the alcohol percentage is 5% then someone might set the variable to 5.0 instead of 0.05 that the program expects. As a result, the program would compute that someone would be legally intoxicated after a miniscule sip of beer. Address this problem by adding or modifying the mutator method, setAlcohol. If the variable that is being set is over 1 then set the alcohol variable to the incoming value divided by 100. Otherwise set the alcohol variable to the incoming value. You should also do this check for the percentage set by the constructor. Test your program by setting the percent alcohol to 5.0 and to 0.05. The results should be unchanged. PROGRAMMING PROJECTS Programming Projects require more problem-solving than Practice Programs and can usually be solved many different ways. Visit www.myprogramminglab.com to complete many of these Programming Projects online and get instant feedback. double. Call the class DoubleOut. Include all the methods from the class DollarFormat in Listing 6.14, all the methods from the class OutputFormat of Self-Test Question 30, and a method called scienceWrite that displays a value of type double using e notation, such as 2.13e–12. (This e notation is also called scientific notation, which explains the method name.) When displayed in e notation, the number should appear with exactly one nonzero digit before the decimal point—unless the number is exactly zero. The method scienceWrite will not advance to the next line. Also add a method called scienceWriteln that is the same as scienceWrite except that it does advance to the next line. All but the last two method definitions can simply be copied from the text (or more easily from the source code for this book that is available on the Web.). Note that you will be overloading the method names write and writeln. 477 478 CHAPTER 6 / More About Objects and Methods Write a driver program to test your method scienceWriteln. This driver program should use a stub for the method scienceWrite. (Note that this means you can write and test scienceWriteln before you even write scienceWrite.) Then write a driver program to test the method scienceWrite. Finally, write a program that is a sort of super driver program that takes a double value as input and then displays it using the two writeln methods and the scienceWriteln 5 for the number of digits after the decimal point when you need to specify such a number. This super driver program should allow the user to repeat this testing with additional numbers of type double until the user is ready to end the program. 2. Write a new class TruncatedDollarFormat that is the same as the class DollarFormat from Listing 6.14, except that it truncates rather than rounds to obtain two digits after the decimal point. When truncating, all digits after the first two are discarded, so 1.229 becomes 1.22, not 1.23. Repeat Programming Project 3 in Chapter 4 using this new class. 3. Complete and fully test the class Time that Exercise 2 describes. Add two more constructors that are analogous to the setTime methods described in Parts c and d of Exercise 2. Also include the following methods: getTime24 returns a string that gives the time in 24-hour notation hhmm. For example, if the hour value is 7 and the minute value is 25, return "0725". If the hour value is 0 and the minute value is 5, return "0005" . If the hour value is 15 and the minute value is 30, return "1530" . getTime12 returns a string that gives the time in 12-hour notation h:mm xx. For example, if the hour value is 7 and the minute value is 25, return "7:25 am". If the hour value is 0 and the minute value is 5, return "12:05 am". If the hour value is 15 and the minute value is 30, return "3:30 pm". 4. Complete and fully test the class Characteristic that Exercise 5 describes. Include the following methods: getDescription—returns the description of this characteristic. getRating—returns the rating of this characteristic. getCompatability(Characteristic otherRating)—returns the com- patibility measure of two matching characteristics, or zero if the descriptions do not match. getCompatibilityMeasure(Characteristic otherRating)—a private method that returns a compatibility measure as a double value using the formula [ m = 1– (r1 – r2)2 81 ] 6.8 Graphics Supplement 479 when both ratings are nonzero; m is zero if either rating is zero. (Recall from Exercise 5 that the constructor sets the rating to zero, indicating that it has not yet been determined.) isMatch(Characteristic otherRating)—a private method that re- turns true if the descriptions match. 5. Write a Java enumeration LetterGrade that represents letter grades A variable to hold a boolean value that is true if the grade is passing. Also, define a constructor that initializes this instance variable, an accessor method isPassing to return its value, and a method toString that returns the grade as a string. Finally, write a program to demonstrate the enumeration. 6. Complete and fully test the class Person that Exercise 10 describes. Include the following additional methods: getName—returns the name of the person as a string. getAge—returns the age of the person. setName(first, last)—sets the name of the person, given a first and last name as strings. setName(name)—sets the name of the person, given the entire name as one string. setAge(age)—sets the age of the person. createToddler—a static method that returns a special instance of the class to represent a toddler. The instance has the name "A toddler" and the age 2. createPreschooler—a static method that returns a special instance of the class to represent a preschooler. The instance has the name "A preschooler" and the age 5. createAdolescent—a static method that returns a special instance of the class to represent an adolescent. The instance has the name "An adolescent" and the age 9. createTeenager—a static method that returns a special instance of the class to represent a teenager. The instance has the name "A teenager" and the age 15. 7. Write a Temperature class that represents temperatures in degrees in both and a character for the scale: either 'C' for Celsius or 'F' for Fahrenheit. The class should have for both the degrees and the scale, and a default constructor. For each of these constructors, assume zero degrees if no value is specified and Celsius if no scale is given. VideoNote Solving a similar problem 480 CHAPTER 6 / More About Objects and Methods from Practice Program 5 of Chapter 3 and round to the nearest tenth of a degree. and one to set both. equal, one to test whether one temperature is greater than another, and one to test whether one temperature is less than another. Write a driver program that tests all the methods. Be sure to invoke each of the constructors, to include at least one true and one false case for each comparison method, and to test at least the following three temperature pairs for equality: 0.0 degrees C and 32.0 degrees F, −40.0 degrees C and −40.0 degrees F, and 100.0 degrees C and 212.0 degrees F. 8. Repeat Programming Project 8 of the previous chapter, but include constructors. VideoNote Solution to Project 9 9. Write and fully test a class that represents rational numbers. A rational number can be represented as the ratio of two integer values, a and b, where b is not zero. The class has attributes for the numerator and denominator of this ratio. The ratio should always be stored in its simplest form. That is, any common factor of a and b should be removed. For example, the rational number 40/12 should be stored as 10/3. The class has the following constructors and methods: and converts the resulting ratio to simplified form. simplify—a private method that converts the rational number to sim- plified form. getGCD(x, y)—a private static method that returns the largest common factor of the two positive integers x and y, that is, their greatest common divisor. For example, the greatest common divisor of 40 and 12 is 4. getValue—returns the rational number as a double value. toString—returns the rational number as a string in the form a/b. 10. Write a program that will record the votes for one of two candidates by using the class VoteRecorder, which you will design and create. Vote Recorder will have static variables to keep track of the total votes for candidates and instance variables to keep track of the votes made by a single person. It will have the following attributes: nameCandidatePresident1—a static string that holds the name of the first candidate for president 6.8 Graphics Supplement nameCandidatePresident2—a static string that holds the name of the second candidate for president nameCandidateVicePresident1—a static string that holds the name of the first candidate for vice president nameCandidateVicePresident2—a static string that holds the name of the second candidate for vice president votesCandidatePresident1—a static integer that holds the number of votes for the first candidate for president votesCandidatePresident2—a static integer that holds the number of votes for the second candidate for president votesCandidateVicePresident1—a static integer that holds the number of votes for the first candidate for vice president votesCandidateVicePresident2—a static integer that holds the number of votes for the second candidate for vice president myVoteForPresident—an integer that holds the vote of a single individual for president (0 for no choice, 1 for the first candidate, and 2 for the second candidate) myVoteForVicePresident—an integer that holds the vote of a single individual for vice president (0 for no choice, 1 for the first candidate, and 2 for the second candidate) In addition to appropriate constructors, VoteRecorder has the following methods: setCandidatesPresident(String name1, String name2)—a static method that sets the names of the two candidates for president setCandidatesVicePresident(String name1, String name2)—a static method that sets the names of the two candidates for vice president resetVotes—a static method that resets the vote counts to zero getCurrentVotePresident—a static method that returns a string with the current total number of votes for both presidential candidates getCurrentVoteVicePresident—a static method that returns a string with the current total number of votes for both vice presidential candidates getAndConfirmVotes votes, confirms them, and then records them getAVote(String name1, String name2)—a private method that returns a vote choice for a single race from an individual (0 for no choice, 1 for the first candidate, and 2 for the second candidate) getVotes—a private method that returns a vote choice for president and vice president from an individual confirmVotes president and vice president, asks whether the voter is happy with these choices, and returns true or false according to a yes-or-no response 481 482 CHAPTER 6 / More About Objects and Methods recordVotes the appropriate static variables Create a program that will conduct an election. The candidates for president are Annie and Bob. The candidates for vice president are John and Vote Recorder object for each voter. After all the voters are done, present the results. 11. Repeat Programming Project 10 from Chapter 5, but include constructors. Graphics 12. Change the applet in Listing 6.24 so that after the button is clicked, the button disappears. The label and the icon should remain visible just as in Listing 6.24. (Hint: This is not a big change.) Graphics labeled Red, White, and Blue. When a button is clicked, the background of the applet changes to the color named on the button. Graphics Light that simulates a simple light. Create one button labeled On/Off. As you click this button, the background color will change between DARK_GRAY and YELLOW. Graphics Give it two buttons labeled Odd and Even. The user must guess whether a secret number is odd or even by clicking one of these buttons. After a guess is made, the applet should display either Congratulations, you are correct! or Sorry, you are wrong. In either case, also display The secret number was sages. The program will have a private instance variable secretNumber of type long that holds the secret number. You will need to set it in the init method using the following line of code: secretNumber = java.util.Calendar.getInstance().getTimeInMillis() % 100; In the actionPerformed method, check which button was pressed and make the appropriate response label visible. After that, make the two buttons invisible (only one guess is allowed) and the label containing the secret number visible. A n s wers to Self - Test Q ues t io n s 1. If a class is named Student, every constructor for this class must also be named Student. 6.8 Graphics Supplement 2. You specify no return type for a constructor, not even void. 3. A default constructor is a constructor without parameters. 4. Classes do not always have a default constructor. If you give no constructor definition for a class, Java will automatically provide a default constructor. However, if you provide one or more constructors of any sort, Java does not provide any constructors for you. So if none of your constructors is a default constructor, the class has no default constructor. 5. yourPet.setPet(correctName, correctAge, correctWeight); 6. The declaration of an instance variable within a class definition has no keyword static, but the declaration of a static variable does use static. Every object of the class has its own instance variables. A class has only one of each static variable, and all objects share that static variable. 7. Yes. 8. Yes. An example is the static variable interestRate in the method setInterestRate in Listing 6.7. 9. No, you cannot reference an instance variable within the definition of a static method, because a static method can be invoked without an object, and so there are no instance variables. 10. Yes. 11. Yes. Note that this means you can reference both static variables and instance variables within a non-static method. 12. It is valid, but a more normal way of doing the same thing is double inches = imensionConverter.convertFeetToInches(2.5); 13. Yes. 14. Yes, you can invoke a non-static method within the definition of a static method, but only if you have an object of the class and use that object in the invocation of the non-static method. 15. Yes. Invoking a static method within the definition of a non-static method requires nothing special. 16. No, because addInterest is not a static method. 17. a. 2; b. 3; c. 2.0; d. 2.0; e. 3.0; f. 3.0; g. A random integer ≥10 and ≤ 19. Note that the first two values are of type long, while the last four values are of type double. 483 484 CHAPTER 6 / More About Objects and Methods 18. approxSpeed = (int)Math.round(speed); Because Math.round returns a value of type long, and you want a value of type int, you must use a type cast. 19. longSpeed = Math.round(speed); Because Math.round returns a value of type long, no type cast is necessary. 20. long. Since one argument is of type long, the result is of type long. 21. The following class and a demonstration program are included in the code that is on the Web. public class CircleCalculator { public static double getArea(double radius) { return Math.PI * radius * radius; } public static double getCircumference(double radius) { return Math.PI * (radius + radius); } } 22. They are all legal. 23. Double.toString(x) 24. Integer.parseInt(s) 25. Integer.parseInt(s.trim()) 26. System.out.println("Largest double is " + Double.MAX_VALUE); System.out.println("Smallest double is " + Double.MIN_VALUE); 27. $7.00 long, rather than variables of type int. Note that, because the method Math.round returns a value of type long, you will not need a type cast in the method writePositive. For example, int allCents = (int)(Math.round(amount * 100)); would become long allCents = Math.round(amount * 100); The variables dollars and cents should also be changed to type long. 6.8 Graphics Supplement 29. This will produce a “Null Pointer Exception” error message. The variables s1 and s2 do not name any objects. The lines Species s1 = null; Species s2 = null; should be changed to Species s1 = new Species(); Species s2 = new Species(); 30. The class OutputFormat is in the file OutputFormat.java included with the source code provided on the Web. We also list it here: public class OutputFormat { /** Displays a number with digitsAfterPoint digits after the decimal point. Rounds any extra digits. Does not advance to the next line after output. */ public static void write(double number, int digitsAfterPoint) { if (number >= 0) writePositive(number, digitsAfterPoint); else { double positiveNumber = -number; System.out.print('-'); writePositive(positiveNumber, digitsAfterPoint); } } //Precondition: number >= 0 //Displays a number with digitsAfterPoint digits after //the decimal point. Rounds any extra digits. private static void writePositive(double number, int digitsAfterPoint) { int mover = (int)(Math.pow(10, digitsAfterPoint)); //1 followed by digitsAfterPoint zeros int allWhole; //number with the decimal point //moved digitsAfterPoint places allWhole = (int)(Math.round(number * mover)); int beforePoint = allWhole / mover; int afterPoint = allWhole % mover; System.out.print(beforePoint); System.out.print('.'); writeFraction(afterPoint, digitsAfterPoint); } 485 486 CHAPTER 6 / More About Objects and Methods //Displays the integer afterPoint with enough zeros //in front to make it digitsAfterPoint digits long. private static void writeFraction(int afterPoint, int digitsAfterPoint) { int n = 1; while (n < digitsAfterPoint) { if (afterPoint < Math.pow(10, n)) System.out.print('0'); n = n + 1; } System.out.print(afterPoint); } /** Displays a number with digitsAfterPoint digits after the decimal point. Rounds any extra digits. Advances to the next line after output. */ public static void writeln(double number, int digitsAfterPoint) { write(number, digitsAfterPoint); System.out.println(); } } 31. Yes, you could use the names print and println, rather than write and writeln, in the class OutputFormat. Java would have no name confusion with System.out.println, because when you invoke a method in OutputFormat, you specify the class name before the dot. (If you invoke the method with an object instead of the class name, Java still knows the class name because it knows the type of the object.) However, the methods in OutputFormat behave a little differently from the method System.out. println, so using a different name would be clearer to people. 32. Yes, the 7 would be converted to 7.0 by Java so that the types would match the heading of the constructor having three parameters. 33. No, you cannot overload a method name on the basis of return type. These two methods have the same signatures. 34. Yes, they differ in the type of their parameter, so this is a valid overloading of the method name convertValue. The fact that the methods return values of different types does not affect whether or not both definitions can be used. Only the types of the parameters matter in making overloading valid in this case. 35. Yes, it would be valid because no other method named setSpecies has the same number and types of parameters. The definition follows: 6.8 Graphics Supplement public void setSpecies(String newName) { name = newName; population = 0; growthRate = 0; } 36. Yes, it would be valid because no other method named setSpecies has the same number and types of parameters. The definition follows: public void setSpecies(String newName) { name = newName; } 37. No; if you add both of these new methods setSpecies, the class will have two definitions of this method that have the same number and types of parameters. That is, both methods have the same signature. 38. Simply delete all occurrences of this from the definition. 39. Add an invocation of the method trim. The rewritten version follows public void set(String amountString) { String dollarsString; String centsString; amountString = amountString.trim(); <The rest of the method definition is the same as in Listing 6.16.> 40. public String getNameOfFirst() { return first.getName(); } public int getAgeOfFirst() { return first.getAge(); } public double getWeightOrFirst() { return first.getWeight(); } 41. a. b. c. d. e. f. g. 3 false A positive integer Suit.CLUBS Suit.SPADES "black" "spades" 487 488 CHAPTER 6 / More About Objects and Methods 42. import mypackages.library1.*; 43. You must make the following the first instruction line in the file, ignoring blank lines and comments: package mypackages.library1; 44. A package name must be a path name for the directory that contains the classes in the package, but the package name uses dots in place of slashes. When naming the package, you use a relative path name that starts from any directory named in the setting of the class path (environment) variable. 45. The way to do this depends a little on your operating system and on your personal preferences. Here is an outline of what you should do: Choose a package name and insert the following at the start of the file Pet.java: package Package_Name; Compile the modified file Pet.java. Place both of the files Pet.java and Pet.class into the directory corresponding to Package_Name. 46. You may name the content pane anything you wish, other than a keyword. So the following is perfectly legal: Container insideOfApplet = getContentPane(); Of course, if you make this change, you must replace contentPane with insideOfApplet wherever else it occurs in the method actionPerformed. 47. When we say that an event is “sent” to a listener object, what we really mean is that some method in the listener object is invoked and given the event object as the argument. This invocation happens automatically. Your applet class definition will not normally contain an invocation of this method. 48. It would have no effect on the program, as long as you also replace e with buttonEvent wherever else e occurs in the method actionPerformed. The e is a parameter for the method, and we can use any non-keyword identifier as the parameter. 49. Change the code JButton cloudyButton = new JButton("Cloudy"); contentPane.add(cloudyButton); cloudyButton.addActionListener(this); to the following: JButton cloudyButton = new JButton("Cloudy"); ImageIcon nastyFaceIcon = new ImageIcon("nasty.gif"); 6.8 Graphics Supplement cloudyButton.setIcon(nastyFaceIcon); contentPane.add(cloudyButton); cloudyButton.addActionListener(this); The complete applet code is in the file ButtonIconDemo2.java included with the source code for this book that is available on the Web. e must be included in the method heading but need not be used in the method body. 51. The listener, which is the applet itself, is listening to only one button, so it need not decide which button was clicked. There is only one button and hence only one action. 52. Take the following three steps: aButton.setVisible(false); as the last one in the definition of the method actionPerformed. aButton a private instance variable by adding the statement private JButton aButton; JButton from the statement that creates aButton. 489