Hands-on Programming Exercises — Ch. 11 & Liang
Animal class with fields name (String) and age (int), a constructor, and a method makeSound() that prints "Animal sound". Create a Dog class that extends Animal, adds a breed field, calls super(name, age) in its constructor, and overrides makeSound() to print "Woof!". In main, create a Dog and call both its own method and verify it has the Animal fields.Animal(String name, int age) { this.name = name; this.age = age; }. Dog: class Dog extends Animal { String breed; Dog(String name, int age, String breed) { super(name, age); this.breed = breed; } }. Override: add @Override then public void makeSound() { System.out.println("Woof!"); }.super() call ensures the parent class sets up its own fields properly before the child adds its own. Skipping it (when no no-arg constructor exists) causes a compile error.Person class with name (String) and age (int), a constructor, and a display() method that prints "Person: [name], Age: [age]". Create an Employee class that extends Person, adds jobTitle (String) and salary (double), uses super(name, age), and overrides display() to print the person info plus job and salary. In main, test both classes.Employee(String name, int age, String jobTitle, double salary) { super(name, age); this.jobTitle = jobTitle; this.salary = salary; }. Override display: @Override public void display() { super.display(); System.out.println("Job: " + jobTitle + ", Salary: " + salary); }.super.describe() lets you include the parent's output before adding child-specific details — avoiding code duplication.Vehicle class with brand (String) and speed (int), a constructor, and a describe() method that prints "Vehicle: [brand], Max Speed: [speed] km/h". Create a Car class that extends Vehicle, adds numDoors (int), and overrides describe() — calling super.describe() first, then printing "Doors: [numDoors]". Test in main.@Override public void describe() { super.describe(); System.out.println("Doors: " + numDoors); }. The super.describe() must come before any Car-specific printing so the output order matches exactly.Shape provides a default implementation (returning 0), while each subclass overrides it with the correct formula. The @Override annotation lets the compiler catch signature mistakes.Shape class with a color field (String), a constructor, and two methods getArea() and getPerimeter() — both return 0.0. Create a Rectangle class that extends Shape, adds width and height (double), and uses @Override to implement both methods correctly. Print results in main.Rectangle(String color, double width, double height) { super(color); this.width = width; this.height = height; }. Override: @Override public double getArea() { return width * height; } and @Override public double getPerimeter() { return 2 * (width + height); }.protected — not private — so that specialized subclasses (like SavingsAccount) can access it directly without going through getters. External code still can't touch it. This is the key role of protected in inheritance.BankAccount class with a protected field balance (double), a constructor, and a deposit(double amount) method that adds to balance, plus a getBalance() getter. Create a SavingsAccount that extends BankAccount, adds an interestRate (double), and has an applyInterest() method that directly uses balance += balance * interestRate. Test in main.protected double balance;. applyInterest: public void applyInterest() { balance += balance * interestRate; }. Note: this works because balance is protected, not private. If it were private, you'd need setBalance(getBalance() + ...).toString() from Object, but the default output is a cryptic memory address like Book@1b6d3586. Overriding it makes objects human-readable — System.out.println(book) automatically calls your version.Book class with private fields title (String), author (String), and pages (int). Add a constructor and override toString() from Object to return "Book[title=..., author=..., pages=...]". In main, create two books and print them directly with System.out.println() — Java calls toString() automatically.@Override public String toString() { return "Book[title=" + title + ", author=" + author + ", pages=" + pages + "]"; }. Since fields are private, you can access them directly inside the class. System.out.println(b1) automatically calls b1.toString().equals() from Object compares references (memory addresses), not content. Two separate Point(1, 2) objects will be "not equal" by default even though they represent the same coordinates. Overriding equals() fixes this by comparing field values.Point class with fields x and y (int). Add a constructor. Override equals(Object obj): first check if obj instanceof Point, then cast and compare x and y values. Also override toString() to return "Point(x, y)". In main, compare points using both == and .equals().@Override public boolean equals(Object obj) { if (obj instanceof Point) { Point other = (Point) obj; return this.x == other.x && this.y == other.y; } return false; }. The instanceof check prevents a ClassCastException if a non-Point is passed.Calculator class with an overloaded add() method: one takes two ints, another takes three ints, and a third takes two doubles. Also add a multiply(int a, int b) that returns a * b. Create SmartCalc that extends Calculator and overrides multiply(int a, int b) to print a message before returning the result. Test both in main.int add(int a, int b), int add(int a, int b, int c), double add(double a, double b) — same name, different parameters = overloading. SmartCalc: @Override public int multiply(int a, int b) { System.out.println("[Smart] Multiplying " + a + " x " + b); return a * b; } — same signature in subclass = overriding.Animal → Mammal → Dog. When you create a Dog, Java first calls Animal(), then Mammal(), then Dog() — building from the top down. At the bottom, Dog has access to everything defined in all three levels.name, alive=true; method: breathe() prints "[name] is breathing"), Mammal extends Animal (adds furColor; method: nurse() prints "[name] is nursing young"), and Dog extends Mammal (adds breed; overrides method makeSound() printing "Woof! I am [name]"). In main, create one Dog and call all three methods.Mammal(String name, String furColor) { super(name); this.furColor = furColor; }. Dog: Dog(String name, String furColor, String breed) { super(name, furColor); this.breed = breed; }. Each level passes its relevant args up. Dog inherits breathe() from Animal and nurse() from Mammal — no need to rewrite them.