Main Page

Previous Next

Interfaces

In the classes that we derived from the class Animal, we had a common method, sound(), that was implemented individually in each of the subclasses. The method signature was the same in each class, and the method could be called polymorphically. The main point to defining the class Animal first, and then subsequently the classes Dog, and Cat, and so on from it, was to be able to get polymorphic behavior. When all you want is a set of one or more methods to be implemented in a number of different classes so that you can call them polymorphically, you can dispense with the base class altogether.

You can achieve the same end result much more simply by using a Java facility called an interface. The name indicates its primary use - specifying a set of methods that represent a particular class interface, which can then be implemented appropriately in a number of different classes. All of the classes will then share this common interface, and the methods in it can be called polymorphically. This is just one aspect of what you can do using an interface. We will start by examining what an interface is from the ground up, and then look at what we can do with it.

An interface is essentially a collection of related constants and/or abstract methods, and in most cases it will contain just methods. An interface doesn't define what a method does. It just defines its form - its name, its parameters, and its return type.

To make use of an interface, you implement the interface in a class - that is, you declare that the class implements the interface and you write the code for each of the methods declared in the interface as part of the class definition. When a class implements an interface, any constants that were defined in the interface definition are available directly in the class, just as though they were inherited from a base class. An interface can contain either constants, or abstract methods, or both.

Click To expand

The methods in an interface are always public and abstract, so you do not need to specify them as such - it is considered to be bad programming practice to specify any attributes for them and you definitely cannot add any attributes other than the defaults, public and abstract. This implies that methods declared in an interface can never be static so an interface always declares instance methods. The constants in an interface are always public, static and final, so you do not need to specify the attributes for these either.

An interface is defined just like a class, but using the keyword interface rather than the keyword class. You store an interface definition in a .java file with the same name as the interface. The name that you give to an interface must be different from that of any other interface or class in the same package. Just as for classes, the members of the interface - the constants and/or method declarations - appear between braces. Let's start by looking at an interface that just defines constants.

Interfaces Containing Constants

Interfaces provide a very useful and easy to use mechanism for defining a set of constants and sharing them across several classes. Here is an interface containing only constants:

public interface ConversionFactors {
  double INCH_TO_MM = 25.4;
  double OUNCE_TO_GRAM = 28.349523125;
  double POUND_TO_GRAM = 453.5924;
  double HP_TO_WATT = 745.7;
  double WATT_TO_HP = 1.0/HP_TO_WATT;
}

You can save this in a file, ConversionFactors.java. Here we have five constants for conversions of various kinds - remember that constants defined in an interface are automatically public, static, and final. We have no choice about this - constants defined in an interface always have these attributes. Since they are static and final, you must always supply initializing values for constants defined in an interface. The names given to these use capital letters to indicate that they are final and cannot be altered - this is a common convention in Java. You can define the value of one constant in terms of a preceding constant, as in the definition of WATT_TO_HP. If you try to use a constant that is defined later in the interface - if, for example the definition for WATT_TO_HP appeared first - your code will not compile.

Since we have declared the interface as public, the constants are also available outside the package containing the ConversionFactors interface. You can access constants defined in an interface in the same way as for public and static fields in a class - by just qualifying the name with the name of the interface. For instance, you could write:

public MyClass {
  // This class can access any of the constants defined in ConversionFactors
  // by qualifying their names...
  public static double poundsToGrams(double pounds) {
    return pounds*ConversionFactors.POUND_TO_GRAM;  
  }

  // Plus the rest of the class definition...
}

Since the ConversionFactors interface only includes constants, all a class has to do to gain access to them using their unqualified names is to declare that it implements the interface. For instance, here's a class that does that:

public MyOtherClass implements ConversionFactors {
  // This class can access any of the constants defined in ConversionFactors
  // using their unqualified names, and so can any subclasses of this class...
  public static double poundsToGrams(double pounds) {
    return pounds*POUND_TO_GRAM;  
  }

  // Plus the rest of the class definition...
}

The constants defined in the ConversionFactors interface are now members of MyOtherClass and therefore will be inherited in any derived classes. Let's try a working class that implements ConversionFactors.

Try It Out - Implementing an Interface

Here's a simple class that implements the ConversionFactors interface:

public class TryConversions implements ConversionFactors {
  public static double poundsToGrams(double pounds) {
    return pounds*POUND_TO_GRAM;  
  }

