Richard G Baldwin (512) 223-4758, baldwin@austin.cc.tx.us, http://www2.austin.cc.tx.us/baldwin/

More on Interfaces

Java Programming, Lecture Notes # 46, Revised 10/03/99.

Preface
Introduction
Sample Program
What Are Interfaces and What Are They Good For?
The Bottom Line on Interfaces
Review

Preface

Students in Prof. Baldwin's Introductory Java Programming classes at ACC are responsible for knowing and understanding all of the material in this lesson (except that they are not responsible for detailed information that is specific to C++).

The detailed material on C++ is provided as supplementary material for the benefit of persons already familiar with C++ who are making the transition into Java.

Introduction

The concept of the interface can sometimes be fairly difficult to comprehend. Before getting into a lot of technical details, lets see if we can present an overview that will help you to understand the details when we get to them.

The concept of the interface does not exist in C++.

First of all, why does the interface exist in the first place? Many books provide answers to this question from a justification viewpoint. I will simply try to answer it from a practical programming viewpoint and will leave the justification to others.

Probably the most important aspect of the interface concept is that it allows you to treat a number of objects, instantiated from different classes, as if they were all of the same type, or you can treat an object of a given true type as a different type. At least that is true to a limited extent.

At its simplest level, an interface definition has a name, and declares one or more methods.

Only the method signatures are provided. The actual implementations (bodies) of the methods are not provided.

In addition to method declarations, an interface can also declare constants. Nothing else may be included inside the body of an interface definition.

Now please bear with me and concentrate as I attempt to explain what this all means.

Assume that there is an interface definition named X which declares methods A, B, and C.

Assume further that there are three different classes named P, D, and Q.

Each class claims to implement the interface named X.

Each class also provides a full definition for methods A, B, and C

All of this being true, a group of mixed objects of types P, D, and Q can be treated as if they were all of type X (to a limited extent).

Multiple objects of different classes can be treated as if they are all of the same common type where the type is indicated by the name of the interface.

For example, a reference variable for an object of Class P, D, or Q could be assigned to a reference variable of type X. (Normally a reference variable of one type cannot be assigned to a reference variable of another type, except in some special cases.)

Similarly, a new object of class P, D, or Q could be instantiated and its reference could immediately be assigned to a variable of type X without a variable of type P, D, or Q ever having existed.

The references to a group of objects of types P, D, and Q could be assigned to the individual elements of an array of variables of type X.

Or the elements in the array of type X could be used in the instantiation statements of the objects when they are first instantiated and may be the only reference variables ever to exist to refer to the objects.

Having done these things, a reference variable of type X could then be used to access methods A, B, or C of the object to which it refers.

It is important to note that the behavior of methods A, B, and C could differ significantly between objects of classes P, D, and Q.

The actual implementation of a method A, B, or C could be tailored to the specific class in which it is defined. Only the method signature must be the same among the different classes which implement the interface.

A previous paragraph used the terminology "to a limited extent." If one or more of the classes P, D, and Q, define instance methods which are not declared in the interface X, then a reference variable of type X cannot be used to access those instance methods. Those methods can only be accessed using a reference variable of the class in which the method is defined.

Reference variables of the type X can only be used to access methods declared in the interface X (or one of its superinterfaces which we will get to later).

Another limitation is that even though you can consider the interface name as a type for purposes of storing references to objects, you cannot instantiate an object of the interface type itself.

An interface definition does not have a constructor, so it is not possible to invoke the new operator on an interface type.

By the way, if the classes P, D, and Q implement the interface X as described above, a method in another class can invoke the methods named A, B, and C on objects of type P, D, and Q without ever knowing their true type (the class from which they were instantiated). This is accomplished by casting those objects as type X when the method is invoked. An example program which illustrates this important aspect of interfaces is presented later in the lesson.

Sample Program

The following sample program illustrates some of these concepts.

Two interfaces are defined and named Constants and MyIntfc. The Constants interface defines two constants and the MyIntfc interface declares a set() method and a get() method.

The constants and the methods could have been combined into a single interface definition. However, they were separated to illustrate that a single class can implement two or more interfaces using a comma-separated list of interface names.

Two class are defined named ClassA and ClassB. Each of these classes implements both of the interfaces listed above. This means that each class defines the set() method and the get() method declared in MyIntfc. Each class also makes use of the constants defined in the interface named Constants.

It is important to note that in defining the two interface methods, each class defines it in a manner that is appropriate to its own class without concern for how it is defined in other classes.

One of the classes, ClassA, also defines another method named show() which is not declared in the interface. This method is used to demonstrate that a method that is not declared in the interface cannot be accessed using a reference variable of the interface type.

