Old version
This is the CS 112 site as it appeared on May 12, 2022.
Problem Set 4 FAQ
If you don’t see your question here, post it on Piazza or come to office hours! See the links in the navigation bar for both of those options.
Part I
-
In problem 1, how can the
Limousine
constructor check for bad values for the inherited fields if it needs to call the superclass constructor on the very first line?When your
Limousine
constructor calls the superclass constructor, that other constructor will take care of the necessary error-checking of the values passed in for the inherited fields, and thus theLimousine
constructor doesn’t need to perform any error-checking on those fields. (Note: TheVehicle
class we have provided doesn’t actually perform any error-checking on things like the make and the model, but you don’t need to try to correct for this failing.)Then, after calling the superclass constructor, the
Limousine
constructor can perform any necessary error-checking on the values for its new fields – the ones that are not inherited. -
In problem 2, it says that
Woo
has a field calledy
, and thatYoo
– which extendsWoo
– has its own field calledy
. Is that a typo?Yes, there was a typo in the original version of the problem! We have changed it so that the name of
Yoo
‘s new field isc
. Sorry for the confusion! -
In problem 3, there are two different calls to the
add
method that both add a string literal"goodbye"
. Will those two strings be represented by the sameString
object in memory, or will there be two separateString
objects?It depends on the compiler.
In many compilers, if a program includes two different string literals that both represent the same string (i.e., that both contain the same sequence of characters), the compiler will use the same
String
object for both of them.However, not all compilers do this. Some of them would use a separate String object for every string literal.
For Problem 3, you may assume that the compiler is taking either approach.
By the way, if two strings are not both string literals (e.g., if one or both of them were read from the console), then they will definitely be represented using two separate
String
objects.
Problem 4
-
In Problem 4, I’m getting an error that says something like “Cannot make a static reference to the non-static method...” Do you know why I would be getting this?
Don’t forget that non-static methods need a calling object – i.e., an object that comes before the dot when you call the method.
When we call a static method from another class, we put the class name before the dot. However, this does not work for non-static methods. For example, you cannot write something like
Card.getValue()
, becausegetValue()
is a non-static method. Instead, you need to do one of the following:- Put a calling object before the dot – the object that you want
to operate on. For example, if
c
is theCard
object whose value you need, you would writec.getValue()
. - If the line you are writing is part of another non-static
method, and the method you are calling will operate on the same
object as the current method, you should use the implicit
parameter to call it:
this.getValue()
.
- Put a calling object before the dot – the object that you want
to operate on. For example, if
-
For Task 2 and/or Task 3, I’m getting an error that says that “
Scanner
cannot be resolved to a type”. What am I doing wrong?You need to import
java.util
at the top of the file. -
When I test my
Player
class on my own machine, it works fine, but I’m failing a Gradescope test for thegetPlay()
method. Do you know why this could be?Make sure that you do not create a new
Scanner
object in yourgetPlay()
method. Instead, as the problem specifies, you must use theScanner
object that is being passed in as a parameter. Failure to do so will cause you to fail our tests. -
For Task 3, I’m having trouble writing the constructor. Do you have any suggestions?
You may find it helpful to look at two of our vehicle classes as a model.
For example, the
Motorcycle
class extends theVehicle
class. And becauseMotorcycle
objects do not have any new fields of their own, theMotorcycle
constructor just needs to call the constructor of the superclass. You will need to take a similar approach in yourComputerPlayer
class.Also, don’t forget that the constructor in the superclass (the
Player
class) takes one parameter. Thus, when you call that constructor at the start of your subclass constructor, you will need to specify a value for that one parameter. -
For Task 3, I have completed a partial implementation of my
ComputerPlayer
class, but I get a compiler error that says “Implicit super constructor Player() is undefined
”. I don’t understand what I’m doing wrong.There are two possible explanations for this error:
-
You haven’t defined a constructor for
ComputerPlayer
yet. As a result, the compiler is trying to create a default constructor that begins with a call to a no-parameter constructor of the superclass. And becausePlayer
doesn’t have a no-parameter contructor, the compiler issues an error. -
You aleady have a constructor for
ComputerPlayer
, but you forgot to begin it with a call to the superclass constructor. If you omit this call, the compiler tries to add a call to a no-parameter constructor of the superclass. And becausePlayer
doesn’t have a no-parameter contructor, the compiler issues an error.
Once you have a
ComputerPlayer
constructor that begins with a call to the superclass constructor, this error should go away. -
-
For Task 3, I’m overriding one of the inherited methods. Inside the method, I’m trying to use one of the inherited fields, but the compiler is giving me an error message. How can I access the field?
Because the inherited field is declared to be
private
in the superclass, you can’t access it directly in the subclass. Instead, you need to use one of the methods provided in the superclass. -
For Task 3, I’ve implemented one of the
ComputerPlayer
methods that overrides the method inherited fromPlayer
class, but it’s not being called when I run the program. Instead, the superclass version of the method is still being called. What am I doing wrong?First, make sure that you have changed the line in the
CardMatch
constructor that creates the computer player (players[1]
), modifying it so that it uses the constructor from your new subclass instead of thePlayer
constructor.If this still doesn’t fix things, check the header of your new method. In order for it to be called, it must have the same parameters as the method inherited from the superclass. That way, you will override the inherited method, and you will be able to take advantage of polymorphism and dynamic binding, as intended.
If you give your new method a different parameter list, the method will not override the inherited method. Rather, it will overload that method, and it will not be called by the code that we have given you.
-
I’ve completed all of the tasks, and my
CardMatch
program doesn’t have any compiler errors, but I’m getting aNullPointerException
when I run the program. Do you have any idea of what might be wrong?Check to see if the one or both of your versions of the
getPlay
method (thePlayer
version and/or theComputerPlayer
version) could be returning a number that doesn’t correspond to an actual card. If so, that would explain the exception that you’re seeing.Also, don’t forget that the backtrace that accompanies the exception tells you the line number of the line that threw the exception.
-
I’ve completed all of the tasks, and my
CardMatch
program compiles, but the program gets stuck in an infinite loop that repeatedly displays the “invalid play...” message. What am I doing wrong?It sounds like your
ComputerPlayer
version of thegetPlay
method has faulty logic and is returning the number of a card that doesn’t match the card at the top of the discard pile. Because ourCardMatch
code repeatedly callsgetPlay
until it gets a valid play, you end up with an infinite loop. -
When I win the game by discarding all of my cards, the computer is still allowed one more play. Is that correct?
This may not be logical, but it is what will happen given the code that we have given you in
CardMatch
! You don’t need to fix it. -
When I try to run my code, I get an error saying that it can’t find one of the other classes – something that looks like this:
Exception in thread "main" java.lang.NoClassDefFoundError: ...
Why is this happening?
This probably means that you haven’t properly followed the instructions in the Getting started section in Problem 4.
In particular, make sure that all of the files are in the same folder, and that you use the File->Open Folder menu option in VS Code to open the folder containing your files. Note that you MUST open the folder and not just open the individual files.
To make sure things are correctly configured, we recommend that you do the following:
-
Use File->Close Folder or File->Close Editor to close any open files in VS Code.
-
Shut down the VS Code program.
-
Make sure that all of your files are in the same folder.
-
Start up VS Code again.
-
Use File->Open Folder to open the folder containing your files.
-
As needed, click on the name of the file that you want to edit from the list of files in the Explorer Pane on the left-hand side of VS Code.
Some other things to check:
-
Make sure that your files do NOT include a package statement at the top. For example, if you see something like this:
package ps4; // remove this!
at the top of a file, you should remove it.
-
Make sure that the only
import
statements at the top of your file are forjava.util.*
. All otherimport
statements should be removed.
-
Problem 5
-
Can we use any methods of the
Arrays
class in our work on this problem?No.
-
For some of the methods that we are being asked to add to the
ArrayBag
class, the problem indicates that we should take full advantage of the existingArrayBag
methods. Can you give an example of what that means?Consider the following
containsAll
method from lecture:public boolean containsAll(ArrayBag other) { if (otherBag == null || otherBag.numItems == 0) { return false; } for (int i = 0; i < other.numItems; i++) { if (! this.contains(other.items[i])) { return false; } } return true; }
This method needs to determine whether all of the items in the
ArrayBag
given by the parameterother
are present in the calledArrayBag
(the one that is given bythis
). As a result, we use afor
loop that processes one item at a time in theother.items
array.To check whether
other.items[i]
is in the calledArrayBag
, we could in theory have used a nested loop that checked each of the items in thethis.items
array. But because the existingcontains
method already performs this operation for us, we simply make the appropriate call to that method!In a similar way, you should take advantage of existing methods when writing your
removeItems
andintersectionWith
methods.