CS 112
Spring 2022

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

  1. 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 the Limousine constructor doesn’t need to perform any error-checking on those fields. (Note: The Vehicle 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.

  2. In problem 2, it says that Woo has a field called y, and that Yoo – which extends Woo – has its own field called y. 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 is c. Sorry for the confusion!

  3. 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 same String object in memory, or will there be two separate String 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

  1. 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(), because getValue() 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 the Card object whose value you need, you would write c.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().
  2. 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.

  3. When I test my Player class on my own machine, it works fine, but I’m failing a Gradescope test for the getPlay() method. Do you know why this could be?

    Make sure that you do not create a new Scanner object in your getPlay() method. Instead, as the problem specifies, you must use the Scanner object that is being passed in as a parameter. Failure to do so will cause you to fail our tests.

  4. 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 the Vehicle class. And because Motorcycle objects do not have any new fields of their own, the Motorcycle constructor just needs to call the constructor of the superclass. You will need to take a similar approach in your ComputerPlayer class.

    Also, don’t forget that the constructor in the superclass (thePlayer 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.

  5. 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 because Player 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 because Player 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.

  6. 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.

  7. For Task 3, I’ve implemented one of the ComputerPlayer methods that overrides the method inherited from Player 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 the Player 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.

  8. I’ve completed all of the tasks, and my CardMatch program doesn’t have any compiler errors, but I’m getting a NullPointerException 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 (the Player version and/or the ComputerPlayer 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.

  9. 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 the getPlay 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 calls getPlay until it gets a valid play, you end up with an infinite loop.

  10. 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.

  11. 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:

    1. Use File->Close Folder or File->Close Editor to close any open files in VS Code.

    2. Shut down the VS Code program.

    3. Make sure that all of your files are in the same folder.

    4. Start up VS Code again.

    5. Use File->Open Folder to open the folder containing your files.

    6. 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 for java.util.*. All other import statements should be removed.

Problem 5

  1. Can we use any methods of the Arrays class in our work on this problem?

    No.

  2. 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 existing ArrayBag 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 parameter other are present in the called ArrayBag (the one that is given by this). As a result, we use a for loop that processes one item at a time in the other.items array.

    To check whether other.items[i] is in the called ArrayBag, we could in theory have used a nested loop that checked each of the items in the this.items array. But because the existing contains 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 and intersectionWith methods.