The main method in the controlling class named Intfc01 executes a series of instantiations, method invocations, and assignments designed to illustrate the characteristics described above.

The comments and the print statements embedded in the program should make it self-explanatory at this point.

/*File Intfc01.java Copyright 1997, R.G.Baldwin
Revised 08/12/99
Illustrates use of interface.

The interface definitions for Constants and MyIntfc are 
contained in the files named Constants.java and 
MyIntfc.java.  The compiler requires them to be in separate
source files.

The interface named Constants contains two constants.
The interface named MyIntfc contains declarations for set()
and get().

Different versions of set() and get() are implemented in 
ClassA and ClassB.

The output from running the program is: (manual line breaks
were inserted to make it fit the display format)

Instantiate objA of type ClassA, then set, and show data.
In set() method for classA, using pi from Constants 
  interface: 12.28
In show() method for ClassA, data = 12.28

Assign objA to ref var of type MyIntfc named objAA.
Invoke set() method on objAA to modify the data.
In set() method for classA, using pi from Constants 
  interface: 24.56
Invoke get() method on objAA to display the modified data.
objA data = 24

Instantiate object of type ClassB named objB.  Immediately 
  assign the ref to a type MyIntfc ref var instead of a 
  type ClassB ref var.
Invoke its set() method to store some data.
In set() method for classB, using intConstant from 
  Constants interface: 1375
Invoke its get() method to display the data.
objB data = 1375

Successfully assign objA to objB and display objB
objB data = 24

Invoke set() method on objAA to modify its data.
In set() method for classA, using pi from Constants 
  interface: 98.24
Successfully assign objAA to objB and display objB
objB data = 98

Restore objB to its original type and value.
In set() method for classB, using intConstant from 
  Constants interface: 1375
Successfully assign objB to objAA and display objAA
objAA data = 1375

Attempt to assign objB to objA fails because
  "Explicit cast needed to convert MyIntfc to ClassA."

Attempt to invoke show() method of objAA fails because
"Method show() not found in interface MyIntfc".
End of program.

*/
//=======================================================//
class ClassA implements Constants,MyIntfc{
  double data;
  
  //Define versions of set() and get() appropriate to 
  // ClassA
  public void set(int inData){
    //note use of pi from Constants interface
    data = (double)inData*pi;
    System.out.println(
      "In set() method for classA, using pi from " +
                           "Constants interface: " + data);
  }//end set()
  
  public int get(){
    return (int)data;
  }//end get()
  
  //Define a show method for ClassA not declared in 
  // interface MyIntfc
  void show(){
    System.out.println(
            "In show() method for ClassA, data = " + data);
  }//end show() method
}//end ClassA
//=======================================================//

class ClassB implements Constants,MyIntfc{
  int data;
  
  //Define versions of set() and get() appropriate to 
  // ClassB
  public void set(int inData){
    //note use of intConstant from Constants interface
    data = inData*intConstant;
    System.out.println(
      "In set() method for classB, using intConstant " +
                     " from Constants interface: " + data);
  }//end set()
  
  public int get(){
    return data;
  }//end get()
}//end ClassB
//=======================================================//

class Intfc01{
  public static void main(String[] args){
    System.out.println(
      "Instantiate objA of type ClassA, then set, and " +
                                             "show data.");
    ClassA objA = new ClassA();
    objA.set(2);
    objA.show();    
  
    System.out.println("\nAssign objA to ref var of " +
                              "type MyIntfc named objAA.");
    MyIntfc objAA = objA;
    System.out.println("Invoke set() method on objAA " +
                                    "to modify the data.");
    objAA.set(4);  
    System.out.println("Invoke get() method on objAA to " +
                             "display the modified data.");
    System.out.println("objA data = " + objAA.get());
    
    System.out.println(
      "\nInstantiate object of type ClassB named objB." +
            "  Immediately assign\n the ref to a type " +
            "MyIntfc ref var instead of a type ClassB " +
                                              "ref var.");
    MyIntfc objB = new ClassB();
    System.out.println("Invoke its set() method to " +
                                      "store some data.");
    objB.set(11);
    System.out.println("Invoke its get() method to " +
                                     "display the data.");
    System.out.println("objB data = " + objB.get());

    System.out.println("\nSuccessfully assign objA to " +
                                  "objB and display objB");
    objB = objA;
    System.out.println("objB data = " + objB.get());

    System.out.println("\nInvoke set() method on objAA " +
                                    "to modify its data.");
    objAA.set(16);    
    System.out.println("Successfully assign objAA to " +
                                  "objB and display objB");
    objB = objAA;
    System.out.println("objB data = " + objB.get());
    
    System.out.println("\nRestore objB to its original " +
                                        "type and value.");
    //objB already defined as type MyIntfc
    objB = new ClassB();
    objB.set(11);
    System.out.println("Successfully assign objB to " +
                                "objAA and display objAA");
    objAA = objB;
    System.out.println("objAA data = " + objAA.get());

    System.out.println("\nAttempt to assign objB to " +
      " objA fails because\n  \"Explicit cast needed to " +
                           "convert MyIntfc to ClassA.\"");
    //objA = objB; //statement removed by making it comment
    
    System.out.println(
      "\nAttempt to invoke show() method of objAA fails " +
      "because\n \"Method show() not found in interface " +
                                             "MyIntfc\".");
    //objAA.show();//statement removed by making it 
    // a comment
    
    System.out.println("End of program.");

  }//end main
}//end class Intfc01
//=======================================================//