  public static double inchesToMillimeters(double inches) {
    return inches*INCH_TO_MM;  
  }

  public static void main(String args[]) {
    int myWeightInPounds = 180;
    int myHeightInInches = 75;
    System.out.println("My weight in pounds: " +myWeightInPounds +
     " \t-in grams: "+ (int)poundsToGrams(myWeightInPounds));
    System.out.println("My height in inches: " +myHeightInInches +
     " \t-in millimeters: "+ (int)inchesToMillimeters(myHeightInInches));
  }
}

Compile this with the interface definition in the same directory. When you execute it, you should see the output:

My weight in pounds: 180     -in grams: 81646
My height in inches: 75     -in millimeters: 1905

How It Works

The fact that we have only used static methods to access the constants from the interface is unimportant - it's just to keep the example simple. They are equally accessible from instance methods in a class.

The two conversion methods use the conversion factors defined in the ConversionFactors interface. You can see that we can use the unqualified names for the constants defined in the interface. You could delete the implements ConversionFactors bit from the first line, and confirm that it still works if you add the interface name as a qualifier to the references to POUND_TO_GRAM and INCH_TO_MM.

Interfaces Declaring Methods

You might also want to define an interface declaring the methods to be used for conversions:

public interface Conversions {
  double inchesToMillimeters (double inches);
  double ouncesToGrams(double ounces);
  double poundsToGrams(double pounds);
  double hpToWatts(double hp);
  double wattsToHP(double watts);
}

This interface declares five methods to perform conversions. Every method declared in the interface should have a definition within the class that implements it if you are going to create objects of the class. Since the methods in an interface are, by definition, public, you must use the public keyword when you define them in your class - otherwise your code will not compile. The implementation of an interface method in a class must not have an access specifier that is more restrictive than that implicit in the abstract method declaration, and you can't get less restrictive than public.

If we want to make use of this interface in the previous example as well as the ConversionFactors interface, we could redefine the TryConversions class as:

public class TryConversions implements ConversionFactors, Conversions {
  public double wattsToHP (double watts) {
    return watts*WATT_TO_HP;  
  }
  public double hpToWatts (double hp) {
    return hp*HP_TO_WATT;  
  }

  public double ouncesToGrams(double ounces) {
    return ounces*OUNCE_TO_GRAM;  
  }

  public double poundsToGrams(double pounds) {
    return pounds*POUND_TO_GRAM;  
  }

  public double inchesToMillimeters(double inches) {
    return inches*INCH_TO_MM;  
  }

  public static void main(String args[]) {
    int myWeightInPounds = 180;
    int myHeightInInches = 75;

    TryConversions converter = new TryConversions();
    System.out.println("My weight in pounds: " +myWeightInPounds +
     " \t-in grams: "+ (int)converter.poundsToGrams(myWeightInPounds));
    System.out.println("My height in inches: " + myHeightInInches 
                       + " \t-in millimeters: " 
                       + (int)converter.inchesToMillimeters(myHeightInInches));
  }
}

Note how the methods we were using in the original definition of the class are now not declared as static. Since interface methods cannot be declared as static, we cannot make them static in the class that implements the interface. As the methods are now instance methods, we have to create a TryConversions object, converter, in order to call them.

You also may have noticed how we have implemented more than one interface in the class. A class can implement as many interfaces as you like. The names of all the interfaces that are implemented appear after the implements keyword separated by commas.

Of course, you don't have to implement every method in the interface, but there are some consequences if you don't.

A Partial Interface Implementation

You can omit the implementation of one or more of the methods from the interface in a class that implements the interface, but in this case the class inherits some abstract methods from the interface so we would need to declare the class itself as abstract:

public abstract class MyClass implements Conversions {
  // Implementation of two of the methods in the interface
  public double inchesToMillimeters(double inches) {
    return inches*INCH_TO_MM;  
  }

  public double ouncesToGrams(double ounces) {
    return ounces*OUNCE_TO_GRAM;  
  }

  // Definition of the rest of the class...
}

You cannot create objects of type MyClass. To arrive at a useful class, you must define a subclass of MyClass that implements the remaining methods in the interface. The declaration of the class as abstract is mandatory when you don't implement all of the methods that are declared in an interface. The compiler will complain if you forget to do this.

Now we know how to write the code to implement an interface, we can tie up something we met earlier in this chapter. We mentioned that you need to implement the interface Cloneable to use the inherited method clone(). In fact this interface is empty with no methods or constants, so all you need to do to implement it in a class is to specify that the class in question implements. This means that you just need to write something like:

public MyClass implements Cloneable {
   // Detail of the class...
}

The sole purpose of the Cloneable interface is to act as a flag signalling that you are prepared to allow objects of your class to be cloned. Even though you have defined a public clone() method in your class, the compiler will not permit the clone() method to be called for objects of your class type unless you also specify that your class implements Cloneable.

Extending Interfaces

You can define one interface based on another by using the keyword extends to identify the base interface name. This is essentially the same form as we use to derive one class from another. The interface doing the extending acquires all the methods and constants from the interface it extends. For example, the interface Conversions would perhaps be more useful if it contained the constants that the interface ConversionFactors contains.

We could do this by defining the interface Conversions as:

public interface Conversions extends ConversionFactors {
  double inchesToMillimeters (double inches);
  double ouncesToGrams(double ounces);
  double poundsToGrams(double pounds);
  double hpToWatts(double hp);
  double wattsToHP(double watts);
}

Now the interface Conversions also contains the members of the interface ConversionFactors. Any class implementing the Conversions interface will have the constants from ConversionFactors available to implement the methods. Analogous to the idea of a superclass, the interface ConversionFactors is referred to as a super-interface of the interface Conversions.

Interfaces and Multiple Inheritance

Unlike a class, which can only extend one other class, an interface can extend any number of other interfaces. To define an interface that inherits the members of several other interfaces, you specify the names of the interfaces separated by commas following the keyword extends. For example:

public interface MyInterface extends HisInterface, HerInterface {
  // Interface members - constants and abstract methods...
}

Now MyInterface will inherit all the methods and constants that are members of HisInterface and HerInterface. This is described as multiple inheritance. In Java, classes do not support multiple inheritance, only interfaces do.

Some care is necessary when you use this capability. If two or more super-interfaces declare a method with the same signature - that is, with identical names and parameters - the method must have the same return type in all the interfaces that declare it. If they don't, the compiler will report an error. This is because it would be impossible for a class to implement both methods, as they have the same signature. If the method is declared identically in all the interfaces that declare it, then a single definition in the class will satisfy all the interfaces. As we said in the previous chapter, every method in a class must have a unique signature, and the return type is not part of it.

Using Interfaces

What you have seen up to now has primarily illustrated the mechanics of creating an interface and incorporating it into a class. The really interesting question is - what should you use interfaces for?

We have already illustrated one use for interfaces. An interface is a very handy means of packaging up constants. You can use an interface containing constants in any number of different classes that have access to the interface. All you need to do is make sure the class implements the interface and all the constants it contains are available. The constants are static and so will be shared among all objects of a class.

An interface that declares methods defines a standard set of operations. Different classes can add such a standard interface by implementing it. Thus objects of a number of different class types can share a common set of operations. Of course, a given operation in one class may be implemented quite differently in one class compared to another. But the way in which you invoke the operation is the same for objects of all class types that implement the interface. For this reason it is often said that an interface defines a contract for a set of operations.

We hinted at the third and perhaps most important use of interfaces at the beginning of this discussion. An interface defines a type, so you can expedite polymorphism across a set of classes that implement the same interface. This is an extremely useful and powerful facility. Let's have a look at how this works.

Interfaces and Polymorphism

You can't create objects of an interface type but you can create a variable of an interface type. For example:

Conversions converter = null;                 // Variable of the Conversions interface type

If we can't create objects of type Conversions, what good is it? Well, you use it to store a reference to an object of any class type that implements Conversions. This means that you can use this variable to call methods declared in the Conversions interface polymorphically. The Conversions is not a good example to show how this works. Let's consider a real world parallel that we can use to better demonstrate this idea, that of home audio/visual equipment and a remote control. I'm grateful to John Ganter who suggested this idea to me after reading a previous edition of this book.

You almost certainly have a TV, a hi-fi, a VCR, and maybe a DVD player, around your home, and each of them will have its own remote control. All the remote controls will probably have some common subset of buttons, power on/off, volume up, volume down, mute, and so on. Once you have more than four or so remotes cluttering the place up, you might consider one of these fancy universal remote control devices to replace them - sort of a single definition of a remote control, to suit all equipment.

