588 views
# Lab 2 (CS17/111/112/19): Lists, Access Modifiers, and Equals (Fall 2024) ## Learning Objectives - Practice working with `LinkedList` - Learn how to use access modifiers - Learn how to design around access modifiers - Learn about `equals` methods and how to write them ## Stencil Using this **[GitHub Classroom link](https://classroom.github.com/a/Od0Z60J5)**, accept the assignment and clone on your machine. **[Look here for instructions](https://docs.cs200.io/s/java-stencil-setup-guide#Accepting-an-Assignment-on-GitHub-Classroom)** on how to accept the assignment and open the code in IntelliJ. Refer to the [GitHub guide](https://docs.cs200.io/s/github-guide) if you are unfamiliar with it. Make sure you push your code regularly to back it up! ## Setup For this lab, we will work with a modified version of the `Student`, `Faculty` and `Course` classes from your homework sequence. :::warning ***Note***: You do **NOT** need to copy the work from this lab into your homework. We're just trying some things out starting from the same code. ::: ## Problem Sequence The stencil code gives you initial versions of our key classes, as well as a `Main` class. As we saw in Monday’s lecture, `Main` is the conventional name for the class where you run your program. Here, we are going to use `Main` as a simple way to try out code and print the results. **Task 1:** Grab the stencil code and run the `main` method in the `Main` class (in a week or so, we’ll be able to explain all the parts of the `public static void` line – just accept that it is needed for now). You should see a message print out that reads `"Data setup complete"`. This confirms that you are ready to start the actual lab problems. :::info <details><summary>Read this if you get an error running the Main class (eg. "A JNI error has occurred")</summary> If you have an error running your `Main` class, please try [**these Troubleshooting steps**](https://docs.cs200.io/s/java-stencil-setup-guide#Troubleshooting). In particular, you may need to [Set your project's SDK](https://docs.cs200.io/s/java-stencil-setup-guide#Configure-your-SDK-version) to use the correct Java version. </details> ::: **Task 2:** Draw an environment/heap diagram for the data that has been created so far. For now, draw a list in the heap in the following style: :::info ![a list with two dillos](https://lh5.googleusercontent.com/BObLk0IjHz9qRLyE0i2kXsKDMxpNA9h7yfUupTRtl51FVO9VbCBF01MTEnd9wbLQrN4R9BD2px64vEAHVeFgBYogOzhfB6lJ5WDuIHAGOtV2sfQMjCW87zRVJjX8Ta75BxxbVzKAohP_a1nIV9TOIA) We’ll look at how lists are really drawn in the heap in class starting on Wednesday. </details> ::: :::success ***Checkpoint:*** Have a TA check your work! ::: ## Practice with for loops **Task 3:** Write a method in the `Student` class named `tookCoursesFrom` that returns a `LinkedList<String>` of the names of all `Faculty` that taught a course in the student’s `completed` list. :::info ***Suggestion***: There’s a method already in the `Student` class named `hasCourseFrom` that takes a `Faculty` as an argument and returns a boolean indicating whether the student is currently taking a course from the given faculty member. You can use that method as an example of for-loop syntax. ::: **Task 4:** Uncomment the code in `BLOCK 1` in the `Main/main` method (and run `main`) to make sure that your code is working. ## Wrap up the Semester At the end of the semester, the courses that a student has just finished taking should be moved to the `completed` list within the `Student` class. The `taking` list should also be emptied out so that the student can enroll in new courses. **Task 5:** Write a method `endSemester` in the `Student` class that adds all classes in `taking` to the `completed` list, then resets `taking` to an empty list. **Task 6:** Uncomment the code in `BLOCK 2` in the `Main/main` method (and run `main`) to make sure that your code is working. **Task 7:** Adjust your environment/heap diagram to match what the data look like after `BLOCK 2` completes. :::success ***Checkpoint:*** Have a TA check your work! ::: ## Start a new semester It’s time for a new semester! **Task 8:** Look at the code in `BLOCK 3`. Without running the code, figure out (a) what we probably want the last `println` in that block to produce and (b) what you think that `println` will produce. Work with your environment/heap diagram to justify your reasoning, modifying it to show the result of running `BLOCK 3`. **Task 9:** Uncomment the code in `BLOCK 3` and check your prediction. If your prediction was incorrect, look at the diagram again and try to figure out what happened and why. Try this before reading on. :::info <details> <summary> <b>So, what just happened?</b> </summary> Having a new professor take over a course in a new semester should not change the set of profs who Pedro took courses from previously. The problem is that we have only one `Course` object that is trying to serve as both the past offering and the current offering of the `drumming` class. </details> ::: ## Preserving old data In a world where old data gets permanently changed, we sometimes need to save copies of older versions of data before we make changes. **Task 10:** Write a method named `clone` in the `Course` class that takes no arguments but produces a new `Course` object with the same field values as the `this` object. **Task 11:** Modify your `endSemester` method in the `Student` class to put copies of the courses taken into the `completed` list. Rerun the code and make sure that Pedro’s list of former instructors is now unchanged from before the faculty member teaching `drumming` was changed. **Task 12:** Adjust your environment/heap diagram to match what the data look like after modifying `endSemester` to make copies of `Courses`. :::success ***Checkpoint:*** Have a TA check your work! ::: ## Protecting the Faculty The line `drum.taughtBy = profC` in `BLOCK 3` is a bit worrisome from an OO design perspective. What if the university decides to change how it stores the connections between courses and faculty? Perhaps there won’t be a `taughtBy` field in future versions, but some other data structure to store this information. Were the university to make this change, existing code would break. To make code more reusable, many languages (including Java) have a notion of _access modifiers_, which limit which fields of an object other classes can see. Up until now, we’ve been annotating all methods and fields with `public`, which means all classes can read and write to those fields. The alternative annotation, `private`, will prevent outside classes from seeing those fields. **Task 13:** In the `Course` class, put the annotation `private` in front of `taughtBy`, as follows: private Faculty taughtBy; Once you do this, anywhere in the code where you try to access the `taughtBy` field from outside of the `Course` class will turn red (signaling an error). We need to rework the code to avoid this. :::info <details> <summary> <b><i>Example: </i></b> What do we mean by rework? </summary> You might have the following line in your `Student` class: if (c.taughtBy.equals(f)) Rather than “pull out” `c.taughtBy` so we can work with it in the `Student` class, we make a method inside the `Course` class that does the key work. Here, we’d rewrite this code as: if (c.isTaughtBy(f)) {...} We write the new `isTaughtBy` method in `Course` and give it a faculty member to compare to. The use of `.equals` would move into that method. </details> ::: **Task 14:** Write `isTaughtBy` as outlined above. **Task 15:** Fix the use of `drum.taughtBy = profC` in the `Main` class (`BLOCK 3`) by adding the method `changeProf` to the `Course` class. **Task 16:** Using these two as models, convert any remaining uses of `taughtBy` that are outside the `Course` class into methods within the `Course` class. :::info ***Hint:*** Think about the methods available to you from `Faculty`. ::: :::success ***Checkpoint:*** Have a TA check your work! ::: ## Equality ### Important backround Consider the following two `Courses`: should they be considered the same or not? ```java new Course("drumming", profA) new Course("drumming", profB) ``` Whether you consider these the same depends on context. If we want to know whether a student has taken the `"drumming"` course (say, as a prereq), we probably don’t care who taught it. But if you want to know whether two students took the same course at the same time, we might want these to be different. Java lets you (the programmer) indicate when two objects from the same class should be considered the same. You do this by writing a method called `equals`. This method can choose which fields to consider when comparing two objects. Here, for example is a `.equals` method that compares `Course` objects based only on their names (it would go in the `Course` class): ```java= @Override public boolean equals(Object other) { if (other instanceof Course) { return this.nameNum.equals(((Course) other).nameNum); } else { return false; } } ``` The heart of the method is line 4, which compares the `nameNum` fields of the two objects. The rest of this contains details that Java needs. Specifically: - the input to an `equals` method has to allow any other object (not necessarily one from the same class). The Java type `Object` allows any object. - But if the `other` value is not a `Course`, there is no way that `other` and `this` are equal. Line 3 asks “is `other` an object from the `Course` class?” - Once we are inside the `if` branch on line 4, we as programmers know that `other` must be a `Course` (line 3 checked that). But Java doesn’t know that. The expression `((Course) other)` tells Java "I the programmer know that `other` is a `Course`, so let me access the `nameNum` field. Every class has a default `equals` method that checks whether two objects are at the same location in the heap. You can always override that, however, with code like the above. ### Practice with `equals` **Task 17:** Get familiar with the `equals` method, either by editing it to see what breaks (make the `Object` type into `Course`, take off the `(Course)` before `other`, etc) or by trying to add an `equals` method to the `Student` class that calls two `Student` objects equal if they have the same Student name. You could also add an `id` field to students and add that to the \`equals’ check. :::success ***Checkoff:*** Congratulations! Call over a TA to get credit for completing the lab! ::: *** _Please let us know if you find any mistakes, inconsistencies, or confusing language in this or any other CSCI0200 document by filling out the_ [_anonymous feedback form_](https://forms.gle/8HY7tDdgM98fk2e19)_._