What Are Interfaces and What Are They Good For?

Interfaces and Multiple Inheritance
Defining an Interface
Implementing an Interface
An Interface as a Type

According to The Java Tutorial by Campione and Walrath:

An interface is a collection of method definitions (without implementations) and constant values.

You use interfaces to define a protocol of behavior that can be implemented by any class anywhere in the class hierarchy.

Interfaces are useful for:

  • capturing similarities between unrelated classes without forcing a class relationship
  • declaring methods that one or more classes are expected to implement
  • revealing an object's programming interface without revealing its class (objects such as these are called anonymous objects and can be useful when shipping a package of classes to other developers)

Interfaces and Multiple Inheritance

C++ allows the programmer to create a new class as a subclass of two or more different superclasses. This is called multiple inheritance.

Java does not allow multiple inheritance. Some authors suggest that the Java interface is a substitute for multiple inheritance. Other authors disagree. Here is what Campione and Walrath have to say on the subject in The Java Tutorial.

Often interfaces are touted as an alternative to multiple class inheritance. While interfaces may solve some of the same problems as multiple class inheritance, they are quite different animals. In particular:

  • you cannot inherit variables from an interface
  • you cannot inherit method implementations from an interface.
  • the interface hierarchy is independent of the class hierarchy--classes that implement the same interface may or may not be related through the class hierarchy.

This is not true for multiple inheritance.

Defining an Interface

Declaration
Body

You define an interface in much the same way that you define a class. The interface definition has two components:

An interface presented in schematic view might look like this:

interfaceDeclaration{
  //interfaceBody
}//end of interface definition

The interfaceDeclaration declares various attributes about the interface (name, whether it extends another interface, etc.).

The interfaceBody contains the constant and method declarations within the interface.

Declaration

A minimum interface declaration contains the Java keyword interface and the name of the interface.

By convention, interface names begin with upper-case letters just like class names but this is not a requirement.

An interface declaration can have two other components:

An interface can extend other interfaces.

However, while a class can only extend one other class, an interface can extend any number of interfaces.

Here is a full interface definition which includes the body as well as the declaration. (the body is discussed later).

public interface MyIntfc extends interfaceX, interfaceY{
  public final double pi = 6.14;
  public final int intConstant = 125;
  void set(int inData);
  int get();
}//end interface MyIntfc

The public access specifier indicates that the interface can be used by any class in any package. If omitted, the interface will only be accessible to classes that are defined in the same package.

The extends clause is similar to the extends clause in a class declaration. An interface can extend multiple interfaces (while a class can only extend one).

An interface cannot extend classes.

The list of superinterfaces is a comma-separated list of all of the interfaces extended by the new interface.

An interface inherits all constants and methods from its superinterface unless:

Body

The body of the interface contains method declarations.

The method declaration is terminated by a semicolon and no body is provided for the method.

C++ programmers will recognize this as being generally the same as a function prototype.

You may not use transient, volatile, private, protected, or synchronized in a member declaration in an interface.

All methods declared in an interface are implicitly public and abstract.

The body of the interface may also define constants. Constant values defined in an interface are implicitly public, static, and final.

A complete interface definition for an interface named MyIntfc was provided above which declared two methods, set() and get(), and defined two constants, pi, and intConstant. The interface extended interfaceX and interfaceY.

Implementing an Interface

You use an interface by defining a class that implements the interface by name.

When a class claims to implement an interface, it must provide a full definition for all the methods declared in the interface as well as all of the methods declared in all of the superinterfaces of that interface.

A class can implement more than one interface by including several interface names in a comma-separated list of interface names. In that case, the class must provide a full definition for all of the methods declared in all of the interfaces listed as well as all of the superinterfaces of those interfaces.

Here is an example of a class which implements two interfaces: Constants and MyIntfc.

class ClassA implements Constants,MyIntfc{
  double data;
  
