KotlinCS 124 LogoJava
PrevIndexNext
Kotlin
Java
  • Implementing a Map : 04/26/2024

  • Streams : 04/25/2024

  • Generics : 04/24/2024

  • Hashing : 04/23/2024

  • Binary Search : 04/22/2024

  • MP3: Course Ratings : 04/19/2024

  • Quicksort : 04/18/2024

  • Merge Sort : 04/17/2024

  • Sorting Algorithms : 04/16/2024

  • MP Debugging Part 1 : 04/15/2024

  • MP2: Course Activity : 04/12/2024

  • Practice with Recursion : 04/11/2024

  • MP Debugging Part 0 : 04/10/2024

  • MP2: API Client : 04/09/2024

  • MP2: API Server : 04/08/2024

  • Trees and Recursion : 04/05/2024

  • Trees : 04/04/2024

  • Recursion : 04/03/2024

  • MP1: Filtering and Search : 04/02/2024

  • MP1: Loading and Sorting : 04/01/2024

  • Lists Review and Performance : 03/29/2024

  • Linked Lists : 03/28/2024

  • Algorithms and Lists : 03/27/2024

  • Continuing MP0 : 03/26/2024

  • Getting Started with MP0 : 03/25/2024

  • Lambda Expressions : 03/22/2024

  • Anonymous Classes : 03/21/2024

  • Practice with Interfaces : 03/20/2024

  • Implementing Interfaces : 03/19/2024

  • Using Interfaces : 03/18/2024

  • Working with Exceptions : 03/08/2024

  • Throwing Exceptions : 03/07/2024

  • Catching Exceptions : 03/06/2024

  • References and Polymorphism : 03/05/2024

  • References : 03/04/2024

  • Data Modeling 2 : 03/01/2024

  • Equality and Object Copying : 02/29/2024

  • Polymorphism : 02/28/2024

  • Inheritance : 02/27/2024

  • Data Modeling 1 : 02/26/2024

  • Static : 02/23/2024

  • Encapsulation : 02/22/2024

  • Constructors : 02/21/2024

  • Objects, Continued : 02/20/2024

  • Introduction to Objects : 02/19/2024

  • Compilation and Type Inference : 02/16/2024

  • Practice with Collections : 02/15/2024

  • Maps and Sets : 02/14/2024

  • Lists and Type Parameters : 02/13/2024

  • Imports and Libraries : 02/12/2024

  • Multidimensional Arrays : 02/09/2024

  • Practice with Strings : 02/08/2024

  • null : 02/07/2024

  • Algorithms and Strings : 02/06/2024

  • Strings : 02/05/2024

  • Functions and Algorithms : 02/02/2024

  • Practice with Functions : 02/01/2024

  • More About Functions : 01/31/2024

  • Errors and Debugging : 01/30/2024

  • Functions : 01/29/2024

  • Practice with Loops and Algorithms : 01/26/2024

  • Algorithms : 01/25/2024

  • Loops : 01/24/2024

  • Arrays : 01/23/2024

  • Compound Conditionals : 01/22/2024

  • Conditional Expressions and Statements : 01/19/2024

  • Operations on Variables : 01/18/2024

  • Variables and Types : 01/17/2024

  • Welcome to CS 124 : 01/16/2024

Inheritance

public class Pet {
protected String name;
public Pet(String setName) {
name = setName;
}
public String getName() {
return name;
}
}
public class Dog extends Pet {
private String breed;
public Dog(String setName, String setBreed) {
super(setName);
breed = setBreed;
}
public String getBreed() {
return breed;
}
@Override
public String toString() {
return "A dog named " + name + " is a " + breed;
}
}
Dog chuchu = new Dog("Chuchu", "mutt");

Next we begin our exploration of relationships between Java classes. So far the classes that we’ve created have stood alone—or at least we thought. In this lesson we’ll see that all Java classes are related to each other, and how to utilize those connections to reflect real-world relationships and improve our Java code.

Debugging Challenge
Debugging Challenge

But let’s start with some debugging practice!

First, A Puzzle
First, A Puzzle

Let’s begin this lesson with a puzzle:

public class Pet { }
Pet chuchu = new Pet();
System.out.println(chuchu.toString());

If we compile and run this code, we see something printed. Which is… weird! Right? The snippet above uses dot notation to call a method on chuchu called toString. But where is that instance method defined? Do you see it? I don’t! So why does this code work? On some level, this lesson is about figuring that out.

Inheritance
Inheritance

Java allows us to establish relationships between classes. Specifically, Java allows one class to inherit state and behavior by extending another class. Let’s look at an example of this:

// I'm not using encapsulation here for the sake of brevity...
public class Person {
public String name;
}
// Student extends Person and so inherits its state and behavior
public class Student extends Person {
public String level;
}
Student you = new Student();
// This already makes sense to us: Student has an String instance variable named level
// It's declared in the declaration of Student
you.level = "Freshman";
// But where is this instance variable coming from?
// It's inherited from Person!
you.name = "Excellent Student";
System.out.println(you.name + " is a " + you.level);

