首页 > Java > java教程 > 正文

抽象:解码 Java 中的接口

Susan Sarandon
发布: 2024-11-03 06:58:02
原创
502 人浏览过

Abstraction: Decoding Interfaces in Java

在 Java 中,接口充当类必须遵守的契约。由于接口仅提供可以做什么的知识(通过方法签名)并且隐藏它是如何完成的(通过将实现留给那些实现接口),它实现了抽象什么如何的分离是抽象背后的核心思想。

在 Java 8 中,接口的发展超越了纯粹的抽象行为,支持 默认静态 方法来提高灵活性和向后兼容性

这篇文章深入探讨了接口、它们的主要特性以及接口和抽象类之间的区别,并通过代码示例来帮助您掌握概念。


什么是接口?

Java 中的接口指定实现类必须遵循的一组行为(方法)。它仅包含方法签名常量。与抽象类相比,接口通过使一个类能够实现多个接口来允许多重继承

界面的主要特点:

  • 接口中的变量隐式是公共的、静态的和最终的。

  • 所有方法都是隐式公共和抽象的(Java 8 之前)。

  • 一个类可以实现多个接口,克服类的单一继承限制。

  • Java 8开始,接口还可以包含默认方法和静态方法,增强向后兼容性。


基础知识:接口语法

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。接口中的变量:

  • public:任何实现该接口的类都可以访问。
  • static:可以直接使用接口名称访问。
  • Final:一旦初始化就防止值被修改,以确保一致性。

注意:静态最终变量可以在声明时或在静态块内初始化。但是,由于接口不允许静态块,因此这些变量必须在声明期间初始化

2。抽象方法:

  • 这些是方法签名,没有任何主体或实现。
  • 它们在界面中默认是公开的
  • 所有抽象方法必须由实现类重写

3。默认方法:

  • Java 8中引入,为接口中的方法提供默认实现
  • 这些方法默认是公共的
  • 实现类可以覆盖它们,但它不是强制性的
  • 这里,“默认”不是访问修饰符;它只是表明该方法不是抽象的并且可以有具体的实现。
  • 此功能可帮助开发人员扩展现有接口,而不会破坏向后兼容性

4。静态方法:

  • 静态方法属于接口
  • 只能使用界面名称访问它们。
  • 这些方法默认是公共的
  • 它们不通过实现类继承
  • 静态方法不能被覆盖

用 Java 实现接口

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. 方法访问:
    使用类实例 obj 访问默认方法 (concreteMethod()) 和重写方法 (abstractMethod()),演示了如何调用这两种类型的方法。

  2. 访问接口变量:
    可以使用接口名称 (InterfaceBasics.id) 和实现类名称 (InterfaceBasicsImpl.id) 来访问接口变量 id。这表明接口中的静态最终变量是继承的,允许实现类引用该变量。

  3. 静态方法访问:
    静态方法 staticMethod() 只能使用接口名称 (InterfaceBasics.staticMethod()) 进行调用。尝试通过实现类 (InterfaceBasicsImpl.staticMethod()) 访问它会导致编译时错误,因为接口中的静态方法不是继承的。


为什么使用默认方法和静态方法?

1. 默认方法

  • 在 Java 8 之前,向接口添加新方法带来了重大挑战。任何新功能都需要更新所有实现类,这通常会导致大型代码库发生重大更改。
  • 通过引入默认方法,接口现在可以为新方法提供具体实现,确保向后兼容性。这意味着现有类可以保持不变,同时仍然受益于新功能。
  • 这种设计选择也为将流和 lambda 功能添加到集合框架铺平了道路。

2. 静态方法

  • 静态方法提供与接口相关的实用函数,不需要通过实现类来覆盖。
  • 通过将静态方法绑定到接口本身并防止继承,Java 避免了多个接口之间的方法名称冲突可能引起的潜在歧义和混乱,通常称为钻石问题
  • 示例用例: 这是一个具有用于日志记录配置的静态方法的接口的实际用例:
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");
    }
}
登录后复制
登录后复制
登录后复制
登录后复制
  • 在此示例中,静态方法 getDefaultLogFileName() 提供了一种检索默认日志文件名的方法,同时保持实现简洁并封装在接口内。

接口与抽象类有何不同?

即使使用默认方法,接口仍然与抽象类不同:

Aspect 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
方面 界面 抽象类 标题> 方法 可以有抽象、默认和静态方法 可以有抽象和非抽象方法 变量 仅限公共、静态和最终变量 可以有任何访问修饰符和实例变量 继承 支持多重继承 支持单一继承 构造函数 不能有构造函数 可以有构造函数 表>

默认方法应该仅用于扩展现有接口需要向后兼容的地方。它们不能替代抽象类。


有关接口的常见面试问题

1。接口变量可以修改吗?

不,接口变量是隐式最终变量,这意味着它们的值一旦分配就不能更改。

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。我们可以声明一个默认方法和静态方法吗?

默认方法提供了可以通过实现类覆盖的具体实现,从而实现灵活性。相反,静态方法属于接口本身,不能被重写,并提供实用功能。因此,两者不能一起使用。

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。为什么接口中的静态方法不能被继承?

静态方法与接口本身相关联,而不是与类的任何特定实例相关联,这意味着它们属于整个接口。如果通过实现类继承静态方法,则可能会导致调用哪个方法的歧义和混乱,特别是如果多个接口定义具有相同名称的方法

例如:

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);
    }
}
登录后复制

通过将静态方法仅绑定到接口,Java 保持了清晰度并避免了方法解析中的潜在冲突,从而导致了臭名昭著的多重继承钻石问题


结论

Java 中的接口通过定义实现类必须遵守的行为,在实现抽象方面发挥着至关重要的作用。随着 Java 8 中 default静态方法 的引入,接口变得更加强大,允许向后兼容并直接在接口内提供实用方法。

但是,接口并不能替代抽象类。当您需要为行为定义契约时,尤其是当需要多重继承时,应该使用它们。


要点:

  • 接口通过定义类应该做什么来提供抽象,而不指定如何做。

  • 接口中的
  • 变量始终是公共的、静态的和最终的。

  • 默认方法和静态方法,在 Java 8 中引入,允许接口内的向后兼容性和实用程序实现。

  • 接口中的静态方法不会被继承,确保其用法清晰。

了解如何以及何时使用接口不仅可以提高您的编码技能,还可以帮助您为围绕OOP 概念Java 设计模式面试问题做好准备。


相关帖子

  • Java 基础知识

  • 数组面试要点

  • Java 内存基础

  • Java 关键字要点

  • 集合框架要点

编码快乐!

以上是抽象:解码 Java 中的接口的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板