  //Define versions of set() and get() appropriate to 
  // ClassA
  public void set(int inData){
    //note use of pi from Constants interface
    data = (double)inData*pi;
    System.out.println(
      "In set() method for classA, using pi from " +
                           "Constants interface: " + data);
  }//end set()
  
  public int get(){
    return (int)data;
  }//end get()
  
  //Define a show method for ClassA not declared in 
  // interface MyIntfc
  void show(){
    System.out.println(
            "In show() method for ClassA, data = " + data);
  }//end show() method
}//end ClassA
//=======================================================//

As you can see, this class provides a full definition of the methods set() and get() from the interface named MyIntfc and also uses constants defined in the interface named Constants.

In addition, the class provides a definition for a method named show() which is not declared in either of the interfaces.

An Interface as a Type

The definition of an interface is a definition of a new reference data type. You can use interface names just about anywhere that you would use other type name.

However, you cannot instantiate objects of the interface type. It doesn't have a constructor.

The example program presented at the beginning of this lesson contains numerous examples of using the name of an interface as a type. The sample program presented in the next section elaborates on the importance of the interface as a type.

The Bottom Line on Interfaces

Interesting Code Fragments
Program Listing

So, in the final analysis, what really is the bottom line on interfaces. What are they really good for?

The interface makes it possible for a method in one class to invoke methods on objects of other classes, without the requirement to know the true class of those objects, provided that those objects are instantiated from classes that implement one or more specified interfaces.

In other words, objects of classes that implement specified interfaces can be passed into the methods of other objects as the generic type Object, and the methods of the other object can invoke methods on the incoming objects by first casting them as the interface type.

This provides a significant degree of generality in your programming capability. The next sample program illustrates the solution to a classical problem where generality is very important.

Assume that you are a member of a programming team and you have been tasked to define a class and write the methods of that class which will manipulate incoming objects of unknown types based on whether one object is less than, equal to, or greater than another object. Perhaps you are writing a class to sort objects, or to create and maintain a list of objects in "proper order." A very important question is what constitutes proper order.

Obviously if the objects are of unknown type, you cannot know if one is greater than another. You must rely on the objects being able to compare themselves and to tell you which is greater. This means that the classes from which the objects were instantiated must contain methods which perform the comparisons and return the answer, and it means that you must be able to invoke those methods on the objects.

Generally, you cannot invoke any methods on an object of the generic type Object other than those methods defined in the class named Object. This means that you cannot invoke the methods of the objects defined in the true class of those objects without some additional tools, and that is where the interface as a type comes into play.

The trick is for you to define an interface that declares the necessary comparison methods and to require that any objects passed into your methods implement that interface. Once you receive a pair of objects (as the generic type Object), you can cast them as the interface type and invoke their methods to determine which is greater.

At this point, all you care about is the answer provided by the methods of those objects. You don't care about the methodology. You leave the methodology up to the designer of the class for the objects that you receive and assume that those objects know how to compare themselves properly. For example, for some good reason the designer of the class may have decided that 5 is less than 4, and we will take that decision to be valid. You depend on the designer of that class to make those kinds of decisions.

For example, the incoming objects may contain information about people such as names and ages. In a sorting operation, it might be appropriate to order the objects in terms of age, or it might be just as appropriate to order them in terms of alphabetic names. You leave that decision up to the designer of the class from which your incoming objects were instantiated.

You simply require that a decision be made by requiring that the class implement the interface that you define. This in turn requires the designer of the class to implement the decisions in the form of a set of methods that can be used to compare the objects.

Interesting Code Fragments

This program illustrates the use of an interface to make it possible for a method named compare() in a class named LibraryClass to invoke the methods of objects passed in as the generic type Object.

The method named compare() isn't required to know the true type (the class from which they were instantiated) of the incoming objects. However, it does require that they be of a type that implements the interface named Intfc02A. This makes it possible to cast the incoming objects according to that interface type and invoke the methods of the objects. (Note that only those methods declared in the interface can be invoked in this manner.)

The output produced by this program is shown in the comments in the full program listing.

The program defines three classes and one interface. One class is the controlling class named Intfc02 that is used to exercise the other two classes.

The second class is a class named UserClass which implements the interface named Intfc02A. Objects of this class are suitable for being passed as type Object to the method named compare() and to be manipulated there.

The third class is a class named LibraryClass. This class contains the method named compare() that is used to manipulate the objects of unknown type (actually of type UserClass but only you and I know that).

The first interesting code fragment is the code in the controlling class named Intfc02 which is used to exercise the other two classes. The following statement is typical of what you will find there. As you can see, this code fragment instantiates two objects of type UserClass, and passes them to the compare() method of a new object of type LibraryClass.

new LibraryClass().compare(
                        new UserClass(5),new UserClass(6));

