Block B

We made an interface for shapes called Shape.


public interface Shape
{
    public double area();
    public double diameter();
    public double perimeter();
}

Three methods are specfied. Any class implementing this interface must implement these three methods.

The Circle class here accepts the greater challenge.


public class Circle implements Shape
{
    private double radius;
    public Circle(double radius)
    {
        this.radius = radius;
    }
    public double area()
    {
        return Math.PI*radius*radius;
    }
    public double diameter()
    {
        return 2*radius;
    }
    public double perimeter()
    {
        return 2*Math.PI*radius;
    }
}

Begin by opening the class and the interface. Let's make a new circle.


jshell> /open Shape.java

jshell> /open Circle.java

jshell> Circle c = new Circle(10);
c ==> Circle@6e8cf4c6

All of the methods appear to work nicely.

`

jshell> c.area()
$4 ==> 314.1592653589793

jshell> c.diameter()
$5 ==> 20.0

jshell> c.perimeter()
$6 ==> 62.83185307179586

Here is something not to do.


jshell> Shape s = new Shape();
|  Error:
|  Shape is abstract; cannot be instantiated
|  Shape s = new Shape();
|            ^---------^

Since the methods in the interface have no bodies, this makes no sense at all to do.

You CAN do this.


jshell> Shape s = new Circle(10);
s ==> Circle@27973e9b

jshell> s.area()
$8 ==> 314.1592653589793

A Shape variable can point at a Circle object because Circle implements Shape.

Now let us create a Rectangle class.


public class Rectangle implements Shape
{
    private double height;
    private double width;
    public Rectangle(double width, double height)
    {
        this.width = width;
        this.height = height;
    }
    public double area()
    {
        return width*height;
    }
    public double diameter()
    {
        return Math.hypot(width, height);
    }
    public double perimeter()
    {
        return 2*(height + width);
    }
}

Let's restart Jshell.


jshell> /open Shape.java

jshell> /open Circle.java

jshell> /open Rectangle.java

jshell> Shape s = new Rectangle(6,8);
s ==> Rectangle@34c45dca

jshell> s.area()
$5 ==> 48.0

jshell> s.diameter()
$6 ==> 10.0

jshell> s.perimeter()
$7 ==> 28.0

The Shape variable happily points at Rectangles, too. Here is an added bonus. Interface types can appear as type parameters in generic classes such as ArrayList.


jshell> ArrayList<Shape> al = new ArrayList<>();
al ==> []

jshell> al.add(new Circle(10));
$9 ==> true

jshell> al.add(new Rectangle(6,8));
$10 ==> true

jshell> al
al ==> [Circle@3d494fbf, Rectangle@1ddc4ec2]

Now add this method to your Rectangle class


    public int numSides()
    {
        return 4;
    }

We reset all.


jshell> /open Shape.java

jshell> /open Circle.java

jshell> /open Rectangle.java

jshell> Shape s = new Rectangle(6,8);
s ==> Rectangle@34c45dca

Look what happens.


jshell> s.area()
$5 ==> 48.0

jshell> s.numSides()
|  Error:
|  cannot find symbol
|    symbol:   method numSides()
|  s.numSides()
|  ^--------^

jshell> s.getClass()
$6 ==> class Rectangle

Even though the object being pointed at is a Rectangle, the numSides method is not visible to s.

The Visiblity Principle The type of a variable determines what methods are visible to the variable

In this case, the three Shape methods are visible, but numSides is not.

The Delegation Principle The execution of methods is delegated to the object being pointed at. When a Shape variable points at a Circle, Circle methods are executed. When a Shape variable points at a Rectangle, Rectangle methods are executed.