You can use the name of a Java interface as you would a data type when you declare a variable, a data field, or a method’s parameter or return type. Although using an interface name in one of these ways is often a good idea, you must ensure compatible data types when assigning values to variables or passing arguments to methods. To do so, you might have to cast a data type.
Let’s write an interface for objects that have an area, such as circles and squares. The interface can specify a get
method for the area. This is shown below:
/** An interface for classes of objects that have an area.@author Frank M. Carrano */public interface Measurable{/** Gets the area of this object.@return the area. */public double getArea();} // End Measurable
Any class that implements this interface must define the getArea
method.
The following UML diagram illustrates two such classes, Square
and Circle
, and the client, ShapeDemo
. Let’s assume that we have defined these three classes. The classes are depicted as follows:
Because Square
implements Measurable
, we can assign a Square
object to a variable
of type Measurable
without a cast:
Measurable box = new Square(2.5);
However, to subsequently assign box
to a variable of type Square
it will require a cast:
Square boxAlias = (Square)box;
✏️ Note: Conversions between class types and interface types
- Conversion from a class type to an interface type is implicit and legal.
- Conversion from an interface type to a class type requires an explicit cast to the class type.
Again, consider the following statement:
Measurable box = new Square(2.5);
Since the Measurable
interface declares the getArea
method and the Square
class implements
getArea
, we can invoke this method in a statement such as:
double boxArea = box.getArea(); // Legal
However, Square
also defines the getSide
method which Measurable
does not declare. Thus, the following statement is illegal and would cause a syntax error:
double boxSide = box.getSide(); // ILLEGAL: getSide is not in Measurable
Because compilation occurs before execution, the compiler does not know that box
will reference a Square
object when this statement executes. But you do!
You can tell the compiler to assume that box
will reference a Square
object by casting box
to Square
. For example, you could write this:
Square boxAsSquare = (Square)box; // I promise that box references an object that has Square methods.
The compiler will believe you, so the following statement will compile and execute correctly, as seen here:
double boxAsSquareSide = boxAsSquare.getSide(); // Legal due to previous cast
If, however, box
does not reference a Square
object, an exception will occur if you try to cast it to Square
. For example, if box
actually references a Circle
object instead of a Square
object, you cannot cast box
to Square
.
The following program contains the previous statements so that you can verify their effect and experiment with them:
/** A class of circles.@author F. M. Carrano */public class Circle implements Measurable{private double radius;public Circle(double newRadius){radius = newRadius;} // End constructorpublic double getRadius(){return radius;} // End getRadiuspublic double getArea(){return Math.PI * radius * radius;} // End getAreapublic String toString(){return "A circle whose radius is " + radius;} // End toString} // End Circle
Now, consider the following method that we could add to the previous program:
/** Displays the side of a Square object. */
public static void displaySide(Square aSquare, String units)
{
double side = aSquare.getSide();
System.out.println("The Square's side is " + side + " " + units + ".");
} // End displaySide
The data type of displaySide
’s parameter, aSquare
, is Square
. You can pass it as an argument whose data type is Square
, but not Measurable
. And, as we have seen, you could not assign a Measurable
type variable to one of the Square
types. A cast to Square
would be required in both cases.
Now , let’s define the following method whose parameter, shape
, has Measurable
as its data type:
/** Displays the area of a Measurable object. */
public static void displayArea(Measurable shape, String units)
{
double area = shape.getArea();
System.out.println("The Measurable shape's area is " + area + " square " + units + ".");
} // End displayArea
You can pass this method a variable whose data type is either Measurable
, or a class, such as Square
or Circle
, that implements Measurable
.
The following program is like the previous one, but it includes the previous two methods. Run the program and try various calls to the methods until you are comfortable with casting interface types. This is shown below:
public class ShapesDemo{public static void main(String[] args){Square mySquare = new Square(2.5);double mySquareSide = mySquare.getSide();double mySquareArea = mySquare.getArea();System.out.println("A Square whose side is " + mySquareSide + " inches has an area of " + mySquareArea + " square inches.");Measurable box = new Square(3.0); // Implicit cast from class type to interface typedouble boxArea = box.getArea(); // LEGAL: Measurable declares getArea// Square's getArea is called// double boxSide = box.getSide(); // ILLEGAL: getSide is not in Measurable// The compiler does not know box references a Square object, but you do!Square boxAsSquare = (Square)box; // I promise that box references an object that has Square methods. The compiler will believe you.double boxAsSquareSide = boxAsSquare.getSide(); // Legal due to castdouble boxAsSquareArea = boxAsSquare.getArea(); // Legal due to castSystem.out.println("A Measurable box whose side is " + boxAsSquareSide + " inches has an area of " + boxAsSquareArea + " square inches.");// If you break your promise, an exception will occur.box = new Circle(3.0); // Legal: Circle is Meaurable// boxAsSquare = (Square)box; // Illegal: box does not reference a SquareSystem.out.println("The Measurable box as a Circle object has an area of " + box.getArea() + " square inches.");displaySide(mySquare, "inches"); // Pass a Square argument to a Square parameterdisplayArea(mySquare, "inches"); // Pass a Square argument to a Measurable parameterdisplayArea(boxAsSquare, "inches"); // Pass a Square argument to a Measurable parameterdisplayArea(box, "inches"); // Pass a Measurable argument to a Measurable parameter// displaySide(box, "inches"); // ILLEGAL: Pass a Measurable argument to a Square parameter} // End main/** Displays the side of a Square object. */public static void displaySide(Square aSquare, String units){double side = aSquare.getSide();System.out.println("The Square's side is " + side + " " + units + ".");} // End displaySide/** Displays the area of a Measurable object. */public static void displayArea(Measurable shape, String units){double area = shape.getArea();System.out.println("The Measurable shape's area is " + area + " square " + units + ".");} // End displayArea} // End ShapesDemo