A universal remote has a lot of similarities to an interface. By itself a universal remote does nothing. It defines a set of buttons for standard operations, but the operation of each button must be programmed specifically to suit each kind of device that you want to control. We can represent the TV, VCR, DVD, etc. by classes, each of which will make use of the same remote control interface - the set of buttons if you like, but each in a different way. Even though it uses the same button on the remote, Power On for the TV for instance is quite different from Power On for the VCR. Let's see how that might look in a concrete example.

Try It Out - Defining Interfaces

Here's how we might define an interface to model a simple universal remote:

public interface RemoteControl {
  boolean powerOnOff();                    // Returns new state, on = true             
  int volumeUp(int increment);             // Returns new volume level
  int volumeDown(int decrement);           // Returns new volume level
  void mute();                             // Mutes sound output
  int setChannel(int channel);             // Set the channel number and return it
  int channelUp();                         // Returns new channel number
  int channelDown();                       // Returns new channel number
}

The methods declared here in the RemoteControl interface should be self-explanatory. We have included just a few of the many possible remote operations here to conserve space in the book. You could add more if you want. You could have separate power on and off methods for instance, tone controls, and so on. There is no definition for any of these methods here. Methods declared in an interface are always abstract - by definition. There is also no access attribute for any of them. Methods declared in an interface are always public by default.

Now any class that requires the use of the functionality provided by a RemoteControl just has to declare that it implements the interface, and include the definitions for each of the methods in the interface. For example, here's the TV:

public class TV implements RemoteControl {
  public TV(String make, int screensize) {
    this.make = make;
    this.screensize = screensize;
    // In practice you would probably have more 
    // arguments to set the max and min channel 
    // and volume here plus other characteristics for a particular TV. 
  }

  public boolean powerOnOff() {
    power = !power;
    System.out.println(make + " "+ screensize + " inch TV power " 
                    + (power ? "on.":"off."));
    return power;
  }

  public int volumeUp(int increment) {
     if(!power)                   // If the power is off
       return 0;                  // Nothing works

    // Set volume - must not be greater than the maximum
    volume = volume+increment > MAX_VOLUME ? MAX_VOLUME : volume+increment; 
    System.out.println(make + " "+ screensize + " inch TV volume level: "
                     + volume);
    return volume;
  }

  public int volumeDown(int decrement) {
    if(!power)                   // If the power is off
      return 0;                  // Nothing works

    // Set volume - must not be less than the minimum
    volume = volume-decrement < MIN_VOLUME ? MIN_VOLUME : volume-decrement; 
    System.out.println(make + " "+ screensize + " inch TV volume level: "
                     + volume);
    return volume;
  }

  public void mute() {
    if(!power)                   // If the power is off
      return;                    // Nothing works

    volume = MIN_VOLUME;
    System.out.println(make + " "+ screensize + " inch TV volume level: "
                     + volume);
  }

  public int setChannel(int newChannel) {
    if(!power)                   // If the power is off
      return 0;                  // Nothing works

    // Channel must be from MIN_CHANNEL to MAX_CHANNEL 
    if(newChannel>=MIN_CHANNEL && newChannel<=MAX_CHANNEL);
      channel = newChannel;  
    System.out.println(make + " "+ screensize + " inch TV tuned to channel: "
                     + channel);
    return channel;
  }

  public int channelUp() {
    if(!power)                   // If the power is off
      return 0;                  // Nothing works

    // Wrap channel up to MIN_CHANNEL when MAX_CHANNEL is reached
    channel = channel<MAX_CHANNEL ? ++channel : MIN_CHANNEL;  
    System.out.println(make + " "+ screensize + " inch TV tuned to channel: "
                     + channel);
    return channel;
  }

  public int channelDown() {
    if(!power)                   // If the power is off
      return 0;                  // Nothing works

    // Wrap channel down to MAX_CHANNEL when Min_CHANNEL is reached
    channel = channel>MIN_CHANNEL ? --channel : MAX_CHANNEL;  
    System.out.println(make + " "+ screensize + " inch TV tuned to channel: "
                     + channel);
    return channel;
  }

  private String make = null;            
  private int screensize = 0;
  private boolean power = false;

  private int MIN_VOLUME = 0;
  private int MAX_VOLUME = 100;
  private int volume = MIN_VOLUME;

  private int MIN_CHANNEL = 0;
  private int MAX_CHANNEL = 999;
  private int channel = 0;
}

This class implements all the methods declared in the RemoteControl interface, and each method outputs a message to the command line so we'll know when it is called. Of course, if we missed out any of the interface method definitions in the class, the class would be abstract and we would have to declare it as such.

