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.