Skip to the content.
Introduction to Inheritance 9.1/9.2 9.3/9.4 9.5 9.6 9.7 Hacks

Hacks

Hacks Menu

DevOps

9.1 Hacks

  • Implement two new subclasses, Circle and Hexagon, extending from the Shape class. Each shape should have a method to calculate its area and should override the print_something() method to print something unique for that shape. Follow the same structure as the Rectangle and Triangle classes!

  • Optional!
  • Create a new subclass called Ellipse that extends Shape. Update Your Driver Code

  • Constructor: Implement a constructor for Ellipse that accepts parameters for name, length, and width. This constructor should call the superclass constructor using super().

  • Test the Ellipse: Instantiate an Ellipse object and print its area. Verify that the constructor correctly initializes the shape and that the super() keyword is used properly. Hints:

  • Ellipse Constructor: Use super(name, length, width) to initialize inherited fields. Check Order: Remember, super() must be the first statement in your subclass constructor.

9.3 Hacks

  • When overriding the area method for both the Ellipse and the Hexagon use the @Override notation.
  • For the area of the hexagon it may be useful to look into the hexagon area formula:

Area = (3√3 / 2) * s²

  • Also override the calc_perimeter() method for both shapes.
  • use the super keyword to have both shaps use both the parent print_something() and child print_something() method Both shapes should print out something along the lines of: “This is a shape and also a hexagon”

9.5 Hacks

Let’s implement the Triangle subclass to deepen your understanding. Below is a half-completed method for the Triangle class. Your task is to complete the draw method. Make sure your implementation returns a unique string for the Triangle class. This exercise will help reinforce how subclasses can extend functionality.

Advanced Challenge: Area Calculation

Now, let’s enhance our Shape class to include an area calculation feature. Modify the Shape class to include an area method, and implement it in your subclasses. Below is a structure to help you get started: Ensure each subclass calculates and returns its area correctly. This will allow you to practice method overriding further and understand how different shapes can extend base functionalities.

Homework Hack

For your homework, create your own class hierarchy for shapes. You should have a base class called Shape with subclasses Triangle, Rectangle, and Hexagon. Each subclass should implement a method called draw(), returning a unique string for each shape type.

- `Triangle`: "Drawing a triangle."

- `Rectangle`: "Drawing a rectangle."

- `Hexagon`: "Drawing a hexagon."

Make sure to demonstrate polymorphism by creating an array of Shape types and iterating through it to call the draw() method. This will reinforce your understanding of class hierarchies and method overriding.

public class Shape {
    protected String name;
    private int length;
    private int width;

    // Default constructor
    public Shape() {
        this.name = "Shape";
        this.length = 10;
        this.width = 5;
    }

    // Parameterized constructor
    public Shape(String name, int length, int width) {
        this.name = name;
        this.length = length;
        this.width = width;
    }

    // Getter methods
    public String get_name() {
        return this.name;
    }

    public int get_length() {
        return this.length;
    }

    public int get_width() {
        return this.width;
    }

    // Setter methods
    public void set_name(String n) {
        this.name = n;
    }

    public void set_length(int a) {
        this.length = a;
    }

    public void set_width(int b) {
        this.width = b;
    }

    // Method to calculate the area
    public double calc_area() {
        return this.length * this.width;
    }

    // Method to print the shape
    public void print_shape() {
        System.out.println("Shape: " + this.name);
    }

    // Additional method to print something
    public void print_something() {
        System.out.println("This is a shape");
    }
}

public class Rectangle extends Shape {
    public Rectangle() {
        super();
    }

    public Rectangle(String name, int length, int width) {
        super(name, length, width);
    }

    @Override
    public double calc_area() {
        return (this.get_length() * this.get_width());
    }

    @Override
    public void print_something() {
        System.out.println("This is a rectangle");
    }
}

public class Triangle extends Shape {
    public Triangle() {
        super();
    }

    public Triangle(String name, int length, int width) {
        super(name, length, width);
    }

    @Override
    public double calc_area() {
        return (get_length() * get_width() * 0.5);
    }
}

public class Driver {
    public static void main(String[] args) {
        Shape s1 = new Shape();
        Shape s2 = new Rectangle("rectangle", 4, 10);
        Shape s3 = new Triangle("triangle", 5, 20);

        System.out.println("Area of s1 = " + s1.calc_area());
        System.out.println("Area of s2 = " + s2.calc_area());
        System.out.println("Area of s3 = " + s3.calc_area());

        s1.print_shape();
        s2.print_shape();

        // Using the overridden method
        s1.print_something();
        s2.print_something();
    }
}

// Run the driver code
Driver.main(new String[0]);

9.6 Hacks

  • using a previous example of inheritance create an example of polymorphsim, or create an example of polymorphic behavhoir between two classes of Shape and Sqaure
  • Using the previous polymorphism popcorn hack, explain which parts are static and dynamic data types and when that is the case
  • Define Down-Casting in your own words
  • using the previous polymorphism example add an example of down-casting.

Static vs. Dynamic Data Types in Polymorphism Static (Compile-time) Type: This is the type of the reference variable. For example, Shape mySquare has a static type of Shape.