The next interesting code fragment is the class named UserClass whose objects are suitable for processing by an object of the class named LibraryClass. They are suitable because UserClass implements the interface named Intfc02A which is a requirement of the compare() method of the class named LibraryClass.

By defining the methods named LT, EQ, and GT, this class makes it possible for the compare() method to invoke these three methods to compare two objects of type UserClass.

By implementing the interface named Intfc02A, UserClass makes it possible for the method named compare() of the class named LibraryClass to receive objects of this type as the generic type Object (without knowing their true type) and to cast them to type Intfc02A for purposes of invoking the methods of UserClass.

UserClass defines three methods that are declared in the interface named Intfc02A. These methods can be used to determine if an object of this class is less than, equal to, or greater than another object of the same class that is passed in as a parameter to the method.

(It probably would have been safer to use the instanceOf() method to confirm that the two objects are of the correct type, and if not to throw an exception.)

The three methods are very similar, so only the one named LT is shown here.

Note first that this class implements the interface named Intfc02A which is a requirement of the method named compare().

Note next that when the method named LT is invoked on an object of the UserClass type, it receives an object of type Object as a parameter. The object on which it is invoked (this) is to be compared to the object passed in as a parameter. It casts the incoming object to its own type (UserClass) in order to access the instance variable named data that comes in with the object. (Otherwise access to the instance variable would not be possible.)

Finally, note how the parentheses are positioned in the casting operation. It is easy to get this wrong.

class UserClass implements Intfc02A{
  int data;
  
  public boolean LT(Object obj){//test for less than
    if(this.data < ((UserClass)obj).data)return true;
    else return false;
  }//end LT()

  //...

That brings us to the class named LibraryClass. This class contains a method that compares two objects of any class that implements the interface named Intfc02A.

(To reiterate, even though we exercised the method named compare() using only objects of type UserClass, the method named compare() can compare two objects of any class that implements the interface named Intfc02A, but as currently written, they must be of the same class.)

The actual comparison methods are defined in the class of the incoming objects. The compare() method of the LibraryClass object casts the incoming objects as the interface type (Intfc02A) and invokes the instance methods of those objects.

Although the method named compare() invokes three different methods on the incoming objects, each invocation is very similar to the other two, so only the invocation of the method named LT is shown here.

Note that the method named compare() receives two incoming objects as the generic type Object and casts only one of them as the interface type in order to invoke its methods, passing the other object intact (without casting) to the method. (Recall that the object is subsequently cast as type UserClass inside the method of class UserClass into which it is passed.)

Again, note the placement of the parentheses in the casting operation. It is critical that you get them placed correctly.

class LibraryClass{
  void compare(Object objA,Object objB){
    System.out.println("objA less than objB? " 
                             + ((Intfc02A)objA).LT(objB) );
  //...
  }//end compare() method
}//end LibraryClass

You can view the code that was omitted in the complete program listing that follows in the next section.

A listing of the interface definition is shown below.

/*File Intfc02A.java Copyright 1997, R.G.Baldwin
Interface definition used to support Intfc02.java
Illustrates use of interface.
*/

public interface Intfc02A{
  public boolean LT(Object obj);//test less than
  public boolean GT(Object obj);//test greater than
  public boolean EQ(Object obj);//test equal to  
}//end interface Intfc02A

A complete listing of the program follows in the next section.

Program Listing

The output from running this program is shown in the comments at the top of the program listing. Some of the interesting code fragments are shown highlighted in boldface.

/*File Intfc02.java Copyright 1997, R.G.Baldwin
This program illustrates the use of an interface to make 
it possible for a method in a library class to invoke a 
method of an object passed in simply as type Object.

Note that the method in the library class isn't required
to know the true type of objects passed in.  However, it
does require that they be of a type that implements the
interface named Intfc02A.  This makes it possible to
cast the incoming object according to that interface type 
and invoke the methods of the object.

This program produces the following output:

Compare 5 and 6
objA less than objB? true
objA equal to objB? false
objA greater than objB? false

Compare 5 and 5
objA less than objB? false
objA equal to objB? true
objA greater than objB? false

Compare 5 and 4
objA less than objB? false
objA equal to objB? false
objA greater than objB? true  
  
This program was tested using JDK 1.1.3 under Win95.
**********************************************************/

//This class is used to test the ability of the method
// named compare() of the class named LibraryClass to
// properly process objects of the class named UserClass.
// The class named UserClass implements an interface
// required by the method named compare() of the class 
// named LibraryClass to make such processing possible.
class Intfc02{
  public static void main(String[] args){
    System.out.println("Compare 5 and 6");
    new LibraryClass().compare(new UserClass(5),
                                         new UserClass(6));
    System.out.println("\nCompare 5 and 5");
    new LibraryClass().compare(new UserClass(5),
                                         new UserClass(5));
    System.out.println("\nCompare 5 and 4");
    new LibraryClass().compare(new UserClass(5),
                                         new UserClass(4));
  }//end main
}//end class Intfc02
//=======================================================//

//This is a user class whose objects are suitable for 
// processing by an object of the class named LibraryClass
// because this class implements the interface named 
// Intfc02A which is a requirement of the compare() method
// of the class named LibraryClass.

//By defining the methods named LT, EQ, and GT, this
// class makes it possible for the compare() method
// to compare two objects of this class using the methods
// defined in this class.  

//By implementing the interface named Intfc02A, this class
// makes it possible for the method named compare() of the
// class named LibraryClass to receive objects of this type
// simply as type Object (without knowing their true type)
// and then cast them to type Intfc02A for purposes of 
// invoking the methods of this class.

class UserClass implements Intfc02A{
  int data;
  
