← Data abstraction CS Skill Tree

An abstract class and 2 subclasses, worked

The lessons behind it are Extending a class, Overriding a method and Reaching the super class.

3 small files, written from their header comments: an abstract parent and 2 classes that extend it.

Your readiness not started

Your own marking on this problem.

The 3 header comments

FileHeader comment
Plant.javaThere will never be an object that is only a Plant. A Plant has a name and a number of days between waterings, and nothing outside Plant may change them. The constructor may be called only by subclasses and by classes in the same package. isIndoor() has no body here. toString() returns the name, then ", water every ", then the number of days, then " days".
Cactus.javaA Cactus is a Plant. It is built with no arguments. Its name is cactus, it is watered every 14 days, and it lives outdoors.
Fern.javaA Fern is a Plant. It is built from a name. It is watered every 3 days and lives indoors. Its toString() returns what Plant's returns, followed by ", keep out of direct sun".

Read each comment phrase by phrase. Each phrase turns into 1 piece of Java.

PhraseJava
never an object that is only a Plantpublic abstract class Plant
nothing outside Plant may change themprivate fields
called only by subclasses and by classes in the same packagea protected constructor
has no body herepublic abstract boolean isIndoor();
is a Plantextends Plant
built with no arguments; its name is cactusa constructor with no parameters that calls super("cactus", 14)
what Plant's returns, followed bysuper.toString() + ...

The 3 files

public abstract class Plant
{
    private String name;
    private int waterDays;

    protected Plant(String name, int waterDays)
    {
        this.name = name;
        this.waterDays = waterDays;
    }

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

    public abstract boolean isIndoor();

    @Override
    public String toString()
    {
        return this.name + ", water every " + this.waterDays + " days";
    }
}
public class Cactus extends Plant
{
    public Cactus()
    {
        super("cactus", 14);
    }

    @Override
    public boolean isIndoor()
    {
        return false;
    }
}
public class Fern extends Plant
{
    public Fern(String name)
    {
        super(name, 3);
    }

    @Override
    public boolean isIndoor()
    {
        return true;
    }

    @Override
    public String toString()
    {
        return super.toString() + ", keep out of direct sun";
    }
}

Trace it once

Plant p1 = new Cactus();
Plant p2 = new Fern("Boston fern");
System.out.println(p1);
System.out.println(p2);
System.out.println(p1.isIndoor());
System.out.println(p2.isIndoor());
System.out.println(p2.getName());
LineBody that runsPrints
println(p1)Plant's toString (Cactus has none)cactus, water every 14 days
println(p2)Fern's toString, which calls Plant'sBoston fern, water every 3 days, keep out of direct sun
p1.isIndoor()Cactus'sfalse
p2.isIndoor()Fern'strue
p2.getName()Plant'sBoston fern

What goes wrong, and what you see

MistakeWhat happens
abstract left off Plant's class linePlant is not abstract and does not override abstract method isIndoor() in Plant
Fern's constructor writes this.name = name; in place of the super callname has private access in Plant, plus the missing-super error in the next row
Fern's constructor has no super callconstructor Plant in class Plant cannot be applied to given types, with required: String,int and found: no arguments
super(3, name), arguments in the wrong orderincompatible types: int cannot be converted to String
Cactus has no isIndoorCactus is not abstract and does not override abstract method isIndoor() in Plant
Fern's toString calls this.toString() in place of super.toString()compiles, then stops with StackOverflowError the first time a fern is printed
a driver writes new Plant("ivy", 5)Plant is abstract; cannot be instantiated

When 2 parameters have the same type, the wrong order compiles and prints the 2 values swapped. Check every super(...) call against the parameter order of the constructor it calls.

Drill

4 questions. Work each one on paper before you tap.

Level-up check

1. Predict the output. Plant p = new Fern("maidenhair"); then System.out.println(p); What prints?

2. Spot the bug. Fern's constructor is written as below. What happens when you compile?

public Fern(String name)
{
    super(3, name);
}

3. The missing body. Someone deletes isIndoor from Cactus and compiles all 3 files. What happens?

4. Who may call the constructor. Plant and Cactus are in a package named garden. A class in another package, which imports garden.* and does not extend Plant, writes new Cactus(). A second line writes new Plant("ivy", 5). Which lines compile?

4 questions. 3 right is a pass.

Write it out

Not scored. Type it from memory, then compare. The box is scratch space and is not saved.

Write itA third subclass

Write Orchid from this comment. An Orchid is a Plant. It is built from a name. It is watered every 7 days and lives indoors. Its toString() returns what Plant's returns, followed by ", mist the leaves".

Your checklist

Tick these when they are true.

Could you write this cold?

Blank file, no notes, 4 hours on a clock, and only the Java API documentation open. Say yes only when that is true. You can take it back at any time.

Rules on the practice APE
  • You change only the lines between //startMethod and //endMethod, and you keep each method header as given.
  • A private helper method or field of your own between the markers is fine.
  • No new imports.

The official site's Basic Strategies page says: You may receive points for compiling code but you WON’T receive points for code that does not compile.

The Inheritance problem in each practice APE uses these moves on its own classes.

Further reading