← APE preparation CS Skill Tree

Data abstraction and class design

A class is a decision about what an object remembers, who may change it, and what it can be asked to do. Everything in this area is that one decision seen from a different side: writing a class of your own, building one on top of another, replacing a method you inherited, reaching the part of yourself that the parent owns, and signing a promise that lets somebody else's code use your class without knowing anything about it.

What a class decides

Here is the smallest class worth looking at, and every line of it is a choice somebody made.

public class Student
{
    private String name;
    private double gpa;

    public Student(String name, double gpa)
    {
        if (name == null)
        {
            throw new IllegalArgumentException("name cannot be null");
        }
        this.name = name;
        this.gpa = gpa;
    }

    public String getName()
    {
        return this.name;
    }
}

The fields are private, which means no code outside this file can put a value in them. That is not politeness. It is what makes the rest of the class worth anything: because the only ways in are the ones written here, the class can decide what a valid Student is and actually hold that line. A public field has no door, so nothing can be promised about it by anybody.

There is a getter for the name and no setter, and that absence is also a choice. A student's name does not change after the object is built, so there is a way to read it and no way to write it. If you ever added a setter, it would need the same null check the constructor has, because a guarantee about a field is only as strong as the weakest way into that field.

What a constructor promises

The check sits above both assignments, and the word that matters is "above". If the name is null, the throw happens while the object is still half built, and new hands back nothing at all. So the promise is not "most students have a name". It is: every Student object that exists anywhere in this program passed that check, because there is no other way one could have come into being.

That is the whole job of a constructor. Take the object from the defaults Java handed it, which are null for a reference and 0.0 for a number, to a state you are willing to stand behind, and refuse to finish if you cannot.

What extends gives a child, and what it does not

public class Fern extends Plant

One word, and a Fern is now a kind of Plant. It carries every field and method Plant declares, and it can be used anywhere a Plant is wanted. 2 things do not come with it. Constructors are not inherited, so Fern writes its own and calls the parent's. And private does not open up: a field the parent declared private sits inside every Fern object and is invisible to Fern's code, because private belongs to a class rather than to a family.

Then there is the line that makes the rest of this area work.

Plant p = new Fern("Boston fern");

Two types, 2 jobs. The variable's type decides what you are allowed to call. The object's type decides which body actually runs. Java settles the first while compiling and the second at the moment of the call, by looking at what is really there.

Which method a call reaches

Every class already inherits a toString from Object, and that inherited one prints the class name and a number about where the object sits in memory. Writing your own replaces it for your objects, and Java calls it for you whenever it needs text from an object, inside println and on either side of a +.

Replacing it is worth the 5 minutes on any class. It is on the official list for a better reason than that, though, which is what an override proves you understand. A method in a parent can call a method the parent has no body for, and the call lands in whichever child is really there. That is how 1 method written once in Plant can say cactus goes outside for a cactus and Boston fern stays inside for a fern, while Plant itself has no answer to whether a plant lives indoors.

What an interface promises

An interface is a list of method headers with no bodies. implements signs it, and the compiler holds you to it. In exchange, code that was written against the interface years before your class existed will work on your class.

Comparable is the smallest useful example and the one the official list names. Java knows how to put numbers and strings in order. It does not know how you want your objects arranged, and it will not guess: hand a sort an array of a class that never said, and it throws a ClassCastException at run time. Write compareTo and the same sort works, because the sort asks 1 question of each pair and your method is the answer.

What the department names

The official APE site lists the topics this area covers. Its own words:

Data Abstraction and Class Design

Extending a class

Overriding a method, such as toString

Creating a class

Accessing super class methods and/or fields

Implementing an interface, such as Comparable

Its page of problem areas from previous exams names the cost of not knowing the 2 keywords:

Unfamiliarity with keywords in Java required for basic things like inheritance (extends) and interface use (implements)

Every item on that list has a lesson of its own.

The lessons

Trace these before you go on

Work each one on paper and write the answer down before you open it. If one of them surprises you, start with the lesson it came from.

TraceWho is allowed to look

Plant declares private String name; and a public toString. Fern extends Plant.

  1. Can code inside Fern write this.name = "Boston fern";?
  2. Does a Fern object contain a name field at all?
  3. Inside Plant, a method takes another Plant as a parameter and reads other.name. Does that compile?
Answers

1. No. The compiler says name has private access in Plant. Private belongs to the class that declared it, and Fern is a different class.

2. Yes. The field is in every Fern object. Carrying a field and being allowed to read it are separate questions.

3. Yes. Private is private to the class, not to the object, so code inside Plant can read any Plant's fields, including one it was handed.

TraceThe variable against the object

Plant is abstract and declares isIndoor(). Cactus's isIndoor returns false, and Cactus adds public String spines(). The line is Plant p = new Cactus();.

  1. Does p.isIndoor() compile, and what does it return?
  2. Does p.spines() compile? Is the failure at compile time or at run time?
  3. Does Plant p2 = new Plant("ivy", 5); compile?
Answers

1. It compiles, because the variable's type declares the method, and it returns false, because the object is a Cactus.

2. It does not compile. The failure is at compile time, decided by the variable's type alone, even though the object really does have the method.

3. No. The compiler says Plant is abstract; cannot be instantiated. There is no way to build a plain Plant anywhere in the program.

TraceAn order that lies

A class implements Comparable and its whole compareTo is return this.id - other.id;.

  1. With ids 12345 and 12340, what sign comes back, and is it right?
  2. With this.id equal to Integer.MAX_VALUE and other.id equal to -1, what value comes back, and is it right?
  3. Write the line that has neither problem.
  4. A different class's compareTo returns -9. What does a sort do with the 9?
Answers

1. Positive, and it is right. Small numbers far from the edges of the range subtract without any trouble, which is what makes the habit survive testing.

2. -2147483648. The true answer is 1 more than the largest int, so it wraps around to the most negative one, and the method now claims the largest id in the range comes first. Nothing throws.

3. return Integer.compare(this.id, other.id); It never subtracts, so it cannot overflow.

4. Nothing. Only the sign is read. A negative number means this one comes first and the size of it carries no information at all.

The practice problems

3 worked problems, each with the reasoning, a trace and a drill. Each one uses the same moves as a practice APE problem, on different classes. Start with the lesson behind it if a problem does not click.

What you have marked Not started
Open a problem to start tracking it. Your own marking, saved on this device. It is not a grade.

Where else this is taught on this site

Short pages, 1 idea each, for whichever piece is shaky.

The one thing to keep

A class keeps its fields private so that its own code is the only code that can put a value in them, and the constructor is the door that decides which values get through. extends makes one class a kind of another and hands the child everything except the constructors and the private fields. The variable's type decides what you may call and the object's type decides which body runs, which is what makes an override useful and what lets a parent call a method it has no body for. implements is a promise the compiler checks, and compareTo is the promise that turns your class into something every sort in the library already knows how to arrange.