Interfaces
- 100% developed as of Nov 9, 2012 Defining classes
- 100% developed as of Dec 5, 2013 Inheritance
- 100% developed as of Dec 5, 2013 Interfaces
- 75% developed as of Jun 4, 2013 Overloading methods and constructors
- 75% developed as of Nov 20, 2013 Object Lifecycle
- 100% developed as of Nov 20, 2013 Scope
- 75% developed as of Oct 27, 2006 Nested classes
- 100% developed as of Dec 5, 2013 Generics
An interface is an abstraction of class with no implementation details. For example, java.lang.Comparable
is a standard interface in Java. You cannot instantiate an interface. An interface is not a class but it is written the same way. The first difference is that you do not use the class
keyword but the interface
keyword to define it. Then, there are fields and methods you cannot define here:
- A field is always a constant: it is always public, static and final, even if you do not mention it.
- A method must be public and abstract, but it is not required to write the
public
andabstract
keywords. - Constructors are forbidden.
An interface represents a contract:
publicinterface SimpleInterface{ publicstaticfinalintCONSTANT1=1; intmethod1(Stringparameter); }
You can see that the method1()
method is abstract (unimplemented). To use an interface, you have to define a class that implements it, using the implements
keyword:
publicclass ClassWithInterfaceimplementsSimpleInterface{ publicintmethod1(Stringparameter){ return0; } }
A class can implement several interfaces, separated by a comma. Java interfaces behave much like the concept of the Objective-C protocol. It is recommended to name an interface <verb>able
, to mean the type of action this interface would enable on a class. However, it is not recommended to start the name of an interface by I
as in C++. It is useless. Your IDE will help you instead.
Interest
[edit | edit source ]If you have objects from different classes that do not have a common superclass, you can't call the same method in those classes, even if the two classes implement a method with the same signature.
publicclass OneClass{ publicintmethod1(Stringparameter){ return1; } }
publicclass AnotherClass{ publicintmethod1(Stringparameter){ return2; } }
publicstaticvoidmain(String[]args){ doAction(newOneClass()); doAction(newAnotherClass()); } publicvoiddoAction(ObjectanObject){ anObject.method1("Hello!"); }
The solution is to write an interface that defines the method that should be implemented in the two classes as the SimpleInterface
in the Code listing 4.14 and then both classes can implement the interface as in the Code listing 4.15.
publicstaticvoidmain(String[]args){ doAction(newClassWithInterface()); doAction(newAnotherClassWithInterface()); } publicvoiddoAction(SimpleInterfaceanObject){ anObject.method1("Hello!"); }
You can also implement this using a common super class but a class can only inherit from one super class whereas it can implement several interfaces.
Java does not support full orthogonal multiple inheritance (i.e. Java does not allow you to create a subclass from two classes). Multiple inheritance in C++ has complicated rules to disambiguate fields and methods inherited from multiple superclasses and types that are inherited multiple times. By separating interface from implementation, interfaces offer much of the benefit of multiple inheritance with less complexity and ambiguity. The price of no multiple inheritance is some code redundancy; since interfaces only define the signature of a class but cannot contain any implementation, every class inheriting an interface must provide the implementation of the defined methods, unlike in pure multiple inheritance, where the implementation is also inherited. The major benefit of that is that all Java objects can have a common ancestor (a class called Object
).
When overriding methods defined in interfaces there are several rules to be followed:
- Checked exceptions should not be declared on implementation methods other than the ones declared by the interface method or subclasses of those declared by the interface method.
- The signature of the interface method and the same return type or subtype should be maintained when implementing the methods.
- All the methods of the interface need to be defined in the class, unless the class that implements the interface is abstract.
Extending interfaces
[edit | edit source ]An interface can extend several interfaces, similar to the way that a class can extend another class, using the extends
keyword:
publicinterface InterfaceA{ publicvoidmethodA(); }
publicinterface InterfaceB{ publicvoidmethodB(); }
publicinterface InterfaceABextendsInterfaceA,InterfaceB{ publicvoidotherMethod(); }
This way, a class implementing the InterfaceAB
interface has to implement the methodA()
, the methodB()
and the otherMethod()
methods:
publicclass ClassABimplementsInterfaceAB{ publicvoidmethodA(){ System.out.println("A"); } publicvoidmethodB(){ System.out.println("B"); } publicvoidotherMethod(){ System.out.println("foo"); } publicstaticvoidmain(String[]args){ ClassABclassAb=newClassAB(); classAb.methodA(); classAb.methodB(); classAb.otherMethod(); } }
Doing so, a ClassAB
object can be casted into InterfaceA
, InterfaceB
and InterfaceAB
.
Question 4.2: Consider the following interfaces.
publicinterface Walkable{ voidwalk(); }
publicinterface Jumpable{ voidjump(); }
publicinterface Swimable{ voidswim(); }
publicinterface MovableextendsWalkable,Jumpable{ }
List all the methods that an implementing class of Movable
should implement.
walk()
jump()
publicclass PersonimplementsMovable{ publicvoidwalk(){ System.out.println("Do something."); } publicvoidjump(){ System.out.println("Do something."); } }
Question 4.3: Consider the following classes and the following code.
importjava.util.Date; publicclass ConsoleLogger{ publicvoidprintLog(Stringlog){ System.out.println(newDate()+": "+log); } }
importjava.io.File; importjava.io.FileOutputStream; publicclass FileLogger{ publicvoidprintLog(Stringlog){ try{ Filefile=newFile("log.txt"); FileOutputStreamstream=newFileOutputStream(file); byte[]logInBytes=(newDate()+": "+log).getBytes(); stream.write(logInBytes); stream.flush(); stream.close(); }catch(Exceptione){ e.printStackTrace(); } } }
Object[]loggerArray=newObject[2]; loggerArray[0]=newConsoleLogger(); loggerArray[1]=newFileLogger(); for(Objectlogger:loggerArray){ // logger.printLog("Check point."); }
Change the implementation of the code in order to be able to uncomment the commented line without compile error.
You have to create an interface that defines the method printLog(String)
and makes ConsoleLogger
and FileLogger
implement it:
publicinterface Logger{ voidprintLog(Stringlog); }
importjava.util.Date; publicclass ConsoleLoggerimplementsLogger{ publicvoidprintLog(Stringlog){ System.out.println(newDate()+": "+log); } }
importjava.io.File; importjava.io.FileOutputStream; publicclass FileLoggerimplementsLogger{ publicvoidprintLog(Stringlog){ try{ Filefile=newFile("log.txt"); FileOutputStreamstream=newFileOutputStream(file); byte[]logInBytes=(newDate()+": "+log).getBytes(); stream.write(logInBytes); stream.flush(); stream.close(); }catch(Exceptione){ e.printStackTrace(); } } }
Now your code has to cast the objects to the Logger
type and then you can uncomment the code.
Logger[]loggerArray=newLogger[2]; loggerArray[0]=newConsoleLogger(); loggerArray[1]=newFileLogger(); for(Loggerlogger:loggerArray){ logger.printLog("Check point."); }