A VCR class might also implement RemoteControl:

public class VCR implements RemoteControl {
  public VCR(String make) {
    this.make = make;
  }

  public boolean powerOnOff() {
    power = !power;
    System.out.println(make + " VCR power "+ (power ? "on.":"off."));
    return power;
  }

  public int volumeUp(int increment) {
     if(!power)                   // If the power is off
       return 0;                  // Nothing works

    // Set volume - must not be greater than the maximum
    volume = volume+increment > MAX_VOLUME ? MAX_VOLUME : volume+increment; 
    System.out.println(make + " VCR volume level: "+ volume);
    return volume;
  }

  public int volumeDown(int decrement) {
     if(!power)                   // If the power is off
       return 0;                  // Nothing works

    // Set volume - must not be less than the minimum
    volume = volume-decrement < MIN_VOLUME ? MIN_VOLUME : volume-decrement; 
    System.out.println(make + " VCR volume level: "+ volume);
    return volume;
  }

  public void mute() {
     if(!power)                   // If the power is off
       return;                    // Nothing works

    volume = MIN_VOLUME;
    System.out.println(make + " VCR volume level: "+ volume);
  }

  public int setChannel(int newChannel) {
    if(!power)                   // If the power is off
      return 0;                  // Nothing works

    // Channel must be from MIN_CHANNEL to MAX_CHANNEL 
    if(newChannel>=MIN_CHANNEL && newChannel<=MAX_CHANNEL)
      channel = newChannel;  
    System.out.println(make + " VCR tuned to channel: "+ channel);
    return channel;
  }

  public int channelUp() {
    if(!power)                   // If the power is off
      return 0;                  // Nothing works

    // Wrap channel up to MIN_CHANNEL when MAX_CHANNEL is reached
    channel = channel<MAX_CHANNEL ? ++channel : MIN_CHANNEL;  
    System.out.println(make + " VCR tuned to channel: "+ channel);
    return channel;
  }

  public int channelDown() {
    if(!power)                   // If the power is off
      return 0;                  // Nothing works

    // Wrap channel down to MAX_CHANNEL when Min_CHANNEL is reached
    channel = channel>MIN_CHANNEL ? --channel : MAX_CHANNEL;  
    System.out.println(make + " VCR tuned to channel: "+ channel);
    return channel;
  }

  private String make = null;            
  private boolean power = false;

  private int MIN_VOLUME = 0;
  private int MAX_VOLUME = 100;
  private int volume = MIN_VOLUME;

  private int MIN_CHANNEL = 0;
  private int MAX_CHANNEL = 99;
  private int channel = 0;
}

Of course, we could continue, and define classes for other kinds of devices that used the remote, but these two will be sufficient to demonstrate the principle.

Let's see how we can use the RemoteControl interface and these two classes in a working example.

Try It Out - Polymorphism Using an Interface Type

We want to demonstrate polymorphic behavior with these classes. By introducing a bit of 'randomness' into our example, we can avoid having any prior knowledge of the objects involved. Here's the class to operate both TV and VCR objects via a variable of type RemoteControl:

public class TryRemoteControl {
  public static void main(String args[]) {
    RemoteControl remote = null;

    // We will create five objects to operate using our remote
    for(int i = 0 ; i<5 ; i++) {
      // Now create either a TV or a VCR at random
      if(Math.random()<0.5)
        // Random choice of TV make and screen size
        remote = new TV(Math.random()<0.5 ? "Sony" : "Hitachi", 
                        Math.random()<0.5 ? 32 : 28);           
      else // Random choice of VCR
        remote = new VCR(Math.random()<0.5 ? "Panasonic": "JVC"); 

      // Now operate it, whatever it is
      remote.powerOnOff();                 // Switch it on
      remote.channelUp();                  // Set the next channel up
      remote.volumeUp(10);                 // Turn up the sound
    }
  }
}

This should be in the same directory as the other two class, and the interface. When you compile and run this, you should see output recording a random selection of five TV and VCR objects operated by our RemoteControl variable. I got:

Sony 28 inch TV power on.
Sony 28 inch TV tuned to channel: 1
Sony 28 inch TV volume level: 10
Panasonic VCR power on.
Panasonic VCR tuned to channel: 1
Panasonic VCR volume level: 10
Sony 32 inch TV power on.
Sony 32 inch TV tuned to channel: 1
Sony 32 inch TV volume level: 10
JVC VCR power on.
JVC VCR tuned to channel: 1
JVC VCR volume level: 10
Sony 28 inch TV power on.
Sony 28 inch TV tuned to channel: 1
Sony 28 inch TV volume level: 10