extends and Inheritance Terminology
extends and Inheritance Terminology

We use the extends keyword to create a relationship between two classes.

This relationship is one way. The terminology that we use here is helpful. We refer to the class that is extended as the parent and the class that extends as the child:

// Person is the parent of Student
public class Person { }
// Student is the child of Person
public class Student extends Person { }

This helps us remember that we cannot create circular class relationships. This won’t compile:

public class One extends Two { }
public class Two extends One { }

We can also establish multiple levels of inheritance. When we do, we use similar family-based terminology:

// Person is the parent of Student and the ancestor of Freshman
public class Person { }
// Student is the child of Person
public class Student extends Person { }
// Freshman is the child of Student and a descendant of Person
public class Freshman extends Student { }
// Sophmore is the child of Student and a descendant of Person
public class Sophmore extends Student { }

super
super

When we extend a class, we need to make sure that our parent class is set up properly when instances of our class are created. For example, consider the class hierarchy below. Whenever an instance of Student is created, we are also creating an instance of Person. So we need to make sure that the Person constructor gets called. Let’s see how to do that:

public class Person {
private String name;
public Person(String setName) {
name = setName;
}
}
public class Student extends Person {
}
Student student = new Student();

public and private
public and private

As a final observation, note that private still works the way that we expect. A class that extends another does not gain access to its private variables:

public class Person {
private String name;
public Person(String setName) {
name = setName;
}
}
public class Student extends Person {
}
Student student = new Student();

Object
Object

However, none of this really resolves our puzzle. We still don’t know why this works:

public class Pet { }
Pet chuchu = new Pet();
System.out.println(chuchu.toString());

Pet doesn’t extend anything. So where is toString coming from?

To fill in the missing piece of the puzzle, we need to meet the class that sits at the top of Java’s class hierarchy, Object:

Practice: Simple Person Inheritance

Created By: Geoffrey Challen
/ Version: 2020.9.0

Create a public class called Student that inherits from a class called Person. (Do not create Person. It is already available.) Define a single public Student constructor that takes a String argument (name) and an int argument (university ID number). You should call the Person constructor and pass that String argument. (You don't need to do anything else with it.) You should also provide a public getter named getID for the student ID. Reject negative ID numbers using assert.

Overriding Inherited Methods
Overriding Inherited Methods

So it’s nice and all that every class will inherit a toString method from Object. But this method really isn’t very useful!

public class Pet { }
Pet chuchu = new Pet();
System.out.println(chuchu.toString());

For example, if my Pet has a String name, I might want to display that instead. Can we do this? Yes! Let’s look at how:

public class Pet {
private String name;
public Pet(String setName) {
name = setName;
}
}
Pet chuchu = new Pet("Chuchu");
System.out.println(chuchu.toString());

We’ll get into this more tomorrow and review exactly how Java locates various method and field names when it compiles your code.

Practice: Score Tracker

Created By: Geoffrey Challen
/ Version: 2021.9.0

Create a public class named ScoreTracker that we'll use to keep track of the scores of two players who are playing a game. Players playing this game always take turns, and Player 1 always plays first. Both players scores start at zero.

Each ScoreTracker should provide a public method score that accepts a number of points and does not return a value. If it is Player 1's turn, the points (which might be negative) get added to their score. Otherwise they get added to Player 2's score.

You should also provide a public method currentlyAhead that returns 1 if Player 1 is ahead, 2 if Player 2 is ahead, and 0 if it's a tie.

You should not expose any of your state publicly, and ScoreTracker does not need to provide a public constructor.

When your class is complete, here is how it should work:

Homework: Rating Tracker

Created By: Geoffrey Challen
/ Version: 2022.9.0

Declare and implement a public class named RatingTracker, which will store and return the average of a set of ratings. RatingTracker should not provide a constructor. It should provide two public methods: addRating and getAverageRating. addRating adds a new rating to the average, accepting a single int value. You should assert that this value is between 0 and 5, inclusive.

getAverageRating accepts no arguments and returns the average of all the ratings seen so far as a double. You should assert that at least one rating has been added before calling getAverageRating.

When your class is completed, here's how it should work:

You should not need to use a loop, array, or list to solve this problem. You may need to cast your values carefully when computing the average.

CS People: Safiya Noble
CS People: Safiya Noble

If you’re like me, you use a search engine constantly. But have you ever stopped to consider where the results come from? The Internet is huge! Without search, most of us would never find our way around. And so what ends up on the first page of results matters. A lot.

Professor and MacArthur Award Winne Safiya Noble has examined how biases infiltrate Google and other search engine results in her seminal book “Algorithms of Oppression”. Listen to her describe some of her work and its broader implications:

More Practice

Need more practice? Head over to the practice page.