Dynamic (Run-time) Type: This is the actual type of the object that the reference variable points to. In the case of Shape mySquare = new Square(), the dynamic type is Square.

In the example above:

mySquare has a static type of Shape, but its dynamic type is Square. At compile time, Java checks that mySquare can call methods defined in Shape, but at runtime, the actual method invoked is the draw() method of Square.

Definition of Down-Casting Down-casting is the process of casting a reference variable from a parent class type to a child class type. This is typically used when we want to access members specific to the child class that are not available in the parent class. It’s necessary to ensure that the object being cast is actually an instance of the child class, or else a ClassCastException will be thrown.

9.7 Hacks

  • Create an class where you execute an unchanged method from Object, then execute a different method from Object that you changed.

FRQ Prompt

Consider a program that manages a collection of books, specifically focusing on textbooks. You are required to implement a class named Textbook that extends an existing class called Book. The Textbook class should include the following features:

  1. A private integer field named edition that represents the edition number of the textbook.
  2. A constructor that takes three parameters: a string for the title, a double for the price, and an integer for the edition. This constructor should invoke the superclass constructor to initialize the title and price.
  3. A method getEdition() that returns the edition of the textbook.
  4. A method canSubstituteFor(Textbook other) that determines if the current textbook can be substituted for another textbook. This method should return true if both textbooks have the same title and the current textbook’s edition is equal to or greater than the other textbook’s edition.
  5. An overridden method getBookInfo() that returns a string representation of the textbook information, including the title, price, and edition.
  6. Optional: Include error handling in the constructor to ensure that the edition is a positive integer, and override the toString() method for convenient output of the textbook information.

Write the complete implementation of the Textbook class, including all specified methods and any additional features you believe would be beneficial.

// Assuming the existence of a Book class
class Book {
    private String title;
    private double price;
    
    // Constructor for the Book class
    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }
    
    // Getter for title
    public String getTitle() {
        return title;
    }

    // Getter for price
    public double getPrice() {
        return price;
    }

    // A method to get book info (to be overridden by subclasses)
    public String getBookInfo() {
        return "Title: " + title + ", Price: $" + price;
    }
}

public class Textbook extends Book {
    // Private field for edition
    private int edition;

    // Constructor for Textbook, invokes the superclass constructor
    public Textbook(String title, double price, int edition) {
        super(title, price);
        // Optional error handling for edition
        if (edition <= 0) {
            throw new IllegalArgumentException("Edition must be a positive integer.");
        }
        this.edition = edition;
    }

    // Method to get the edition of the textbook
    public int getEdition() {
        return edition;
    }

    // Method to check if this textbook can substitute for another textbook
    public boolean canSubstituteFor(Textbook other) {
        // Checks if titles are the same and if the current edition is greater than or equal to the other edition
        return this.getTitle().equals(other.getTitle()) && this.edition >= other.getEdition();
    }

    // Overridden method to get textbook info (includes edition)
    @Override
    public String getBookInfo() {
        return "Title: " + getTitle() + ", Price: $" + getPrice() + ", Edition: " + edition;
    }

    // Optional: Override toString() for convenient output
    @Override
    public String toString() {
        return getBookInfo();
    }

    // Main method for testing
    public static void main(String[] args) {
        Textbook tb1 = new Textbook("Java Programming", 99.99, 3);
        Textbook tb2 = new Textbook("Java Programming", 89.99, 2);
        Textbook tb3 = new Textbook("Data Structures", 120.0, 1);

        // Test getBookInfo()
        System.out.println(tb1.getBookInfo()); // Output textbook info
        System.out.println(tb2.getBookInfo());

        // Test canSubstituteFor
        System.out.println(tb1.canSubstituteFor(tb2));  // true (same title, tb1 edition >= tb2 edition)
        System.out.println(tb2.canSubstituteFor(tb1));  // false (tb2 edition < tb1 edition)
        System.out.println(tb1.canSubstituteFor(tb3));  // false (different titles)
    }
}

Multiple Choice

1. What is wrong with this block of code?

class Shape{
    private double length = 0;
    private double width = 0;
    
    public Shape(double length, double width){
        this.length = length;
        this.width = width;
    }

    public double getArea(){
        return this.length * this.width;
    }

    private String toString(){
        return "Shape length:"+ (new Double(this.length)).toString() + " width:" + (new Double(this.width)).toString();
    }
}

Shape myShape = new Shape(2,3);

System.out.println(myShape.getArea());

a) You can’t use the this keyword in the constructor

b) When passing a double through an argument it must be in the form of 0.0

c) The toString() method must be public (This is the answer.)

d) The getArea() method doesn’t return a double

2. Which method cannot be exectuted in the following example of Polymorphism

class Water{
    public String toString(){
        return "Water";
    }

    private boolean isSalty(){
        return false;
    }

    public String typeOfWater(){
        return "Static";
    }

}

class Lake extends Water{
    public String toString(){
        return "Lake";
    }

    public boolean isSalty(){
        return true;
    }
}

Water myLakeWater = new Lake();

a) typeOfWater()

b) isSalty() (This is the answer.)

c) toString()

d) getClass()