How It Works

The variable remote is of type RemoteControl so we can use it to store a reference to any class object that implements the RemoteControl interface. Within the for loop, we create either a TV or a VCR object at random. The TV or VCR object will be of a randomly chosen make, and any TV object will be either 28" or 32" - again chosen at random. The object that is created is then operated through remote by calling its powerOnOff(), channelUp(), and volumeUp() methods. Since the type of the object is determined at runtime, and at random, the output demonstrates we are clearly seeing polymorphism in action here through a variable of an interface type.

Using Multiple Interfaces

Of course, a RemoteControl object in the previous example can only be used to call the methods that are declared in the interface. If a class implements some other interface besides RemoteControl, then to call the methods declared in the second interface you would either need to use a variable of that interface type to store the object reference, or to cast the object reference to its actual class type. Suppose we have a class defined as:

public MyClass implements RemoteControl, AbsoluteControl {
   // Class definition including methods from both interfaces...
}

Since this class implements RemoteControl and AbsoluteControl, we can store an object of type MyClass in a variable of either interface type. For example:

AbsoluteControl ac = new MyClass();

Now we can use the variable ac to call methods declared in the AbsoluteControl interface. However, we cannot call the methods declared in the RemoteControl interface using ac, even though the object reference that it holds has these methods. One possibility is to cast the reference to the original class type, like this:

((MyClass)ac).powerOnOff();

Since we cast the reference to type MyClass, we can call any of the methods defined in that class. We can't get polymorphic behavior like this though. The compiler will determine the method that is called when the code is compiled. To call the methods in the RemoteControl interface polymorphically, you would have to have the reference stored as that type. Provided you know that the object is of a class type that implements the RemoteControl interface, you can get from the reference store in the variable ac to a reference of type RemoteControl. Like this for example:

if(ac instanceof RemoteControl)
  ((RemoteControl)ac).mute();

Even though the interfaces RemoteControl and AbsoluteControl are unrelated, you can cast the reference in ac to type RemoteControl. This is possible because the object that is referenced by ac is actually of type MyClass, which happens to implement both interfaces and therefore incorporates both interface types.

If you got a bit lost in this last section don't worry about it. You won't need this level of knowledge about interfaces very often.

Nesting Classes in an Interface Definition

You can put the definition of a class inside the definition of an interface. The class will be an inner class to the interface. An inner class to an interface will be static and public by default. The code structure would be like this:

interface Port {
  // Methods & Constants declared in the interface...

  class Info {
    // Definition of the class...
  }
}

This declares the interface, Port, with an inner class, Info. Objects of the inner class would be of type Port.Info. You might create one with a statement like this:

Port.Info info = new Port.Info();

The standard class library includes a number of interfaces with inner classes, including one with the name Port (in the javax.sound.sampled package) that has an inner class with the name Info, although the Info class does not have the default constructor that we have used in the illustration here. The circumstances where you might define a class as an inner class to an interface would be when objects of the inner class type have a strong logical association with the interface.

A class that implements the interface would have no direct connection with the inner class to the interface - it would just need to implement the methods declared by the interface, but it is highly likely it would make use of objects of the inner class type.

Interfaces and the Real World

An interface type is sometimes used to reference an object that encapsulates something that exists outside of Java, such as a particular physical device. This is done when the external device does not require methods implemented in Java code because all the function is provided externally. The interface method declarations just identify the mechanism for operating on the external object.

The example of the Port interface in the library is exactly that. A reference of type Port refers to an object that is a physical port on a sound card, such as that for the speaker or the microphone. The inner class, Port.Info, defines objects that encapsulate data to define a particular port. You can't create a Port object directly since there is no class of type Port. Indeed it doesn't necessarily make sense to do so since your system may not have any ports. Assuming your PC has sound ports you obtain a reference of type Port to an object that encapsulates a real port such as the microphone, by calling a static method defined in another class. The argument to the method would be a reference to an object of type Port.Info specifying the kind of port that you want. All of the methods defined in the Port interface would correspond to methods written in native machine code that would operate on the port. To call them you just use the Port reference that you have obtained.

Previous Next
JavaScript Editor Java Tutorials Free JavaScript Editor