Chapters
Note: Understanding of inheritance is required to understand this topic.
If a class is the blueprint of an object then interface is the blueprint of a class. Some folks call interface as "meta-class". Like standard class, interface can use the this and super keyword. Interface is a special type of class in java. Interface, like abstract class, provides abstraction. Let's create an example to demonstrate interface.
Once a class implements an interface with abstract methods, that class needs to define those abstract methods. Don't forget to follow the rules of method overriding when overriding an abstract method.
Abstract class and interface are used to achieve abstraction. Though, these two have differences:
1.) Abstract class fields can be final or non-final at the discretion of programmers whereas interface fields are final by default.
2.) Abstract class fields can be static or non-static at the discretion of programmers whereas interface fields are static by default.
3.) Abstract class fields can have different access modifier whereas interface fields are public by default.
4.) abstract keyword can be omitted in abstract methods in interface whereas abstract methods in abstract class need to explicitly include the abstract keyword.
5.) Abstract class has constructor whereas interface doesn't.
6.) Interface can have default methods whereas abstract class can't.
1.) If you want to achieve full abstraction where all methods are abstract or close to full abstraction then, it's preferrable to use interface due to its properties. If you want to achieve partial abstraction then, it's preferrable to use abstract class.
2.) You may wanna use interface if you're building a complex abstraction. We can take advatange of java's multiple inheritance support to interfaces to create a complex type of abstraction.
3.) If you want your fields to have different access modifiers or you want to mix final and non-final fields then, use abstract class.
4.) Use interface if you want an implementation that can be used by any class in your project.
We can use the extends keyword to subclass an interface by another interface. However, unlike in classes, a parent interface can subclass multiple interfaces by using a comma-separated list.
If we want a class to inherit an interface we use the implements keyword. Java supports multiple inheritance in interface. Thus, a class can inherit multiple interfaces using the implements keyword.
To resolve shadowing of variables between interfaces, we can add their interfaces names everytime we access them from the implementing class.
1.) If a super interface and its sub interface have the same method then, the implementing class only needs to override the identical methods once. This also applies to implementing class with multiple super interfaces with identical methods.
As the name implies, tag or marker interface tags of marks a class. Java has pre-defined marker interfaces like Serializable, EventListener,etc. These interfaces have special meaning to the JVM. For example, if we tag a class as serializable then the instances of that class can be serialize in a file. Take a look at this example:
This topic is pretty advance and an understanding of lambda expression is required to understand the use of this interface. Regardless, I'm gonna explain the basic concept of this interface very briefly. A functional interface is an interface with only one abstract method. However, it can have multiple default and static methods. default method is an added feature in JDK8.
This example shows the structure of a functional interface.
We know that interface can't be instantiated. However, just like abstract class, typecasting can still happen between a sub class and a super interface.
An interface can't have an inner class due to the fact that it doesn't have contructor. Although, interface can have static nested class as its member. Classes that are defined in interface are implicitly static.
Since Java 8, there are added features that improve java interface. Those improvements really pushed interface boundary making it more flexible and usable. These are the added features:
Default method also called defender method or virtual extension method was introduced in java8. Prior to java8, interface can't have defined methods.
However, having no defined methods in interface pose a problem. For example, if an interface has been implemented multiple times in a project and then we want to add another method; We have no choice but to implement that additional method to all implementing classes of that interface.
First of all, that's gonna be tedious and a frustrating work. One of the main purposes of default methods is to provide a simple way of adding new methods without updating the implementing classes. Let's take a look at this example.
If we want to access identical default methods between interfaces, we need to override the identical methods first then we can use the super keyword to call for the methods.
"ClassA inherits unrelated defaults..."
Default method can be redeclared as abstract method in another interface.
Interface can now have private and static methods. A non-private static method is implicitly public.
Like classes, interface can also be nested. An interface can be nested in a class or another interface. One of the uses of nested interface is to group interfaces that are related to each other.
An interface can have interface as its members. A nested interface in another interface is implicilty public.
An interface can be nested in a class. Unlike interface in another interface, interface in a class can have public, default or protected access modifier.
- Java Interface
- Differences Between Abstract Class And Interface
- When To Use Interface And Abstract Class
- Inheritance Between Interfaces
- Inheritance Between Class And Interface
- Tag or Marker Interface
- Functional Interface
- Calling Method Using Interface Reference
- Static Class In Interface
- Added features In Interface since Java 8
- Nested Interface
Java Interface
Note: Understanding of inheritance is required to understand this topic.
If a class is the blueprint of an object then interface is the blueprint of a class. Some folks call interface as "meta-class". Like standard class, interface can use the this and super keyword. Interface is a special type of class in java. Interface, like abstract class, provides abstraction. Let's create an example to demonstrate interface.
public class SampleClass{ public static void main(String[]args){ MyTV myTV = new MyTV(); myTV.power(); myTV.adjustLight(10); } } //interface interface Controls{ //interface variables, they're //default public and final //public and final keywords //can be omitted in interface //variables int LIGHT_LVL = 100; boolean POWER_STATE = true; //interface methods, they're //default public and abstract //the abstract and public //keywords can be omitted in //interface methods void adjustLight(int level); void power(); } //use the implements keyword to implement //an interface to a class class MyTV implements Controls{ private int lightLvl; private boolean isOff; MyTV(){ lightLvl = LIGHT_LVL; isOff = POWER_STATE; } @Override public void adjustLight(int level){ if(isOff){ System.out.println("Can't adjust brightness because "+ "TV is off..."); return; } System.out.println("Current brightness: " + lightLvl + "%"); System.out.println("Adjusting brightness by: " + level + "%"); lightLvl -= level; if(lightLvl < 0) lightLvl = 0; System.out.println("Current brightness: " + lightLvl + "%"); } @Override public void power(){ if(isOff){ isOff = false; System.out.println("power is on..."); } else{ isOff = true; System.out.println("power is off..."); } } }Variables that are declared in an interface are implicitly public,static and final; Methods that are declared in an interface are implicitly public and abstract. public,static and final can be omitted in interface variables; abstract and public can be omitted in interface methods.
Once a class implements an interface with abstract methods, that class needs to define those abstract methods. Don't forget to follow the rules of method overriding when overriding an abstract method.
Differences Between Abstract Class and Interface
Abstract class and interface are used to achieve abstraction. Though, these two have differences:
1.) Abstract class fields can be final or non-final at the discretion of programmers whereas interface fields are final by default.
2.) Abstract class fields can be static or non-static at the discretion of programmers whereas interface fields are static by default.
3.) Abstract class fields can have different access modifier whereas interface fields are public by default.
4.) abstract keyword can be omitted in abstract methods in interface whereas abstract methods in abstract class need to explicitly include the abstract keyword.
5.) Abstract class has constructor whereas interface doesn't.
6.) Interface can have default methods whereas abstract class can't.
When To Use Interface And Abstract Class
1.) If you want to achieve full abstraction where all methods are abstract or close to full abstraction then, it's preferrable to use interface due to its properties. If you want to achieve partial abstraction then, it's preferrable to use abstract class.
2.) You may wanna use interface if you're building a complex abstraction. We can take advatange of java's multiple inheritance support to interfaces to create a complex type of abstraction.
3.) If you want your fields to have different access modifiers or you want to mix final and non-final fields then, use abstract class.
4.) Use interface if you want an implementation that can be used by any class in your project.
Inheritance Between Interfaces
We can use the extends keyword to subclass an interface by another interface. However, unlike in classes, a parent interface can subclass multiple interfaces by using a comma-separated list.
public class SampleClass{ public static void main(String[]args){ } } interface SystemMenuDefaults{ String SCAN_INTERLACE = "Interlace"; String SCAN_PROGRESSIVE = "Progressive"; } interface ScreenControls{ void adjustResolution(); void scanMode(String scanType); } //an interface extending one interface interface PeripheralControls extends ScreenControls{ void moveUpAlternative(); void moveDownAlternative(); } //an interface extending two interfaces interface SystemMenu extends SystemMenuDefaults,PeripheralControls{ void screenRelatedMenu(int option); } interface Controls extends SystemMenu{ int LIGHT_LVL = 100; boolean POWER_STATE = true; void adjustLight(int level); void power(); } //The implementing class must implement //the abstract methods of parent interface //and its sub interfaces class MyTV implements Controls{ @Override public void adjustLight(int level){} @Override public void power(){} @Override public void screenRelatedMenu(int option){} @Override public void moveUpAlternative(){} @Override public void moveDownAlternative(){} @Override public void adjustResolution(){} @Override public void scanMode(String scanType){} }In the above example, we see that an interface can extend multiple interfaces. If a class implements a sub interface with parent interfaces then the class must define the abstract methods of the sub interface and its parent interfaces.
Inheritance Between Class And Interface
If we want a class to inherit an interface we use the implements keyword. Java supports multiple inheritance in interface. Thus, a class can inherit multiple interfaces using the implements keyword.
public class SampleClass{ public static void main(String[]args){ MyTV myTV = new MyTV(); myTV.power(); myTV.adjustLight(10); } } interface ControlsDefaults{ int LIGHT_LVL = 100; boolean POWER_STATE = true; } interface Controls{ void adjustLight(int level); void power(); } //class implementing multiple interfaces using //comma-separated list class MyTV implements ControlsDefaults,Controls{ private int lightLvl; private boolean isOff; MyTV(){ lightLvl = LIGHT_LVL; isOff = POWER_STATE; } @Override public void adjustLight(int level){ if(isOff){ System.out.println("Can't adjust brightness because "+ "TV is off..."); return; } System.out.println("Current brightness: " + lightLvl + "%"); System.out.println("Adjusting brightness by: " + level + "%"); lightLvl -= level; if(lightLvl < 0) lightLvl = 0; System.out.println("Current brightness: " + lightLvl + "%"); } @Override public void power(){ if(isOff){ isOff = false; System.out.println("power is on..."); } else{ isOff = true; System.out.println("power is off..."); } } }Note: A class can inherilt an interface but an interface can't inherit a class.
To resolve shadowing of variables between interfaces, we can add their interfaces names everytime we access them from the implementing class.
public class SampleClass{ public static void main(String[]args){ ClassA classA = new ClassA(); } } interface InterfaceA{ String NAME = "InterfaceA"; } interface InterfaceB{ String NAME = "InterfaceB"; } class ClassA implements InterfaceA,InterfaceB{ ClassA(){ System.out.println(InterfaceA.NAME); System.out.println(InterfaceB.NAME); } }
Ambiguous Inheritance
1.) If a super interface and its sub interface have the same method then, the implementing class only needs to override the identical methods once. This also applies to implementing class with multiple super interfaces with identical methods.
public class SampleClass{ public static void main(String[]args){ ClassA classA = new ClassA(); } } interface InterfaceA{ void message(); } interface InterfaceB extends InterfaceA{ void message(); } class ClassA implements InterfaceB{ @Override public void message(){ System.out.println("ClassA"); } ClassA(){ message(); } }2.) If the implementing class has super class, super interfaces and their super interfaces and they have identical methods then, the implementing class won't be required to override the methods in the interfaces instead, java will accept the method implementation of the super class, if there's an impelementation in the super class. If all identical methods are abstract then, the implementing class only needs to override those methods once.
public class SampleClass{ public static void main(String[]args){ ClassB classB = new ClassB(); } } interface InterfaceA{ void message(); } interface InterfaceB extends InterfaceA{ void message(); } abstract class ClassA{ public void message(){ System.out.println("ClassA"); } } class ClassB extends ClassA implements InterfaceB{ ClassB(){ message(); } }If we override message() in ClassB then, ClassB only needs to override those message() methods once.
public class SampleClass{ public static void main(String[]args){ ClassB classB = new ClassB(); } } interface InterfaceA{ void message(); } interface InterfaceB extends InterfaceA{ void message(); } abstract class ClassA{ public void message(){ System.out.println("ClassA"); } } class ClassB extends ClassA implements InterfaceB{ @Override public void message(){ System.out.println("ClassB"); } ClassB(){ super.message(); message(); } }3.) If the implementing class has super class, super interfaces and their super interfaces and they have similar methods with same names, same number of parameters but different return type then, A compile-time error will occur in the implementing class because implementing class can't override those methods because overriding those methods in one class is very similar to method overloading.
public class SampleClass{ public static void main(String[]args){ } } interface InterfaceA{ void message(); } abstract class ClassA{ //comment this method if you're gonna use //the fix abstract String message(); //1.) Try this method to fix the error //abstract String message(String message); } class ClassB extends ClassA implements InterfaceA{ @Override public void message(){} //comment this method definition if you're gonna use //the fix @Override String message(){return "";} /*2.) @Override String message(String message){ return message; } */ }The example above will throw a compile-time error. To fix the error, we can add a parameter to one of the message() methods to comply with the method overloading rules.
Tag or Marker Interface
As the name implies, tag or marker interface tags of marks a class. Java has pre-defined marker interfaces like Serializable, EventListener,etc. These interfaces have special meaning to the JVM. For example, if we tag a class as serializable then the instances of that class can be serialize in a file. Take a look at this example:
import java.io.Serializable; public class SampleClass{ public static void main(String[]args){ } } //that instances of this class can be serialize class ClassA implements Serializable{ String name; int num; }We can create our own marker interface if we wanna categorize our classes.
public class SampleClass{ public static void main(String[]args){ Rectangle rect = new Rectangle(); //check if a shape is non-intersecting if(rect instanceof NonIntersecting) System.out.println("Rectangle has no intersecting " +"line segments"); } } //tag or marker interface interface NonIntersecting{} //tag this class as non-intersecting shape class Rectangle implements NonIntersecting{ } //tag this class as non-intersecting shape class Triangle implements NonIntersecting{ } //Pentagram has intersecting line segments class Pentagram{ }
Functional Interface
This topic is pretty advance and an understanding of lambda expression is required to understand the use of this interface. Regardless, I'm gonna explain the basic concept of this interface very briefly. A functional interface is an interface with only one abstract method. However, it can have multiple default and static methods. default method is an added feature in JDK8.
This example shows the structure of a functional interface.
//@FunctionalInterface is an annotation @FunctionalInterface interface MyFunctionalInterface{ void commit(); //this method is optional in //functional interface default void greetings(){ System.out.println("Hello! This is "+ "my functional interface"); } }Java has pre-defined functional interfaces that we can use. Check out the java.util.function package. An understanding of generics is required to understand the syntax of the functional interfaces in that package.
Calling Method Using Interface Reference
We know that interface can't be instantiated. However, just like abstract class, typecasting can still happen between a sub class and a super interface.
public class SampleClass{ public static void main(String[]args){ Messenger messenger = new Messenger(); //create the interface reference and upcast //NotificationSender instance Notifications notif = new NotificationSender(); //these methods only need messageNotification() //and alertNotification methods. So, using //Notification reference will suffice here and //avoid the misuse of displayNotificationCount(). messenger.sendMessage("Hi There!",notif); messenger.sendAlert("You Battery is low!",notif); //downcast the NotificationSender instance that is //referenced in notif variable in order to access //the displayNotificationCount() method. NotificationSender ns = (NotificationSender)notif; ns.displayNotificationCount(); } } interface Notifications{ void messageNotification(); void alertNotification(); } class NotificationSender implements Notifications{ private int msgNotifCount; private int alertNotifCount; @Override public void messageNotification(){ System.out.println("Message Sent!"); msgNotifCount++; } @Override public void alertNotification(){ System.out.println("Alert! This matter is " +"somewhat important!"); alertNotifCount++; } public void displayNotificationCount(){ System.out.println("message notifation count: " +msgNotifCount); System.out.println("alert notifation count: " +alertNotifCount); } } class Messenger{ void sendMessage(String message,Notifications notif){ System.out.println(message); //call messageNotification() using the //reference of Notifications interface notif.messageNotification(); } void sendAlert(String alert,Notifications notif){ System.out.println(alert); //call alertNotification() using the //reference of Notifications interface notif.alertNotification(); } }
Static Class In Interface
An interface can't have an inner class due to the fact that it doesn't have contructor. Although, interface can have static nested class as its member. Classes that are defined in interface are implicitly static.
public class SampleClass{ public static void main(String[]args){ MyTV myTV = new MyTV(); myTV.adjustLight(); myTV.adjustVolume(); if(myTV.toggleAltControls()) myTV.useAltControls(Controls.VOLUME); } } interface Controls{ String LIGHT = "light"; String VOLUME = "volume"; //class member of interface //is static by default //static keyword can be omitted class PeripheralControls{ void adjustVolumeAlternative(){ System.out.println("Alternative Volume "+ "Controller"); } void adjustLightAlternative(){ System.out.println("Alternative Light "+ "Controller"); } } void adjustLight(); void adjustVolume(); } class MyTV implements Controls{ private PeripheralControls perpCon; private boolean isActivated; MyTV(){ isActivated = false; perpCon = new PeripheralControls(); } @Override public void adjustLight(){ System.out.println("Main Light "+ "Controller"); } @Override public void adjustVolume(){ System.out.println("Main Volume "+ "Controller"); } boolean toggleAltControls(){ isActivated = !isActivated; return isActivated; } void useAltControls(String control){ if(isActivated){ switch(control){ case Controls.LIGHT: perpCon.adjustLightAlternative(); break; case Controls.VOLUME: perpCon.adjustVolumeAlternative(); break; default: System.out.println("Invalid Input."); break; } } else System.out.println("Can't use " +"alternative controls " +"because it's not activated"); } }
Added features In Interface since Java 8
Since Java 8, there are added features that improve java interface. Those improvements really pushed interface boundary making it more flexible and usable. These are the added features:
Default Method
Default method also called defender method or virtual extension method was introduced in java8. Prior to java8, interface can't have defined methods.
However, having no defined methods in interface pose a problem. For example, if an interface has been implemented multiple times in a project and then we want to add another method; We have no choice but to implement that additional method to all implementing classes of that interface.
First of all, that's gonna be tedious and a frustrating work. One of the main purposes of default methods is to provide a simple way of adding new methods without updating the implementing classes. Let's take a look at this example.
public class SampleClass{ public static void main(String[]args){ Message1 msg1 = new Message1(); if(msg1.message(null) == false) msg1.defaultMessage(); Message2 msg2 = new Message2(); if(msg2.message(null) == false) msg2.defaultMessage(); } } interface DefaultMessage{ //default method is not required to be overriden //we can override this if it's needed default void defaultMessage(){ System.out.println("Default message"); } boolean message(String message); } class Message1 implements DefaultMessage{ //Overriding the default method @Override public void defaultMessage(){ System.out.println("Default message in Message1"); } @Override public boolean message(String message){ if(message == null) return false; System.out.println("Message1 message: " +message); return true; } } class Message2 implements DefaultMessage{ @Override public boolean message(String message){ if(message == null) return false; System.out.println("Message2 message: " +message); return true; } }In the above example, we see that we're the implementing classes are not required to override the default method. Thus, implementing classes are not required to update everytime we add default methods in our interface. Also, default method is public by default.
If we want to access identical default methods between interfaces, we need to override the identical methods first then we can use the super keyword to call for the methods.
public class SampleClass{ public static void main(String[]args){ ClassA classA = new ClassA(); } } interface InterfaceA{ default void message(){ System.out.println("InterfaceA"); } } interface InterfaceB{ default void message(){ System.out.println("InterfaceB"); } } class ClassA implements InterfaceA,InterfaceB{ //Override message() first @Override public void message(){ //call default methods using the super //keyword InterfaceA.super.message(); InterfaceB.super.message(); } ClassA(){ message(); } }If you don't override message() first, you will encounter this error:
"ClassA inherits unrelated defaults..."
Default method can be redeclared as abstract method in another interface.
public class SampleClass{ public static void main(String[]args){ ClassA classA = new ClassA(); } } interface InterfaceA{ //default method default void message(){ System.out.println("InterfaceA"); } } interface InterfaceB extends InterfaceA{ //redeclare default method as abstract method void message(); } class ClassA implements InterfaceB{ //redifine message() in implementing class @Override public void message(){ System.out.println("ClassA"); } ClassA(){ message(); } }Default method has this "static-non-static" behaviour, if you will. Default method can only access static class/interface members. However, default method can't be called like static method. Take a look at this example:
public class SampleClass{ public static void main(String[]args){ //error: can't call getName() default method directly //System.out.println(ClassA.Interface1.getName()); new ClassB(); //static method can be called directly ClassA.Interface1.setName("main"); new ClassB(); } } abstract class ClassA{ //this variable can be accessed by //default method in nested interface //because it's static private static String name = "ClassA"; //nested interface interface Interface1{ default String getName(){ return name; } static void setName(String name){ ClassA.name = name; } } } //implement Interface1 in ClassA class ClassB implements ClassA.Interface1{ ClassB(){ //default method can be called in //implementing class System.out.println(getName()); } }
Private and Static Method
Interface can now have private and static methods. A non-private static method is implicitly public.
public class SampleClass{ public static void main(String[]args){ Defaults.defaultMessage(); } } interface Defaults{ //private static method private static void defaultFont(){ System.out.println("Default Font Acquired!"); } //implicitly public static void defaultMessage(){ System.out.println("Acquiring Default Font..."); defaultFont(); System.out.println("This is a Default Message!"); } }
Nested Interface
Like classes, interface can also be nested. An interface can be nested in a class or another interface. One of the uses of nested interface is to group interfaces that are related to each other.
Interface In Another Interface
An interface can have interface as its members. A nested interface in another interface is implicilty public.
public class SampleClass{ public static void main(String[]args){ String toolToUse = Toolkit.HAMMER; switch(toolToUse){ case Toolkit.HAMMER: Toolkit.ConstructionTools.useHammer(); break; case Toolkit.SCREWDRIVER: Toolkit.HardwareTools.useScrewDriver(); break; } } } interface Toolkit{ String HAMMER = "hammer"; String NAILS = "nails"; String SCREWDRIVER = "screwdriver"; String SCREWS = "screws"; //nested interface interface ConstructionTools{ static void useHammer(){ getNails(); System.out.println("Using " + HAMMER + "..."); System.out.println("Job's Done!"); } private static void getNails(){ System.out.println("Getting nails..."); System.out.println(NAILS+" acquired!"); } } //nested interface interface HardwareTools{ static void useScrewDriver(){ getScrews(); System.out.println("Using " + SCREWDRIVER + "..."); System.out.println("Job's Done!"); } private static void getScrews(){ System.out.println("Getting screws..."); System.out.println(SCREWS+" acquired!"); } } }Here's another example:
public class SampleClass{ public static void main(String[]args){ MyConstTools mct = new MyConstTools(); mct.useHammer(); mct.useDrill(); MyCustomTools cTools = new MyCustomTools(); cTools.useTool(); } } interface Tools{ interface ConstructionTools{ void useHammer(); void useDrill(); } void useTool(); } //implement nested interface class MyConstTools implements Tools.ConstructionTools{ @Override public void useHammer(){ System.out.println("Using my hammer..."); } @Override public void useDrill(){ System.out.println("Using my drill..."); } } //implement top-level interface class MyCustomTools implements Tools{ @Override public void useTool(){ System.out.println("Using my cutom-made tool"); } }
Interface In a Class
An interface can be nested in a class. Unlike interface in another interface, interface in a class can have public, default or protected access modifier.
public class SampleClass{ public static void main(String[]args){ MyToolBox toolBox = new MyToolBox(ToolBox. WoodenBox.BOX_NAME, 7); if(ToolBox.WoodenBox.checkBox(toolBox)) System.out.println("This box is a: " + ToolBox.WoodenBox.BOX_NAME); else if(ToolBox.MetalBox.checkBox(toolBox)) System.out.println("This box is a: " + ToolBox.MetalBox.BOX_NAME); } } abstract class ToolBox{ private static String name; ToolBox(String name){ this.name = name; } //nested interface interface WoodenBox{ String BOX_NAME = "Wooden Box"; static boolean checkBox(ToolBox box){ //interface can only access static //members of a class if(box.getName() == name) return true; else return false; } } //nested interface interface MetalBox{ String BOX_NAME = "Metal Box"; static boolean checkBox(ToolBox box){ //interface can only access static //members of a class if(box.name == name) return true; else return false; } } String getName(){ return name; } } class MyToolBox extends ToolBox{ private int weight; MyToolBox(String name,int weight){ super(name); this.weight = weight; } }In the above example, we see that interface can access the name static variable in ToolBox. Remember, nested interface in a class can access static members but not instance members because nested interface behave similarly to nested static class.
No comments:
Post a Comment