Unit 9 - Inheritance
Unit 9.1 / 9.2
Popcorn Hack 1
Here’s a challenge for you: Implement two new subclasses, Circle and Hexagon, extending from the Shape class. Follow the same structure as the Rectangle and Triangle classes!
public class Circle extends Shape {
int radius;
public Circle() {
super();
}
public Circle(String name, int radius) {
super(name, radius * 2, radous * 2);
this.radius = radius;
}
}
public class Hexagon extends Shape {
public Hexagon() {
super();
}
public Hexagon(String name, int length, int width) {
super(name, length, width);
}
}
Popcorn Hack 2
- Create a new subclass called Ellipse that extends Shape.
- Constructor: Implement a constructor for Ellipse that accepts parameters for name, length, and width. This constructor should call the superclass constructor using super().
- Update Your Driver Code
- 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.
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 Ellipse extends Shape {
public Ellipse() {
super();
}
public Ellipse(String name, int length, int width) {
super(name, length, width);
}
@Override
public double calc_area() {
return (this.get_length() * this.get_width() * 3.14);
}
@Override
public void print_something() {
System.out.println("This is an ellipse");
}
}
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);
Shape s4 = new Ellipse("ellipse", 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());
System.out.println("Area of s4 = " + s4.calc_area());
s1.print_shape();
s2.print_shape();
s4.print_shape();
// Using the overridden method
s1.print_something();
s2.print_something();
s4.print_shape();
}
}
// Run the driver code
Driver.main(new String[0]);
Area of s1 = 50.0
Area of s2 = 40.0
Area of s3 = 50.0
Area of s4 = 314.0
Shape: Shape
Shape: rectangle
Shape: ellipse
This is a shape
This is a rectangle
Shape: ellipse
Unit 9.3 / 9.4
Popcorn Hack 1
Lets re-define the Triangle class but this time override the default area method with the Heron’s formula
import java.lang.Math;
public class Triangle extends Shape {
private int side1;
private int side2;
private int side3;
public Triangle() {
this.name = "triangle";
this.side1 = 1;
this.side2 = 2;
this.side3 = 3;
}
// Constructor that takes a name and three side lengths
public Triangle(String name, int s1, int s2, int s3) {
super(name, 0, 0); // Call to Shape constructor to set the name
this.name = "triangle";
this.side1 = s1;
this.side2 = s2;
this.side3 = s3;
}
@Override
public double calc_area() {
double area = 0.0;
double semiPerimeter = (this.s1 + this.s2 + this.s3) / 2;
double value = semiPerimeter * (semiPerimeter - this.s1) * (semiPerimeter - this.s2) * (semiPerimeter - this.s3);
area = Math.sqrt(value);
return area;
}
}
Popcorn Hack 2
public class Triangle extends Shape {
private int side1;
private int side2;
private int side3;
public Triangle() {
this.name = "triangle";
this.side1 = 1;
this.side2 = 2;
this.side3 = 3;
}
// Constructor that takes a name and three side lengths
public Triangle(String name, int s1, int s2, int s3) {
super(name, 0, 0); // Call to Shape constructor to set the name
this.name = "triangle";
this.side1 = s1;
this.side2 = s2;
this.side3 = s3;
}
@Override
public double calc_area() {
double area = 0.0;
double semiPerimeter = (this.s1 + this.s2 + this.s3) / 2;
double value = semiPerimeter * (semiPerimeter - this.s1) * (semiPerimeter - this.s2) * (semiPerimeter - this.s3);
area = Math.sqrt(value);
return area;
}
// Add perimeter method override here
//expected output 12
}
Unit 9.5
Popcorn Hack 1
class Shape {
public String draw() {
return "Drawing a shape";
}
public double area() {
return 0;
}
}
class Triangle extends Shape {
private int side1;
private int side2;
private int side3;
public Triangle() {
this.side1 = 1;
this.side2 = 2;
this.side3 = 3;
}
@Override
public String draw() {
return "Drawing a triangle";
}
}
class Rectangle extends Shape {
@Override
public String draw() {
return "Drawing a rectangle";
}
}
class Circle extends Shape {
@Override
public double area(int radius) {
return (3.14 * radius * radius);
}
}
class Square extends Shape {
@Override
public double area() {
// TODO: Implement area calculation
}
}
public class Main {
public static void main(String[] args) {
Shape myTriangle = new Triangle();
System.out.println(myTriangle.draw()); // Should output: "Drawing a triangle."
Shape
Shape myRectangle = new Rectangle();
System.out.println(myRectangle.draw()); // Should output: "Drawing a rectangle."
}
}
Main.main(null);
Drawing a triangle
Drawing a rectangle
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 Ellipse extends Shape {
public Ellipse() {
super();
}
public Ellipse(String name, int length, int width) {
super(name, length, width);
}
@Override
public double calc_area() {
return (this.get_length() * this.get_width() * 3.14);
}
@Override
public void print_something() {
System.out.println("This is an ellipse");
}
}
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);
Shape s4 = new Ellipse("ellipse", 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());
System.out.println("Area of s4 = " + s4.calc_area());
s1.print_shape();
s2.print_shape();
s4.print_shape();
// Using the overridden method
s1.print_something();
s2.print_something();
s4.print_shape();
}
}
// Run the driver code
Driver.main(new String[0]);
Unit 9.6
Popcorn Hack 1
Create an example of Polymorphism in your own project.
public class Circle extends Shape {
private int radius;
// Constructor that takes a name and radius
public Circle(String name, int radius) {
super(name, 0, 0); // Call to Shape constructor to set the name
this.name = "circle";
this.radius = radius;
}
@Override
public double calc_area() {
return Math.PI * radius * radius;
}
}
Using your previous polymorphism example, explain which parts are the static types and which are the dynamic types
Static types vs. dynamic types in polymorphism: Static types are the types determined at compile-time. In the polymorphism example, if you declare Shape myShape = new Circle(“circle”, 5);, the static type of myShape is Shape because it’s declared as a Shape. This is what the compiler uses to check that the method calls are valid. Dynamic types are the actual types of the objects that are determined at runtime. In this case, the dynamic type of myShape is Circle because the actual object created is a Circle, even though it’s being referenced as a Shape. When methods like calc_area() are called, Java will use the dynamic type to determine which method implementation to invoke.
Define down-casting in your own words:
Down-casting: Down-casting is the process of converting a reference of a base class (or interface) to a more specific subclass. It allows access to methods and properties specific to the subclass that wouldn’t be available via the base class reference. Down-casting is necessary when you want to access subclass-specific features from an object that’s been referenced by its base class type.
Add an example of down-casting to your previous polymorphism example
class Shape {
protected String name;
private int x;
private int y;
// Constructor for Shape
public Shape(String name, int x, int y) {
this.name = name;
this.x = x;
this.y = y;
}
// Method to calculate area, to be overridden by subclasses
public double calc_area() {
return 0; // Default implementation
}
// Getter for the name of the shape
public String getName() {
return name;
}
}
public class Circle extends Shape {
private int radius;
// Constructor that takes a name and radius
public Circle(String name, int radius) {
super(name, 0, 0); // Call to Shape constructor to set the name
this.name = "circle";
this.radius = radius;
}
@Override
public double calc_area() {
return Math.PI * radius * radius;
}
// Method to get the radius of the circle
public int getRadius() {
return radius;
}
public static void main(String[] args) {
// Polymorphism example
Shape myShape = new Circle("circle", 5); // Shape reference to a Circle object
// Calling the overridden method via Shape reference (dynamic dispatch)
System.out.println("Area: " + myShape.calc_area());
// Down-casting from Shape to Circle
if (myShape instanceof Circle) {
Circle myCircle = (Circle) myShape; // Down-cast Shape to Circle
System.out.println("Radius of the circle: " + myCircle.getRadius());
}
}
}
Unit 9.7
class Shape {
protected String name;
// Constructor for Shape
public Shape(String name) {
this.name = name;
}
// Default toString() method inherited from Object, which we do not override
// We will call this unchanged
// Overriding equals() method from Object to compare shapes by name
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // Check if they are the same instance
if (obj == null || getClass() != obj.getClass()) return false; // Check if they are different types
Shape shape = (Shape) obj;
return name.equals(shape.name); // Compare by name
}
}
public class Circle extends Shape {
private int radius;
// Constructor that takes a name and radius
public Circle(String name, int radius) {
super(name);
this.radius = radius;
}
public static void main(String[] args) {
// Create two Circle objects
Circle circle1 = new Circle("circle", 5);
Circle circle2 = new Circle("circle", 10);
// Call toString() method, which is inherited from Object and not overridden
System.out.println("Unchanged toString(): " + circle1.toString());
// Call the overridden equals() method
boolean areEqual = circle1.equals(circle2); // true because they have the same name
System.out.println("Overridden equals(): Are circle1 and circle2 equal? " + areEqual);
}
}