- Intro to Java Objects and Classes
- Intro to Java and Static Stuff
- Intro To Java Classes Revisited
- Intro to Java Interfaces
- Intro to Java Abstract Classes
- Intro to Java Reflection
- Intro to Java Collections
- Intro to Java Generics
- Intro to Java Annotations
- Intro to Java Patterns
- Intro to Java Adapter Pattern
- Intro to Java Singleton Pattern
- Intro to Java Decorator Pattern
Interfaces are a very important part of Java. They can also be quite confusing. In this lesson, we want to take a look at Interfaces, what they are, their relationship to classes, and how and why we use them.
Sun Trails
Index: http://java.sun.com/docs/books/tutorial/index.html
Link into Object Oriented Programming Concepts Trail: (interfaces) http://java.sun.com/docs/books/tutorial/java/concepts/interface.html
What is an Interface?
I think of an interface as like a contract. If you want to fulfill a contract, you have certain obligations to fulfill. The same for a Java contract (interface). An interface defines a set of obligations that an implementing class needs to provide. The obligations are nothing more than method signatures. No code, just the signatures. The class that implements the interface provides the code.
The other thing an interface does, is it allows different classes to appear similar, at least in so far as they implement the interface. As you will see, a Bird, a Fish, and a Mammal are not the same, but if they all implement the Animal interface, then we can treat them all like Animals.
What does an Interface look like?
Here is the Animal interface. Look at the differences between this and a class.
public interface Animal {
public void speak();
public void move();
public String getName();
public void setName(String pName);
public String getType();
}
How does this compare to a class?
There are two really big differences in classes and interfaces. First is that when you create an interface, you call it an interface instead of a class. Simple enough. Second is that the method signatures have no code. They look pretty weird if you are used to seeing code behind your methods. They look like they are missing something. They are. They are missing the { } brackets, and instead have a semi colon at the end of the line. Go ahead; try to put some code into an interface. See what happens.
What about variables?
You can create variables in an interface, but they may not be what you think. If you created the name field like this :
private String name;
You would have a few problems. First, you would get a compile error. You can’t declare anything private in an interface. You wouldn’t want to anyway. If it was private you would never see it in an implementing class, and you can’t have code in this class to use it! The next part you would find, is that when you make is public, it is not an instance variable. You didn’t put the words static or final in there, but Java did for you. Any variables you define in an interface are static only.
Can you have private or protected interface methods?
Nope. All interface methods are public, for the same reason as the variables. You are implementing this interface because you want people to know what public methods you will have available to them, by contract.
In fact, some people don’t like to see you put the word “public” in front of your method signatures. You don’t need to, and by definition, they are always public, so why bother? Personally I do out of habit, and for clarity. Others are adamant about their removal. Meh!
So what would be the point of this interface thingy?
Well, if a class implements this interface, then we know what it is capable of by its interface. In this case, if a Bird, Fish and Mammal implement this interface we know that no matter what class we have we can call move() or speak() on it.
There are two really important things here. First, because of the contract concept, we know what methods are available. The second, is that interfaces participate in the “is a” concept. This is where things get cool. In our example, when a Bird implements the Animal interface, the Bird “is a” Animal. The concept is similar to when a child class extends its parent. The child “is a” parent.
How do we implement an interface?
This is how the Bird class decided to implement the interface.
/**
* Here is a simple concrete class that implements the Animal interface. It is
* concrete meaning that it can be instantiated, or created. It completes the
* Animal interface by creating the move(), speak() and getType() methods to
* complete the contract. A Bird object created from this class IS A Animal.
*
* @author Chris Ward
*/
public class Bird implements Animal {
private static final String UNNAMED = "unnamed";
private String name;
/**
* This constructor passes the actual constructing to another constructor in
* this class. In our particular example, it is necessary to call the other
* constructor. If we didn't have it, what would happen? Comment it out to
* see. We wouldn't be able to create Birds without a name. Java will not
* insert a default no argument constructor if there exists a constructor
* that takes arguments. In this constructor we pass null down to the other
* constructor. This is done to show that it is best to only have one
* constructor that actually does the work. The other constructors would be
* convenience constructors (like this one) that pass default arguments
* along, in this case, null.
*/
public Bird() {
this(null);
}
/**
* This constructor first calls a method to set the name? Why do this. It
* isn't always done, but when we know that we have a setName() method, we
* do this to avoid duplication and ensure that the functionality is
* identical.
*
* @param pName
*/
public Bird(String pName) {
setName(pName);
System.out.println("Bird created.");
}
/**
* Implements the move() method from the Animal interface
*/
public void move() {
System.out.println(getDescription() + " is flying.");
}
/**
* Implements the speak() method from the Animal interface
*/
public void speak() {
System.out.println(getDescription() + " chirps.");
}
/**
* Implements the getType() method from the Animal interface
*/
public String getType() {
return "bird";
}
/**
* Method from the Animal interface
*/
public String getName() {
return name;
}
/**
* Method from the Animal interface. It is used to handle setting a name
* from the calling of this method, or from a constructor.
*/
public void setName(String pName) {
if (pName == null || pName.length() == 0) {
name = UNNAMED;
} else {
name = pName;
}
}
/**
* This is a method that puts together a kind of description of the Animal.
* For our purposes here, it puts together the name and type depending on
* what we have. We have marked it private, because it is only used
* internally to the class.
*
* @return
*/
private String getDescription() {
StringBuilder aBuilder = new StringBuilder();
aBuilder.append("A ");
aBuilder.append(getType());
if (getName() != null && !getName().equals(UNNAMED)) {
aBuilder.append(" named ");
aBuilder.append(getName());
}
return aBuilder.toString();
}
}
/**
* Here is a simple concrete class that implements the Animal interface. It is
* concrete meaning that it can be instantiated, or created. It completes the
* Animal interface by creating the move(), speak() and getType() methods to
* complete the contract. A Fish object created from this class IS A Animal.
*
* @author Chris Ward
*/
public class Fish implements Animal {
private static final String UNNAMED = "unnamed";
private String name;
/**
* This constructor passes the actual constructing to another constructor in
* this class. In our particular example, it is necessary to call the other
* constructor. If we didn't have it, what would happen? Comment it out to
* see. We wouldn't be able to create Birds without a name. Java will not
* insert a default no argument constructor if there exists a constructor
* that takes arguments. In this constructor we pass null down to the other
* constructor. This is done to show that it is best to only have one
* constructor that actually does the work. The other constructors would be
* convenience constructors (like this one) that pass default arguments
* along, in this case, null.
*/
public Fish() {
this(null);
}
/**
* This constructor first calls a method to set the name? Why do this. It
* isn't always done, but when we know that we have a setName() method, we
* do this to avoid duplication and ensure that the functionality is
* identical.
*
* @param pName
*/
public Fish(String pName) {
setName(pName);
System.out.println("Fish created.");
}
/**
* Implements the move() method from the Animal interface
*/
public void move() {
System.out.println(getDescription() + " is swimming.");
}
/**
* Implements the speak() method from the Animal interface
*/
public void speak() {
System.out.println(getDescription() + " says glub glub.");
}
/**
* Implements the getType() method from the Animal interface
*/
public String getType() {
return "fish";
}
/**
* Method from the Animal interface
*/
public String getName() {
return name;
}
/**
* Method from the Animal interface. It is used to handle setting a name
* from the calling of this method, or from a constructor.
*/
public void setName(String pName) {
if (pName == null || pName.length() == 0) {
name = UNNAMED;
} else {
name = pName;
}
}
/**
* This is a method that puts together a kind of description of the Animal.
* For our purposes here, it puts together the name and type depending on
* what we have. We have marked it private, because it is only used
* internally to the class.
*
* @return
*/
private String getDescription() {
StringBuilder aBuilder = new StringBuilder();
aBuilder.append("A ");
aBuilder.append(getType());
if (getName() != null && !getName().equals(UNNAMED)) {
aBuilder.append(" named ");
aBuilder.append(getName());
}
return aBuilder.toString();
}
}
/**
* Here is a simple concrete class that implements the Animal interface. It is
* concrete meaning that it can be instantiated, or created. It completes the
* Animal interface by creating the move(), speak() and getType() methods to
* complete the contract. A Mammal object created from this class IS A Animal.
*
* @author Chris Ward
*/
public class Mammal implements Animal {
private static final String UNNAMED = "unnamed";
private String name;
/**
* This constructor passes the actual constructing to another constructor in
* this class. In our particular example, it is necessary to call the other
* constructor. If we didn't have it, what would happen? Comment it out to
* see. We wouldn't be able to create Birds without a name. Java will not
* insert a default no argument constructor if there exists a constructor
* that takes arguments. In this constructor we pass null down to the other
* constructor. This is done to show that it is best to only have one
* constructor that actually does the work. The other constructors would be
* convenience constructors (like this one) that pass default arguments
* along, in this case, null.
*/
public Mammal() {
this(null);
}
/**
* This constructor first calls a method to set the name? Why do this. It
* isn't always done, but when we know that we have a setName() method, we
* do this to avoid duplication and ensure that the functionality is
* identical.
*
* @param pName
*/
public Mammal(String pName) {
setName(pName);
System.out.println("Mammal created.");
}
/**
* Implements the move() method from the Animal interface
*/
public void move() {
System.out.println(getDescription() + " is walking.");
}
/**
* Implements the speak() method from the Animal interface
*/
public void speak() {
System.out.println(getDescription() + " is making noise.");
}
/**
* Implements the getType() method from the Animal interface
*/
public String getType() {
return "mammal";
}
/**
* Method from the Animal interface
*/
public String getName() {
return name;
}
/**
* Method from the Animal interface. It is used to handle setting a name
* from the calling of this method, or from a constructor.
*/
public void setName(String pName) {
if (pName == null || pName.length() == 0) {
name = UNNAMED;
} else {
name = pName;
}
}
/**
* This is a method that puts together a kind of description of the Animal.
* For our purposes here, it puts together the name and type depending on
* what we have. We have marked it private, because it is only used
* internally to the class.
*
* @return
*/
private String getDescription() {
StringBuilder aBuilder = new StringBuilder();
aBuilder.append("A ");
aBuilder.append(getType());
if (getName() != null && !getName().equals(UNNAMED)) {
aBuilder.append(" named ");
aBuilder.append(getName());
}
return aBuilder.toString();
}
}
The first line where the class is defined is the crucial part. You simple define your class as per normal, but you add the implements keyword, and the interface you would like to implement.
Then, the Bird class implements all the methods of the interface. If you delete one, you will see that the compiler will give you an error telling you that the class you are creating must implement the inherited abstract method (that you just deleted). If you are just creating a class in Eclipse, and you implement an interface, Eclipse will create method stubs for you of all the methods in the interface that you have not yet implemented if you click on the little red X beside the class name.
Class Diagram
One more time, why do we want to do this? What was the point?
Remember, we can use the “is a” relationship to our advantage. Therefore we can ask our objects to speak and move, and we don’t even care what type of object they really are. We just know that we have an Animal, and we know that by contract, we can ask them to speak and move.
When Bird implements the Animal interface, we can do this:
Animal aSparrow = new Bird();
/**
* Now we start to create "Animals". Notice that all three of the classes that
* we create objects from are all Animals. Because they all implement the Animal
* interface, we can assign them to variables that are of the type Animal.
* Because the Bird, Mammal, and Fish classes implement the Animal interface,
* you can use any method that is in the Animal interface. Under the covers the
* real object is an actual Bird, Mammal, or Fish. Therefore, when you call a
* method like move() from the Animal interface, it is executing the code from
* the actual class that was created.
*
* @author Chris Ward
*/
public class AnimalsTest3 {
public static void main(String[] pArgs) {
Animal aSparrow = new Bird();
// Creates a Bird object. As an Animal, only the methods of the Animal
// interface are available
Animal aCollie = new Mammal();
// Creates a Mammal object. As an Animal, only the methods of the Animal
// interface are available
Animal aMinno = new Fish();
// Creates a Fish object. As an Animal, only the methods of the Animal
// interface are available
System.out.println("Moving animals:");
aSparrow.move();// move method on object aSparrow of class Bird
aCollie.move(); // move method on object aCollie or class Mammal
aMinno.move(); // move method on object aMinno of class Fish
System.out.println("Getting animals to speak:");
aSparrow.speak(); // speak method on object aSparrow, of class Bird
aCollie.speak(); // speak method on object aCollie, of class Mammal
aMinno.speak(); // speak method on object aMinno, of class Fish
}
}
We can still tell aSparrow to move(), or speak(), without needing to know it is a Bird().
Don’t I always know it’s a Bird?
/**
* The real power of using an interface, is that it allows us to treat all the
* animals the same. It doesn't matter if they are a Bird, or a Fish, they all
* know how to move.
*
* @author Chris Ward
*/
public class AnimalsListTest1 {
// this gets rid of the warnings when we don't use Java 5 typing (more
// later)
@SuppressWarnings("unchecked")
public static void main(String[] pArgs) {
// creating a list that could contain any object,
// but we will just put Animals in it
List animalList = new ArrayList();
// create each object as an animal to allow us
// to treat each animal the same.
Animal sparrow = new Bird();
animalList.add(sparrow);
Animal collie = new Mammal();
animalList.add(collie);
Animal minno = new Fish();
animalList.add(minno);
System.out.println("Moving animals:");
// we iterate over the whole list
for (Iterator aIterator = animalList.iterator(); aIterator.hasNext();) {
Animal aAnimal = (Animal) aIterator.next();
aAnimal.move();
}
System.out.println("Getting animals to speak:");
for (Iterator aIterator = animalList.iterator(); aIterator.hasNext();) {
Animal aAnimal = (Animal) aIterator.next();
aAnimal.speak();
}
}
}
/**
* This example is a rewrite of CreateAnimalsList1. It has been rewritten to
* take advantage of Java 5 generics, and looping. As well, when we create the
* objects, we don't create a local reference.
*
* @author Chris Ward
*/
public class AnimalsListTest2 {
public static void main(String[] pArgs) {
// using Java 5 typed list. Only objects of type
// Animal can go in this list.
List animalList = new ArrayList();
// if we don't need references to the animals
// we create, don't create local variables for them.
animalList.add(new Bird());
animalList.add(new Mammal());
animalList.add(new Fish());
System.out.println("Moving animals:");
// We will use a Java 5 "for each" loop to minimize typing.
// if we did it with a typical for loop, it would look like this
// for (int i = 0; i < animalList.size(); i++) {
// Animal aAnimal = (Animal) animalList.get(i);
// aAnimal.move();
// }
// using Java 5 typed lists we don't need casting.
// for each means: for each and every object in a list
// ie. for every Animal in animalList, assign it to aAnimal
// here is the Java5 for each loop
for (Animal aAnimal : animalList) {
// we don't need to know what type of animal
// we are moving, just that we want them to move.
aAnimal.move();
}
System.out.println("Getting animals to speak:");
// we don't need to know what type of animal
// is speaking, just that we want them to speak.
// for every Animal in animalList, assign it to aAnimal
for (Animal aAnimal : animalList) {
aAnimal.speak();
}
}
}
Lets look at a couple of examples. First, using a collection of Animals: AnimalsListTest1 and 2. In these examples there is a list of Animals. When we use the Animals in the loop, we don't know which Animal is which when we ask it to move(), we are just telling the interface that what ever implemented the move() method should execute that method.
I wrote another class that knows nothing of Birds or Fish. It only knows Animals. It is a Cage. You can put an Animal into a cage, shake it, which makes the animal speak(), and open it, which will get the animal to move() to try to get out. This whole new object and idea simply takes place using the interface.
This is one of the benefits of coding to an interface. Other classes can take advantage of you without even knowing you exist.
/**
* Another example of using an interface. We don't know if we are dealing with
* Birds, Fish, or Mammals, but we know that they will have several methods
* available to us that we can use.
*
* @author Chris Ward
*/
public class Cage {
private Animal animal;
public void insertAnimal(Animal pAnimal) {
animal = pAnimal;
System.out.println(animal.getName() + " " + animal.getType()
+ " is in the cage.");
}
public void shakeCage() {
animal.speak();
}
public void openCage() {
animal.move();
}
}
/**
* Class to test the Cage class. The Cage class knows nothing about what type of
* animal is going to go into the cage, just that it is an Animal. Therefore, it
* knows that by contract, it can perform methods on whatever Animal is given to
* the cage from the Animal interface.
*
* @author Chris Ward
*/
public class CageTest {
public static void main(String[] args) {
Cage aCage = new Cage();
Bird aBird = new Bird("Tweety");
aCage.insertAnimal(aBird);
aCage.shakeCage();
aCage.openCage();
}
}
Nothing about Birds or Fish in here, but if you run the CageTest, you will see that you can place a bird in here and it works.
How common are Interfaces?
Very. Java uses them all the time.
Collections
The whole collections stuff is based off of interfaces. For example, I bet you have used the List before. Well, there is no Class called List. You need to have a Concrete class that you are using that implements List. Same with Map. It is just an interface. See CollectionsTest.
/**
* Shows how interfaces were used in the Java Collections code
*
* @author Chris Ward
*/
public class CollectionsTest {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
String name1 = "Brian";
String name2 = "Joe";
String name3 = "Allen";
// List is an interface. ArrayList is a concrete implementation of that
// interface. We can create an instance of ArrayList, and assign it to a
// list. This means that we can use any of the methods on list.
List arrayList = new ArrayList();
arrayList.add(name1);
arrayList.add(name2);
arrayList.add(name3);
for (int i = 0; i < arrayList.size(); i++) {
System.out.println(arrayList.get(i));
}
// TreeList is provided by the Apache group, but they implement the
// Java List interface, so we know what methods we can execute on it.
// If you don't have or install the apache-commons-collections jar, you
// will need to comment out this section or you will have compile errors
List treeList = new TreeList();
treeList.add(name1);
treeList.add(name2);
treeList.add(name3);
for (int i = 0; i < treeList.size(); i++) {
System.out.println(treeList.get(i));
}
// Map is an interface. We can create a Hashmap, or other types of maps
// that implement the Map interface.
Map hashMap = new HashMap();
hashMap.put("name1", name1);
hashMap.put("name2", name2);
hashMap.put("name3", name3);
for (int i = 0; i < hashMap.size(); i++) {
String aKey = "name" + (i + 1);
System.out.println(hashMap.get(aKey));
}
// TreeMap "is a" Map, so we can assign it to a Map
Map treeMap = new TreeMap();
treeMap.put("name1", name1);
treeMap.put("name2", name2);
treeMap.put("name3", name3);
for (int i = 0; i < treeMap.size(); i++) {
String aKey = "name" + (i + 1);
System.out.println(treeMap.get(aKey));
}
}
}
This use of interfaces was done on purpose so that other tools and classes that understand List and Map could make use of new classes that hadn't been created yet when Java created the Collection package. Look at the TreeList. It works just like the list interface we know, but it comes from the Apache Commons project.
Swing
The Swing package has interfaces all over it. Remember the listeners from the last session? They are created by coding to an interface.
When we coded Gui3 (last session) we used WindowAdapter, which was a class that implemented WindowListener (and some other interfaces) for us. Doing it that way allowed us to only override one method. But let's look at doing it again, this time we will implement the interface methods ourselves. Gui5 does this.
/**
* Simple program to create a window frame and demonstrate using an annonymous
* inner class to close the frame. This time around we are demonstrating the
* concept of codeing to an interface.
*
* @author Chris Ward
*/
public class Gui5 extends JFrame {
public Gui5() {
setTitle("Gui5");
setSize(300, 300);
// We create a class, that implements all the methods of the
// WindowListener interface. The one we are really concerned about here
// is the windowCloseing() method.
addWindowListener(new WindowListener() {
public void windowClosing(WindowEvent e) {
System.out.println("Closeing Gui5");
System.exit(0);
}
public void windowActivated(WindowEvent e) {
System.out.println("Window Activated.");
}
public void windowClosed(WindowEvent e) {
System.out.println("Window Closed.");
}
public void windowDeactivated(WindowEvent e) {
System.out.println("Window Deactivated.");
}
public void windowDeiconified(WindowEvent e) {
System.out.println("Window Deiconified.");
}
public void windowIconified(WindowEvent e) {
System.out.println("Window Iconified.");
}
public void windowOpened(WindowEvent e) {
System.out.println("Window Opened.");
}
});
}
public static void main(String[] args) {
JFrame aFrame = new Gui5();
aFrame.setVisible(true);
}
}
If you look at the WindowListener java interface, you can see how it defines what methods need to be implemented for your class to be a WindowListener. By doing this, JFrame is able to have the addWindowListener(WindowListener l) method. Now when the events occur such as closing or opening the window, it can call those methods on the class that was passed into the addWindowListener method. The JFrame class has no idea what type of windows or classes you are going to invent. It just defined a contract (WindowListener) and agrees to play by that contract (addWindowListener) to allow completely different objects to talk to each other. This is a concept called loose coupling. Using interfaces in this manner is one way to achieve this. This is a good programming concept to strive for because it makes maintenance much easier. It allows you to change code, or swap in a completely different implementation without changing the classes that use it. Far fewer hours are usually spent untangling code when it is written this way.
Type | Download Name | Version | Size | Updated | Hits |
---|