  UserClass(int data){//constructor
    this.data = data;
  }//end constructor
  //-----------------------------------------------------//
  
  //Define three methods that are declared in the 
  // interface named Intfc02A. These methods can be used
  // to determine if an object of this class is less than,
  // equal to, or greater than another object of this
  // class that is passed in as a parameter to the method.
  
  public boolean LT(Object obj){//test for less than
    if(this.data < ((UserClass)obj).data)return true;
    else return false;
  }//end LT()
  //-----------------------------------------------------//
    
  public boolean GT(Object obj){//test for greater than
    if(this.data  ((UserClass)obj).data)return true;
    else return false;
  }//end GT()
  //-----------------------------------------------------//
    
  public boolean EQ(Object obj){//test for equal to
    if(this.data == ((UserClass)obj).data)return true;
    else return false;
  }//end EQ()
    
}//end UserClass
//=======================================================//

//This class contains a method that compares two objects
// of any class that implements the interface named 
// Intfc02A. 

//The actual comparison methods are defined in the class
// of the incoming objects.  The method of this class
// casts those objects as the interface type and invokes
// the instance methods of the objects.
class LibraryClass{
  void compare(Object objA,Object objB){
    System.out.println("objA less than objB? " 
                             + ((Intfc02A)objA).LT(objB) );
    System.out.println("objA equal to objB? " 
                             + ((Intfc02A)objA).EQ(objB) );
    System.out.println("objA greater than objB? " 
                             + ((Intfc02A)objA).GT(objB) );
  }//end compare() method
}//end LibraryClass
//=======================================================//

Review

Q - To a limited extent, the interface concept allows you to treat a number of objects, instantiated from different classes, as if they were all of the same type: True or False? If false, explain why.

A - True.

Q - At its simplest level, an interface definition has a name, and declares one or more methods: True or False? If false, explain why.

A - True.

Q- In an interface definition, both the method signatures and the actual implementations (bodies) of the methods are provided: True or False? If false, explain why.

A - False. Only the method signatures are provided. The actual implementations (bodies) of the methods are not provided.

Q - An interface definition can contain only method declarations: True or False? If false, explain why.

A - False. In addition to method declarations, an interface can also declare constants. Nothing else may be included inside the body of an interface definition.

Q - If classes P, D, and Q all implement interface X, a reference variable for an object of class P, D, or Q could be assigned to a reference variable of type X: True or False? If false, explain why.

A - True.

Q - If classes P, D, and Q all implement interface X, then all of the methods declared in X must be exactly the same in classes P, D, and Q: True or False? If false, explain why.

A - False. The interface simply declares the signatures for methods. Classes that implement the interface are free to provide a body for those methods which best suits the needs of the class.

Q - If classes P, D, and Q all implement interface X a reference variable for an object of class P, D, or Q could be assigned to a reference variable of type X and that reference variable could be used to access all of the methods of the class (which are not excluded using public, private, or protected): True or False? If false, explain why.

A - False. If one or more of the classes P, D, and Q, define instance methods which are not declared in the interface X, then a variable of type X cannot be used to access those instance methods. Those methods can only be accessed using a reference variable of the class in which the method is defined. Reference variables of the type X can only be used to access methods declared in the interface X (or one of its superinterfaces).

Q - The new operator must be used to instantiate an object which is of the type of an interface: True or False? If false, explain why.

A - False. Even though you can consider the interface name as a type for purposes of storing references to objects, you cannot instantiate an object of the interface type itself.

Q - One of the difficulties of implementing interfaces is the requirement to coordinate the definition of interface methods among the classes that implement the interface: True or False? If false, explain why.

A - False. In defining interface methods, each class defines the methods in a manner that is appropriate to its own class without concern for how it is defined in other classes.

Q - As with classes, multiple interface definitions can be combined into the same source file: True or False? If false, explain why.

A- False. The compiler requires interface definitions to be in separate files.

Q - List four ways in which interfaces are useful:

A - See the following list:

Q - A minimum interface declaration contains the Java keyword interface, the name of the interface, and the name of the interface that it extends: True or False? If false, explain why.

A - False. A minimum interface declaration contains the Java keyword interface and the name of the interface. There is no requirement to specify the name of the interface that it extends, because it may not extend another interface.

Q - An interface can extend any number of other interfaces: True or False? If false, explain why.

A - True.

Q - Just like a class definition can extend any number of other classes, an interface can extend any number of other interfaces: True or False? If false, explain why.

A - False. A class can extend only one other class.

Q - An interface can extend any number of other interfaces but not more than one class: True or False? If false, explain why.

A - False. An interface cannot extend a class.

Q - An interface inherits all constants and methods from its superinterface: True or False? If false, explain why.

A - False. See reasons below:

An interface inherits all constants and methods from its superinterface unless:

Q - The method declaration in an interface consists of the method signature followed by a pair of empty curly braces: True or False? If false, explain why.

A - False. The method declaration is terminated by a semicolon and no body (no curly braces) is provided for the method.

Q - The keyword private is used to restrict access to the members of an interface only to classes within the same package: True or False? If false, explain why.

A - False. You may not use private in a member declaration in an interface.

Q - All methods declared in an interface are implicitly public and abstract: True or False? If false, explain why.

A - True.

Q - In addition to declaring methods, the body of the interface may also define constants. Constant values defined in an interface are implicitly public, static, and final: True or False? If false, explain why.

A - True.

Q - You use an interface by defining a class that extends the interface by name: True or False? If false, explain why.

A - False. You use an interface by defining a class that implements (not extends) the interface by name.

Q - When a class claims to implement an interface, it must provide a full definition for all the methods declared in the interface as well as all of the methods declared in all of the superinterfaces of that interface: True or False? If false, explain why.

A - True.

Q - A class can implement more than one interface by including several interface names in a comma-separated list of interface names, and by providing a full definition for all of the methods declared in all of the interfaces listed as well as all of the superinterfaces of those interfaces: True or False? If false, explain why.

A - True.

Q - Whenever a class implements an interface, it is allowed to define only those methods declared in the interface: True or False? If false, explain why.

A - False. Whenever a class implements an interface, the class must define all of the methods declared in the interface, but is also free to define other methods as well.

Q - The definition of an interface is a definition of a new reference data type. You can use interface names just about anywhere that you would use other type names, except that you cannot ____________________.

A - You cannot instantiate objects of the interface type.

Q - Explain in your own words the "bottom line" benefits of the use of an interface.

A - The interface makes it possible for a method in one class to invoke methods on objects of other classes, without the requirement to know the true class of those objects, provided that those objects are all instantiated from classes that implement one or more specified interfaces. In other words, objects of classes that implement specified interfaces can be passed into methods of other objects as the generic type Object, and the methods of the other objects can invoke methods on the incoming objects by first casting them as the interface type.

Q - Write a Java program that meets the following specification.

/*File SampProg23.java from lesson 46
Copyright 1997, R.G.Baldwin
Without viewing the solution that follows, write a Java
application that illustrates the use of an interface.

Put your interface definitions in the files named 
SampProg23Intfc2.java and SampProg23Intfc1.java.

The interface named SampProg23Intfc2 contains two 
constants named pi and intConstant with values of 3.14
and 125 respectively.

The interface named SampProg23Intfc1 contains 
declarations for set() and get(). set() receives an int 
and returns void.  get() receives nothing and returns 
an int.

Implement both interfaces in ClassA and ClassB.

Implement different versions of set() and get() 
in ClassA and ClassB.

Define a show() method in ClassA that is not declared in
either interface.

Illustrate that a reference of the interface type cannot
be used to invoke the show() method.

The output from running the program should be (line breaks
were manually inserted to force the mater to fit the 
narrow format):
  
Instantiate objA of type ClassA, then set, and show data.
In set() method for classA, using pi: 12.28
In show() method for ClassA, data = 12.28

Assign objA to ref var of type SampProg23Intfc1 named 
objAA.
Invoke set() method on objAA to modify the data.
In set() method for classA, using pi: 24.56
Invoke get() method on objAA to display the modified data.
objA data = 24

Instantiate object of type ClassB named objB.  Assign
 the ref to a type SampProg23Intfc1 ref var.
Invoke its set() method to store some data.
In set() method for classB, using intConstant: 1375
Invoke its get() method to display the data.
objB data = 1375

Successfully assign objA to objB and display objB
objB data = 24

Invoke set() method on objAA to modify its data.
In set() method for classA, using pi: 98.24
Successfully assign objAA to objB and display objB
objB data = 98

Restore objB to its original type and value.
In set() method for classB, using intConstant: 1375
Successfully assign objB to objAA and display objAA
objAA data = 1375

Attempt to assign objB to objA fails because
  "Explicit cast needed to convert SampProg23Intfc1 to 
   ClassA."

Attempt to invoke show() method of objAA fails because
"Method show() not found in interface SampProg23Intfc1".
End of program.  

**********************************************************/

class ClassA implements SampProg23Intfc2,SampProg23Intfc1{
  double data;
  
