Home >Java >javaTutorial >Abstraction: Decoding Interfaces in Java
In Java, Interfaces serve as contracts that classes must adhere to. Since an interface only provides the knowledge of what can be done (via method signatures) and hides how it is done (by leaving the implementation to the classes that implement the interface), it achieves abstraction. This separation of what from how is the core idea behind abstraction.
With Java 8, interfaces evolved beyond purely abstract behavior, supporting default and static methods to improve flexibility and backward compatibility.
This post dives into interfaces, their key features, and the distinctions between interfaces and abstract classes, with code examples to help you grasp the concepts.
An interface in Java specifies a set of behaviors (methods) that the implementing class must follow. It only contains the method signatures and constants. In contrast to abstract classes, interfaces allow multiple inheritance by enabling a class to implement more than one interface.
Variables in interfaces are implicitly public, static, and final.
All methods are implicitly public and abstract (before Java 8).
A class can implement multiple interfaces, overcoming the single inheritance limitation of classes.
From Java 8 onwards, interfaces can also contain default and static methods, enhancing backward compatibility.
package oops.interfaces; public interface InterfaceBasics { // Variables are public, static, and final by default // Initialization can only be done with declaration (No Static Blocks) // Compiler Interpretation: public static final int id = 90; int id = 90; // Abstract method (public and abstract by default) // Compiler Interpretation: public abstract void abstractMethod(); void abstractMethod(); // Default method - Introduced in Java 8 (public by default) // Compiler Interpretation: public default void concreteMethod() default void concreteMethod() { System.out.println("Concrete Method Called"); } // Static method - Introduced in Java 8 (public by default) // Compiler Interpretation: public static void staticMethod() static void staticMethod() { System.out.println("Static Method Called"); } }
1. Variables in Interfaces:
Note: static final variables can be initialized either at the time of declaration or within static blocks. However, since interfaces do not allow static blocks, these variables must be initialized during declaration.
2. Abstract Methods:
3. Default Methods:
4. Static Methods:
package oops.interfaces; public interface InterfaceBasics { // Variables are public, static, and final by default // Initialization can only be done with declaration (No Static Blocks) // Compiler Interpretation: public static final int id = 90; int id = 90; // Abstract method (public and abstract by default) // Compiler Interpretation: public abstract void abstractMethod(); void abstractMethod(); // Default method - Introduced in Java 8 (public by default) // Compiler Interpretation: public default void concreteMethod() default void concreteMethod() { System.out.println("Concrete Method Called"); } // Static method - Introduced in Java 8 (public by default) // Compiler Interpretation: public static void staticMethod() static void staticMethod() { System.out.println("Static Method Called"); } }
Method Access:
The default method (concreteMethod()) and the overridden method (abstractMethod()) are accessed using the class instance obj, demonstrating how both types of methods can be called.
Accessing Interface Variables:
The interface variable id can be accessed using both the interface name (InterfaceBasics.id) and the implementing class name (InterfaceBasicsImpl.id). This shows that static final variables in an interface are inherited, allowing the implementing class to refer to the variable.
Static Method Access:
The static method staticMethod() can only be called using the interface name (InterfaceBasics.staticMethod()). Attempting to access it through the implementing class (InterfaceBasicsImpl.staticMethod()) results in a compile-time error, as static methods in interfaces are not inherited.
package oops.interfaces; public interface InterfaceBasics { // Variables are public, static, and final by default // Initialization can only be done with declaration (No Static Blocks) // Compiler Interpretation: public static final int id = 90; int id = 90; // Abstract method (public and abstract by default) // Compiler Interpretation: public abstract void abstractMethod(); void abstractMethod(); // Default method - Introduced in Java 8 (public by default) // Compiler Interpretation: public default void concreteMethod() default void concreteMethod() { System.out.println("Concrete Method Called"); } // Static method - Introduced in Java 8 (public by default) // Compiler Interpretation: public static void staticMethod() static void staticMethod() { System.out.println("Static Method Called"); } }
Even with default methods, interfaces remain distinct from abstract classes:
|
Interface | Abstract Class | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Methods | Can have abstract, default, and static methods | Can have abstract and non-abstract methods | |||||||||||||||
Variables | Only public, static, and final variables | Can have any access modifier and instance variables | |||||||||||||||
Inheritance | Supports multiple inheritance | Supports single inheritance | |||||||||||||||
Constructors | Cannot have constructors | Can have constructors |
Default methods should be used only to extend existing interfaces where backward compatibility is needed. They are not a replacement for abstract classes.
1. Can an interface variable be modified?
No, interface variables are implicitly final, meaning their value cannot be changed once assigned.
package oops.interfaces; public interface InterfaceBasics { // Variables are public, static, and final by default // Initialization can only be done with declaration (No Static Blocks) // Compiler Interpretation: public static final int id = 90; int id = 90; // Abstract method (public and abstract by default) // Compiler Interpretation: public abstract void abstractMethod(); void abstractMethod(); // Default method - Introduced in Java 8 (public by default) // Compiler Interpretation: public default void concreteMethod() default void concreteMethod() { System.out.println("Concrete Method Called"); } // Static method - Introduced in Java 8 (public by default) // Compiler Interpretation: public static void staticMethod() static void staticMethod() { System.out.println("Static Method Called"); } }
2. Can we declare a method both default and static?
No. A default method provides a concrete implementation that can be overridden by implementing classes, allowing flexibility. In contrast, a static method belongs to the interface itself, cannot be overridden, and offers utility functions. Thus, the two cannot be used together.
package oops.interfaces; // A class implementing the InterfaceBasics interface public class InterfaceBasicsImpl implements InterfaceBasics { // Mandatory: Override all abstract methods from the interface @Override public void abstractMethod() { System.out.println("Overridden Method Called"); } public static void main(String[] args) { InterfaceBasics obj = new InterfaceBasicsImpl(); // Calling interface's default and overridden methods obj.concreteMethod(); // Output: Default Method Called obj.abstractMethod(); // Output: Overridden Method Called // Accessing interface variables (static and final by default) // Interface variables are inherited // Possible with both interface name and implementing class name System.out.println(InterfaceBasics.id); // Output: 90 System.out.println(InterfaceBasicsImpl.id); // Output: 90 // Cannot assign a value to final variable 'id' InterfaceBasicsImpl.id = 100; // --> Compile Error // Calling static method using interface name // Cannot access using implementing class name // Interface static methods are NOT inherited InterfaceBasics.staticMethod(); // Output: Static Method Called } }
3. Why Can’t Static Methods in Interfaces Be Inherited?
Static methods are associated with the interface itself rather than any specific instance of a class, meaning they belong to the interface as a whole. If static methods were inherited by implementing classes, it could lead to ambiguity and confusion about which method is being called, especially if multiple interfaces define methods with the same name.
For example:
package oops.interfaces.example; public interface Logger { // Using a variable to store the default log file name String DEFAULT_LOG_FILE_NAME = "application.log"; // Static method to get the default log file name with configuration static String getDefaultLogFileName() { // Simulating configuration retrieval // Could be from a properties file or environment variable String logFileName = System.getenv("LOG_FILE_NAME"); // If a log file name is set in the environment, return it; // Otherwise, return the default if (logFileName != null && !logFileName.isEmpty()) { return logFileName; } else { return DEFAULT_LOG_FILE_NAME; } } } public class FileLogger implements Logger { public static void main(String[] args) { // Using the interface variable String defaultLogFile = Logger.DEFAULT_LOG_FILE_NAME; // Using the static method if ("FILE".equals(System.getenv("LOG_TYPE"))) { defaultLogFile = Logger.getDefaultLogFileName(); } System.out.println("Log file used: " + defaultLogFile); } }
By keeping static methods tied only to the interface, Java maintains clarity and avoids potential conflicts in method resolution leading to the infamous Diamond Problem of Multiple Inheritance.
Interfaces in Java play a crucial role in achieving abstraction by defining the behavior that implementing classes must adhere to. With the introduction of default and static methods in Java 8, interfaces have become even more powerful, allowing backward compatibility and providing utility methods directly within interfaces.
However, interfaces are not a replacement for abstract classes. They should be used when you need to define a contract for behavior, especially when multiple inheritance is required.
Interfaces provide abstraction by defining what a class should do, without specifying how.
Variables in interfaces are always public, static, and final.
Default and static methods, introduced in Java 8, allow backward compatibility and utility implementations within interfaces.
Static methods in interfaces are not inherited, ensuring clarity in their usage.
Understanding how and when to use interfaces will not only enhance your coding skills but also prepare you for interview questions around OOPs concepts and Java design patterns.
Java Fundamentals
Array Interview Essentials
Java Memory Essentials
Java Keywords Essentials
Collections Framework Essentials
Happy Coding!
The above is the detailed content of Abstraction: Decoding Interfaces in Java. For more information, please follow other related articles on the PHP Chinese website!