Interfaces take a while to explain.
As you read the following keep in mind that a reference variable can be of a class or interface type.
COMPILE TIME AND RUNTIME ARE DISTINCT AND SEPARATE PROCESSES
When you think of how your program is structured think of compile-time and runtime as distinct.
Compile time is a simple (dumb) syntax check. The compiler looks at the data type of a reference variable to determine whether your use of it is type compatible in expressions (e.g., in assignments or when passing it as a parameter) and whether your use of dot notation is valid. The dot notation check simply checks whether the class or interface data type declares the fields and methods you reference in code. For example
Human a = new Human(); // Pretend we've coded a class Human
a.setName("Fred");
The call to "setName" will compile if class Human declares a method named "setName" that takes a single
String parameter. Note that just because it compiles doesn't mean it will run. If we coded
Human a = new Human(); // Pretend we've coded a class Human
a = null;
a.setName("Fred");
it would still compile, but obviously it would not run.
Think of the dot notation call to a method like this: "at run time, the object in this variable 'promises' to provide the following method".
INTERFACES DECLARE "WHAT," NOT "HOW"
Now let�s talk about interfaces. An interface is a description of the things an implementing class must provide -- it's a bunch of method headers, without method bodies. The interface describes "what" but not "how." The class that implements an interface will not compile until it implements those methods (actually, it would compile if you make the class abstract, but then you couldn't create object's). Basically, the class that implements the interface is fulfilling the promise to provide implementations of the methods.
So, if you declare a variable to be of an interface type the compiler just does the syntax check to verify that dot notation used with the reference variable jibes with the declarations in the interface. The compiler doesn't care that there are no method bodies in the interface declaration -- it's just doing a dumb syntax check.
At runtime Java basically "closes its eyes," goes to the object at end of the reference it finds in the variable, and tries to run the named method. If the object doesn�t implement the method then you get a runtime error. But because of the checks that go on at compile time, it shouldn't have compiled if you code didn't put an instance of an implementing class in the variable. It could still have a null (in which case it would fail at run time), but generally speaking the compiler checks make it a good bet that the object does implement the requested routine.
INTERFACES ARE VERY IMPORTANT AND USEFUL
The result of this compile time check versus runtime resolution (called "late binding," by the way) is profound. Consider the
JDBC. Most of the JDBC is just a bunch of interface declarations. In other words, there isn't much code in JDBC packages. By doing it with interfaces the people at Sun are saying "we'll tell you what these things have to do, but it's up to the vendor to figure out how."
For example, "Connection" is an interface. When you code
Connection aConnection = DriverManager.getConnection();
what kind of object is being stored in aConnection? You don't know! And better yet, you don't care! All you know is that it's an object that promises to have implemented routines declared in Connection such as createStatement(). When you code
Statement aStatement = aConnection.createStatement();
The compiler checks the syntax of "aConnection.createStatement()" to verify that the method is associated with type Statement. At runtime the object referenced by aConnection better have an implementation of the method or you'll bomb. (And it almost certainly does have an implementation, or other code wouldn't have compiled.) What kind of object is returned by the call to createStatement()? Again, you don't know and you don't care!
The beauty of all this is that you can change to another DBMS, and none of this code is affected. You'll be getting objects coded by vendor B instead of vendor A -- but since they both implement those interfaces they are guaranteed to have implementations of the methods.