Problem Set 3
due by 11:59 p.m. on Tuesday, February 13rd, 2024
General Guidelines
-
In your work on this and all subsequent problem sets, you may not use any of Java’s built-in collection classes (e.g.,
ArrayList
) unless a problem explicitly states that you may do so. We will be writing and using our own collection classes, and using the built-in classes will keep you from fully learning the key concepts of the course. -
More generally, you may not use any built-in class that we have not covered in lecture. Classes that you may use (unless specifically directed otherwise) include
String
,Character
,Scanner
, andMath
. -
You are welcome to use the
Arrays.toString()
method when testing the methods that your write. However, you may not use this method or any other methods from theArrays
class in the methods themselves unless a problem explicitly states that you may do so. -
You may freely use code from the class website, assigned readings, and lecture notes (unless specifically directed otherwise), as long as you cite the source in your comments. However, you may never use code from anywhere else (e.g., elsewhere on the web, or code obtained from another person). This will be considered plagiarism and penalized accordingly. See our collaboration policies for more details.
-
You should continue to follow the guidelines that we gave you in the prior problem sets
Preliminaries
In your work on this assignment, make sure to abide by the collaboration policies of the course.
If you have questions while working on this assignment, please come to office hours, post them on Piazza, or email instructor.
Make sure to follow the instructions outlined at the end of Part I and Part II when submitting your assignment.
Part I
34 points total
Creating the necessary file
Problems in Part I will be completed in a single PDF file. To create it, you should do the following:
-
Open the template that we have created for these problems in Google Docs: ps3_partI
-
Select File->Make a copy..., and save the copy to your Google Drive using the name
ps3_partI
. -
Add your work to this file.
-
Once you have completed all of these problems, choose File->Download->PDF document, and save the PDF file on your machine. The resulting PDF file (
ps3_partI.pdf
) is the one that you will submit. See the submission guidelines at the end of Part I.
Problem 1: A Temperature
class
12 points total; individual-only
Given the Temperature
class defined here.
-
Consider a potential non-static method named
convert
that takes aString
as parameter and would convert the temperature of aTemperature
object to the temperature in the scale given by theString
. For example, if aTemperature
object stores the temperature 0.0 incelsius
, calling theconvert
method with the inputfahrenheit
would change the temperature value to 32.0. Because the method only needs to change the internals of the called object, it doesn’t need to – and should not! – return a value.-
(1 point) What type of instance method would
convert
be, an accessor or mutator? -
(2 points) Give an appropriate method header for this method, making sure to take into account the fact that the method is non-static. You do not need to define the body of the method.
-
-
Now consider a potential non-static method named
colderThan
that takes anotherTemperature
object and determines if the calledTemperature
object (i.e., the one on which the method is invoked) has a lower temperature than the otherTemperature
object – returningtrue
if the called object has a higher temperature andfalse
otherwise.- (1 point) What type of instance method would
colderThan
be, an accessor or mutator? - (2 points) Give an appropriate method header for this method, making sure to take into account the fact that the method is non-static. You do not need to define the body of the method.
- (1 point) What type of instance method would
-
Consider the following client code — i.e., code from another class that uses a
Temperature
object:Temperature t1 = new Temperature(5.0, "celsius"); System.out.println(t1.temperature +" degrees "+ t1.scale); t1.temperature *= 2; // Make it twice as hot :-)
Because our
Temperature
class employs appropriate encapsulation, this code fragment will not compile.- (2 point) Explain what problems are present in the code fragment that prevent it from compiling.
- (2 points) Rewrite the fragment to eliminate those problems while maintaining the intended functionality of the original version. Don’t make any unnecessary changes.
- (2 points) Implement a
toString
method for theTemperature
class. For exemple, after running the previous code fragment, the statementSystem.out.println(t1);
should print"10.0 degrees celcius"
.
Problem 2: A class that needs your help
8 points total; individual-only
Consider the following class, which is intended to serve as a blueprint for objects that encapsulate two pieces of data: a seat code (A, B, C, D, E, or F) and seat row, which must be an integer number from 1 to 30, inclusive.
public class FlightTicket { // Fields to store seat code and seat row private String seatCode; private int seatRow; // Method to check if the seat is a window seat (A or F) public static boolean isWindowSeat() { return seatCode.equals("A") || seatCode.equals("F"); } }
-
(2 points) The method
isWindowSeat
is supposed to check if the seatCode corresponds to a window seat. However, when we attempt to compile this class, we get error messages that indicate thatisWindowSeat
cannot access the fields. In section 2-1 of your copy ofps3_partI
(see above), explain why the method cannot access the fields, and what change or changes are needed to fix things. (Hint: What is another name for an instance method?) -
(6 points) This class does not employ appropriate encapsulation. In section 2-1 of
ps3_partI
, revise the class to prevent direct access to theFlightTicket
objects while allowing indirect access through appropriate methods. Your revised version should include:- the changes that you proposed above in your answer for 2-1
- whatever steps are needed to prevent direct access to the fields
- accessor methods that can be used to obtain the value of each field
- mutator methods that can be used to change the value of each
field. Attempts to assign an invalid value should produce an
IllegalArgumentException
. - a constructor that takes a
seatCode
and aseatRow
and initializes the fields using those values. Attempts to assign an invalid value should produce anIllegalArgumentException
. Take advantage of the error-checking code that is already present in the mutator methods that you defined for changing the values of the fields.
No other methods are required.
Problem 3: Static vs. non-static
14 points total; individual-only
When designing a blueprint class, we have seen that we can include both static and non-static variables. Static variables (also known as class variables) belong to the class as a whole. Non-static variables (also known as instance variables or fields) belong to individual objects of the class; each object gets its own copy of those variables.
We have also seen that a blueprint class can include both static and non-static methods. A non-static method is required if the method must have access to the fields of a particular called object. However, if a method doesn’t need a called object – i.e., if all of the information that it needs is supplied by its parameters or by the static variables of the class – then we typically make it static. Non-static methods must be called on an object of the class. Static methods may be called on an object of the class, but it is better style to call them using the name of the class instead.
Imagine that we are defining a class called BMI
that will serve as a blueprint for objects that encapsulate the body mass index (BMI) based on height and weight. For example, to create a BMI
object that represents the BMI of a person of height 5.5in and weight 150.0lb, we would write:
BMI b = new BMI(5.5, 150.0);
An initial implementation of this class can be found here.
-
(4 points) Imagine that we want to modify the existing
BMI
class so that eachBMI
object has an associated category — aString
that is either one of the following, according to value returned by thecalculateBMI()
method:"underweight"
, ifcalculateBMI()
< 18.5,"normal"
, if 18.5 <=calculateBMI()
< 25 ,"overweight"
, if 25 <=calculateBMI()
< 30 , or"obese"
, ifcalculateBMI()
>= 30.
In addition, we want to keep track of how many
BMI
objects have been created for each of the four categories. What variables (static and/or non-static) would we need to add to theBMI
class as part of our implementation of these changes?In section 3-1 of
ps3_partI
, we have included a table that you should complete to describe the necessary variables. For each of your proposed variables, you should specify:- its type and name (make it descriptive!)
- whether it will be static or non-static
- a brief description of its purpose, and why it needs to be static or non-static.
As an example, we have filled in the first row of the table to describe the existing
height
field. You should add the descriptions of your proposed new variables. You may not need all of the rows in the table. Create more rows if necessary. -
(4 points) Now let’s say that we want to add a method called
updateBMI
that takes two parameters: the height and the weight of an user.- What type of method should
updateBMI
be — static or non-static? Explain briefly. - Suppose we created a new
BMI
object; however, upon noticing that the object was initialized with inaccurate height and weight values, we opted to revise its fields, potentially resulting in modifications to the constant variables within theBMI
class. In this scenario, when theupdateBMI
method is called, what alterations, if any, will the method need to make to the existing fields stored within the BMI object? Be as specific as possible.
- What type of method should
The remaining sections of this problem consider two other new methods
for the BMI
class – methods that do not involve the BMI’s category.
-
(3 points) Now let’s say that we want to add a method called
computeWHR
, that computes the waist-hip ratio (WHR), used as an indicator or measure of health. It takes two parameters of typedouble
– one calledwaistCircumference
and another calledhipCircumference
– and it returnswaistToHipRatio
as a ratio of waist measurement divided by the hip measurement. For example, a person with 30-inch waist and 38-inch hips has WHR of about 0.79.- What type of method should
computeWHR
be — static or non-static? Explain briefly. - Give an example of how you would call this method from
outside the
BMI
class. If you need aBMI
object to call the method, assume that the variableb
represents that object, and that the object has already been created. However, you should only useb
if doing so is absolutely necessary.
- What type of method should
-
(3 points) Finally, let’s say that we want to add a new method called
loseWeight
. It takes a parameter of typedouble
calledamount
and decreases the weight of aBMI
object by the specified amount.- What type of method should
loseWeight
be — static or non-static? Explain briefly. - Give an example of how you would call this method from
outside the
BMI
class. If you need aBMI
object to call the method, assume that the variableb
represents that object, and that the object has already been created. However, you should only useb
if doing so is absolutely necessary.
- What type of method should
Submitting your work for Part I
Note: There are separate instructions at the end of Part II that you should use when submitting your work for that part of the assignment.
Submit your ps3_partI.pdf
file using these steps:
-
If you still need to create a PDF file, open your
ps3_partI
file on Google Drive, choose File->Download->PDF document, and save the PDF file in yourps3
folder. -
Login to Gradescope by clicking the link in the left-hand navigation bar, and click on the box for CS 112.
-
Click on the name of the assignment (
PS 3: Part I
) in the list of assignments on Gradescope. You should see a pop-up window labeled Submit Assignment. (If you don’t see it, click the Submit or Resubmit button at the bottom of the page.) -
Choose the Submit PDF option, and then click the Select PDF button and find the PDF file that you created. Then click the Upload PDF button.
-
You should see a question outline along with thumbnails of the pages from your uploaded PDF. For each question in the outline:
- Click the title of the question.
- Click the page(s) on which your work for that question can be found.
As you do so, click on the magnifying glass icon for each page and doublecheck that the pages that you see contain the work that you want us to grade.
-
Once you have assigned pages to all of the questions in the question outline, click the Submit button in the lower-right corner of the window. You should see a box saying that your submission was successful.
Important
-
It is your responsibility to ensure that the correct version of every file is on Gradescope before the final deadline. We will not accept any file after the submission window for a given assignment has closed, so please check your submissions carefully using the steps outlined above.
-
If you are unable to access Gradescope and there is enough time to do so, wait an hour or two and then try again. If you are unable to submit and it is close to the deadline, email your homework before the deadline to
cs112-staff@cs.bu.edu
Part II Programming Problems
66 points total
Problem 4: MyArray: A simple class for manipulating a Java Array
66 points total; individual-only
For this problem, write a class named MyArray
that provides a series of instance (i.e. non static)
methods which will allow a client program to manipulate an array of integers.
The class MyArray
will act as a custom data type (i.e. Blueprint class) which you can use
to create objects, each one containing its own array of integers that can be manipulated by calling
the instance methods as defined by the public interface of the class.
Begin by downloading the file: MyArray.java,
which sets-up the skeleton of your class. Note that the MyArray
class should contain the following
data members and each should be inialized with the specified default values provided in the skeleton code:
SENTINEL
, a class level read-only variable used to control user inputDEFAULT_SIZE
, a class level read-only variable used to establish the size (i.e. length) of the array when the object is initialized with theno-arg
constructorLOWER
, a class level read-only variable that represents the smallest possible integer that can be entered by the userUPPER
, a class level read-only variable that represents the largest possible integer that can be entered by the userarr
, an instance variable which reference the array of integersnumElements
, an instance variable to store how many integers the array currently contains
As you can see the no-argument constructor has been provided.
This constructor creates the array of integers and assigns the address of the array to the
data member arr
. It also initializes the data member numElements
to zero,
as no elements have been added to the array.
Important guidelines:
-
The class members must not be changed in any way. You must use the member names as provided or specified.
-
Your methods must have the exact headers that we have specified, or we won’t be able to test them. Note in particular that the case of the letters matters.
-
If you are asked to write a method that returns a value, make sure that it returns the specified value, rather than printing it.
-
You should not use any Java classes that we have not covered in the lecture notes.
-
Make sure to do proper validation where necessary. For example, if an expected argument to a method should be positive do not allow for a negative number, and throw an exception as needed. Additionally, if the method expects a valid reference to an array, throw an appropriate exception if
null
is passed. -
Each of your methods should be preceded by a comment that explains what your methods does and what its inputs are. You should also include a comment at the top of the file.
-
More generally, use good programming style. Use appropriate indentation, select descriptive variable names, insert blank lines between logical parts of your program, and add comments as necessary to explain what your code does. See the coding conventions for more detail.
Add the following data members as instance variables of the class:
sum
, represents the sum of all the elements in the arraymin
, represents the minimum value of all elements in the arraymax
, represents the maximum value of all the elements in the arrayavg
, represents the average of all the elements in the array
These data members should be appropriately initialized in the constructors and updated as necessary.
Implement the following methods:
-
Write a custom constructor that creates an array of integers based on the input argument passed to
n
.______ MyArray( int n ) { .... }
-
Write a custom constructor that creates the object’s array based on the array of integers passed to the method. This constructor should create a new array of integers initialized from the array passed to the method.
______ MyArray( int[] arr ) { .... }
This constructor should initialize all the statistics for the object.
(Hint: This constructor should create a new array that is of the same size (i.e. length) as the array passed, but only includes
the elements of the array passed that are within the specified UPPER
and LOWER
bound.)
- Write a method that prompts the user to enter integer elements
(within the range specified by LOWER and UPPER bound) and
store them into the object’s array. The user may enter up to as many integer values as the array can
hold or less. If the user does not
want to fill all the positions of the array, they can specify end of input by entering the
sentinel
value._______ void inputElements() { .... }
Assuming the length of the array is 20
, and a LOWER and UPPER bound of 10
and 100
respecively, a sample run
of this method is:
Enter up to `20` integers between `10` and `100` inclusive. Enter -999` to end user input: 5 4 3 2 12 19 23 37 -999
Note that this assumes that the array can hold 20
elements. Calling the toString
method on the
object after user input would display the following array of elements:
[12, 19, 23, 37]
If the user enters an integer outside of the specified LOWER
and UPPER
bounds, that element should be
rejected and not included in the array. Likewise, if the user enters more than the number of elements the array can hold,
the remaining elements should not be accepted.
You can assume that each time this method is called, it will add to the elements currently in the array.
(Hint: This method implies that the number of elements in the array does not necessarily have to be the
same as the length of the array. Think of the purpose of the data member numElements
.)
-
Write a class level method to determine if the integer passed to the method is within the bounds as specified by the
class
variables of the class,LOWER
andUPPER
:________ boolean validInput( int num ) { .... }
-
Write a method that creates and returns a String representing the contents of the array.
________ String toString() { .... }
The toString
method should create a proper array
representation of the elements.
For example, if arr
references an array of integers containing the elements:
34
, 88
, 27
, the toString
method should return the following string representation:
[34, 88, 27]
Please note that the string representation should only contain however many elements have
been added to the array (i.e. numElements
).
The empty array is denoted as: []
.
- Write a method that computes the expected statistics of the array, specifically the minimum,
maximum, sum, average of all the elements contained in the array. These statistics
should be stored internally in the object in the corresponding data members.
________ void computeStatistics() { .... }
(Hint: At any given point, the statistcs should accurately reflect the integer elements of the array. This implies that this method needs to be called every time the internals of the array change.)
- Write a method that returns the position of the last occurence of the number passed to the method.
________ int lastIndex(int n) { .... }
If the argument value passed to parameter n
is not currently an integer in the array, the method should return -1
.
- Write a method that allows you to insert a new integer at a specified position within the
current range of elements of the array.
________ boolean insert(int n, int position) { .... }
The method should return true
if the number was inserted in the array. If the position specified is not
within the current range of elements of the array (i.e. 0
to numElements
) or if the array is currently
full and a new element cannot be inserted, then the method should return false
.
Example: Given an array of length 10
that contains 4
elements in positions 0
, 1
, 2
and 3
then,
insert(16, 7);
// is not valid as the position is outside the current range of elementsinsert(16, 0);
// is valid and the resulting range is [16, 12, 14, 11, 27]insert(21, 4);
// is valid and the resulting range is [16, 12, 14, 11, 21, 27]insert(32, 6);
// is valid and the resulting range is [16, 12, 14, 11, 21, 27, 32]
At the end of these three calls to method insert
it is expected that numElements
is 7
.
If an array is empty (i.e. numElements is 0
), the current range of elements is also zero
therefore, a
call to insert into position 0
should be valid.
This method should not create a new array. The new integer should be inserted into the array
currently referenced by arr
.
(Hint: Think carefully about what an insert into the array implies. The physical structure of the array cannot change, therefore what must happen if a value is to be inserted somewhere in the middle of the range of elements without losing any of the existing elements.)
- Write a method to remove the smallest element in the array.
_________ int removeSmallest() { .... }
This method should return the element removed. If no element is removed, the method should return -1. You can
assume that we will not test this method on an array that has multiple smallest
elements.
(Hint: Remember that the physical structure of the array cannot change, therefore we must simulate an element of the array being removed. Think how this can be accomplished.
- Write a method to grow the physical array by some additional size
n
.________ boolean grow(int n) { .... }
This method should grow the length of the array of the object this method is called on by n
positions. This
method must also preserve all the elements that are currently in the array. In other words,
growing the array cannot lose any elements that are currently stored in the array.
(Hint: Remember that the physical structure of the array cannot change, therefore we must simulate growing the array. Think how this can be accomplished.)
- Write a method to shrink the physical array to be exactly the same
length
as the number of elements currently in the array._________ boolean shrink() { .... }
This method should return true
if the array could be decreased in size or false``if the length of the
array is already the same as the number of elements in the array, or if the array is empty (i.e., numElements ==
0`).
(Hint: Remember that the physical structure of the array cannot change, therefore we must simulate shrinking the array. Think how this can be accomplished.)
- Write accessor methods for each of the private data members.
public _________ getSum() { .... } public _________ getMin() { .... } public _________ getMax() { .... } public _________ getAvg() { .... } public ________ getNumElements() { .... } public ________ getArrLength() { // return the current physical size (i.e., length) of the object's array }
(Hint: getter
methods return the value of the data member they are accessing. Think what the return type for
each method should be.
// The following accessor method is needed by the autograder to test the contents of the // the object's array. // // In general, however, it is not good practice to return a reference to an array as // arrays are mutable and therefore can be changed. You do not want external code to be able to // alter the contents of an array that is private to an object. // public _________ getArr() { .... }
-
Write a method named computeHistogram that creates and returns s
string
which is a histogram likeasterisk
reprenstation of the array. Example, assuming aLOWER=1
andUPPER=20
bound that allows the object’s array to contain the following elements:{5, 4, 2, 3, 12}
This method would return a string that if output, would display as follows:
***** **** ** *** ************
Submitting Your Work
Submission Checklist:
- You have read the Java Style Guide (linked on Course page)and followed all guidelines regarding format, layout, spaces, blank lines, and comments;
- ensured that the signature of the methods specified in the assignment have not been changed.
- You have verified that your programs satisfy all the performance tests in the templates;
Submitting your work for Part II
You should submit only the following files:
- MyArray.java
Here are the steps:
-
Click on the name of the assignment in the list of assignments. You should see a pop-up window with a box labeled DRAG & DROP. (If you don’t see it, click the Submit or Resubmit button at the bottom of the page.)
-
Add your files to the box labeled DRAG & DROP. You can either drag and drop the files from their folder into the box, or you can click on the box itself and browse for the files.
-
Click the Upload button.
-
You should see a box saying that your submission was successful. Click the
(x)
button to close that box. -
The autograder will perform some tests on your files. Once it is done, check the results to ensure that the tests were passed. If one or more of the tests did not pass, the name of that test will be in red, and there should be a message describing the failure. Based on those messages, make any necessary changes. Feel free to ask a staff member for help.
Note: You will not see a complete Autograder score when you submit. That is because additional tests for at least some of the problems will be run later, after the final deadline for the submission has passed. For such problems, it is important to realize that passing all of the initial tests does not necessarily mean that you will ultimately get full credit on the problem. You should always run your own tests to convince yourself that the logic of your solutions is correct.
-
If needed, use the Resubmit button at the bottom of the page to resubmit your work. Important: Every time that you make a submission, you should submit all of the files for that Gradescope assignment, even if some of them have not changed since your last submission.
-
Near the top of the page, click on the box labeled Code. Then click on the name of each file to view its contents. Check to make sure that the files contain the code that you want us to grade.
Important
-
It is your responsibility to ensure that the correct version of every file is on Gradescope before the final deadline. We will not accept any file after the submission window for a given assignment has closed, so please check your submissions carefully using the steps outlined above.
-
Make sure to use these exact file names as specified or we will not be able to find your files and grade them.
-
Make sure that you do not try to submit a
.class
file or a file with a~
character at the end of its name. -
If you make any last-minute changes to one of your Java files (e.g., adding additional comments), you should compile and run the file after you make the changes to ensure that it still runs correctly. Even seemingly minor changes can cause your code to become unrunnable.
-
If we are not able to compile your program, you will not receive any credit for that problem submission.