  //Define versions of set() and get() appropriate to 
  // ClassA
  public void set(int inData){
    data = (double)inData*pi;//note use of pi
    System.out.println(
      "In set() method for classA, using pi: "+data);
  }//end set()
  
  public int get(){
    return (int)data;
  }//end get()
  
  //Define a show method for ClassA not declared 
  // in interface SampProg23Intfc1
  void show(){
    System.out.println(
      "In show() method for ClassA, data = " + data);
  }//end show() method
}//end ClassA
//=======================================================//
class ClassB implements SampProg23Intfc2,SampProg23Intfc1{
  int data;
  
  //Define versions of set() and get() appropriate to 
  // ClassB
  public void set(int inData){
    data = inData*intConstant;//note use of intConstant
    System.out.println(
      "In set() method for classB, using intConstant: "
        + data);
  }//end set()
  
  public int get(){
    return data;
  }//end get()
}//end ClassB
//=======================================================//
class SampProg23{
  public static void main(String[] args){
    System.out.println(
      "Instantiate objA of type ClassA, then set, and "
      + "show data.");
    ClassA objA = new ClassA();
    objA.set(2);
    objA.show();    
  
    System.out.println(
      "\nAssign objA to ref var of type SampProg23Intfc1 "
      + "named objAA.");
    SampProg23Intfc1 objAA = objA;
    System.out.println(
      "Invoke set() method on objAA to modify the data.");
    objAA.set(4);  
    System.out.println(
      "Invoke get() method on objAA to display the "
      + "modified data.");
    System.out.println("objA data = " + objAA.get());
    
    System.out.println(
      "\nInstantiate object of type ClassB named objB.  "
      + "Assign\n"
      + " the ref to a type SampProg23Intfc1 ref var.");  
    SampProg23Intfc1 objB = new ClassB();
    System.out.println(
      "Invoke its set() method to store some data."); 
    objB.set(11);
    System.out.println(
      "Invoke its get() method to display the data.");
    System.out.println("objB data = " + objB.get());

    System.out.println(
    "\nSuccessfully assign objA to objB and display objB");
    objB = objA;
    System.out.println("objB data = " + objB.get());

    System.out.println(
    "\nInvoke set() method on objAA to modify its data.");
    objAA.set(16);    
    System.out.println(
    "Successfully assign objAA to objB and display objB");
    objB = objAA;
    System.out.println("objB data = " + objB.get());
    
    System.out.println(
      "\nRestore objB to its original type and value.");
    objB = new ClassB();//objB already defined as type 
                        // SampProg23Intfc1
    objB.set(11);
    System.out.println(
    "Successfully assign objB to objAA and display objAA");
    objAA = objB;
    System.out.println("objAA data = " + objAA.get());

    System.out.println(
    "\nAttempt to assign objB to objA fails because\n"
      + "  \"Explicit cast needed to convert "
      + "SampProg23Intfc1 to ClassA.\"");
    //statement removed by making it a comment
    //objA = objB; 
    
    System.out.println(
      "\nAttempt to invoke show() method of objAA fails "
        + "because\n"
      + "\"Method show() not found in interface "
      + "SampProg23Intfc1\".");
    //statement removed by making it a comment
    //objAA.show();
    
    System.out.println("End of program.");

  }//end main
}//end class SampProg23

.

/*File SampProg23Intfc1.java from lesson 46
Copyright 1997, R.G.Baldwin
Interface definition used to support SampProg23.java
Illustrates use of interface.
*/

public interface SampProg23Intfc1{
  void set(int inData);
  int get();
}//end interface SampProg23Intfc1.java
//==================================================

.

/*File SampProg23Intfc2.java from lesson 46
Copyright 1997, R.G.Baldwin
Interface file to support File SampProg23.java
Illustrates use of interface.
*/

public interface SampProg23Intfc2{
  public final double pi = 6.14;
  public final int intConstant = 125;
}//end interface SampProg23Intfc2
//=============================================

-end-