Maison > Java > javaDidacticiel > Quel est le rôle des interfaces en Java ?

Quel est le rôle des interfaces en Java ?

WBOY
Libérer: 2023-04-26 14:28:07
avant
2436 Les gens l'ont consulté

1. Qu'est-ce qu'une classe abstraite

Avant d'expliquer l'interface, la classe abstraite est un concept qui ne peut être contourné. L'interface peut être considérée comme une classe plus abstraite qu'une classe abstraite.

Qu'est-ce qu'un cours abstrait ? "Une classe qui contient une ou plusieurs méthodes abstraites est une classe abstraite, et une méthode abstraite est une méthode sans corps de méthode." Les méthodes abstraites et les classes abstraites doivent être déclarées comme abstract. Par exemple : abstract。例如:

<code>// 抽象类<br>public abstract class Person {<br>    // 抽象方法<br> public abstract String getDescription();<br>}</code>
Copier après la connexion

切记!「除了抽象方法之外,抽象类还可以包含具体数据和具体方法」。例如, 抽象类 Person 还保存着姓名和一个返回姓名的具体方法:

<code>public abstract class Person{<br>    private String name;<br>    public Person(String name){<br>     this.name = name ;<br>    }<br>    public abstract String getDescription();<br>    public String getName(){<br>     return name;<br>    }<br>}</code>
Copier après la connexion
❝  

许多程序员都会「错误」的认为,在抽象类中不能包含具体方法。其实这也是接口和抽象类的不同之处,接口中是不能包含具体方法的。

❞  

「抽象类不能被实例化」。也就是说,如果将一个类声明为 abstract, 就不能创建这个类的对象。

<code>new Person("Jack"); // Error</code>
Copier après la connexion

可以定义一个抽象类的对象变量, 但是它只能引用非抽象子类的对象。假设 Student 类是 Person 的非抽象子类:

<code>Person p = new Student("Jack"); // Right</code>
Copier après la connexion

所谓非抽象子类就是说,如果创建一个继承抽象类的子类并为之创建对象,那么就「必须为父类的所有抽象方法提供方法定义」。如果不这么做(可以选择不做),子类仍然是一个抽象类,编译器会强制我们为新类加上 abstract 关键字。

下面定义扩展抽象类 Person 的具体子类 Student

<code>public class Student extends Person { <br>    private String major; <br>    public Student(String name, String major) { <br>        super(name); <br>        this.major = major; <br>    } <br>    @Override<br>    public String getDescription(){ // 实现父类抽象方法<br>     return "a student majoring in " + major; <br>    } <br>} </code>
Copier après la connexion

在 Student 类中实现了父类中的抽象方法 getDescription 。因此,「在 Student类中的全部方法都是非抽象的, 这个类不再是抽象类」

???? 调用如下:

<code>Person p = new Student("Jack","Computer Science");<br>p.getDescription();<br></code>
Copier après la connexion
 

由于不能构造抽象类 Person的对象, 所以变量 p 永远不会引用 Person 对象, 而是引用诸如 Student这样的具体子类对象, 而这些对象中都重写了 getDescription方法。 

2. 什么是接口

接口的本质其实也是一个类,而且是一个比抽象类还要抽象的类。怎么说呢?抽象类是能够包含具体方法的,而接口杜绝了这个可能性,「在 Java 8 之前,接口非常纯粹,只能包含抽象方法,也就是没有方法体的方法」。而 Java 8 中接口出现了些许的变化,开始允许接口包含默认方法和静态方法,这个下文会讲解。

Java 使用关键字 interface 而不是 class 来创建接口。和类一样,通常我们会在关键字 interface 前加上 public 关键字,否则接口只有包访问权限,只能在接口相同的包下才能使用它。

<code>public interface Concept {<br>    void idea1();<br>    void idea2();<br>}</code> 
Copier après la connexion

同样的,接口中既然存在抽象方法,那么他就需要被扩展(继承)。使用 implements 关键字使一个类扩展某个特定接口(或一组接口),通俗来说:接口只是外形,现在这个扩展子类要说明它是如何工作的。

<code>class Implementation implements Concept {<br>    @Override<br>    public void idea1() {<br>        System.out.println("idea1");<br>    }<br>    <br>    @Override<br>    public void idea2() {<br>        System.out.println("idea2");<br>    }<br>}<br></code>
Copier après la connexion
 

这里需要注意的是,你可以选择显式地声明接口中的方法为 public,但是「即使你不这么做,它们也是 public 的」。所以当实现一个接口时,来自接口中的方法必须被定义为 public。否则,它们只有包访问权限,这样在被继承时,它们的可访问权限就被降低了,这是 Java 编译器所不允许的。

另外,接口中是允许出现常量的,与接口中的方法都自动地被设置为 public—样,「接口中的域将被自动被设置为 public static final 类型」,例如:

<code>public interface Concept {<br> void idea1(); // public void idea1();<br>    // 静态属性<br> double item = 95; // a public static final constant<br>}</code> 
Copier après la connexion
❝  

可以将接口方法标记为 public,将域标记为 public static final。有些程序员出于习惯或提高清晰度的考虑, 愿意这样做。但 Java 语言规范却「建议不要书写这些多余的关键字」

❞  

3. 接口的特性

接口和类其中不同的一点就是,我们「无法像类一样使用 new

<code>x = new Concept(. . .); // ERROR</code> 
Copier après la connexion
Souviens-toi !

"En plus des méthodes abstraites, les classes abstraites peuvent également contenir des données concrètes et des méthodes concrètes"

. Par exemple, la classe abstraite Person enregistre également le nom et une méthode concrète qui renvoie le nom :

<code>Concept x; // OK</code> 
Copier après la connexion
Copier après la connexion

De nombreux programmeurs croiront

"à tort" 🎜 que le béton ne peut pas être inclus dans un méthode de classe abstraite. En fait, c'est aussi la différence entre les interfaces et les classes abstraites. Les interfaces ne peuvent pas contenir de méthodes spécifiques. 🎜❞
🎜🎜"Les classes abstraites ne peuvent pas être instanciées"🎜. En d'autres termes, si une classe est déclarée comme abstract, les objets de cette classe ne peuvent pas être créés. 🎜
<code>x = new Implementation(. . .); // OK provided Implementation implements Concept</code> 
Copier après la connexion
Copier après la connexion
🎜 peut définir une variable objet d'une classe abstraite, mais elle ne peut faire référence qu'à des objets de sous-classes non abstraites. Supposons que la classe Student soit une sous-classe non abstraite de Person : 🎜
<code>if(x instanceof Concept){<br> ...<br>}</code> 
Copier après la connexion
Copier après la connexion
🎜La sous-classe dite non abstraite signifie que si vous créez une sous-classe qui hérite de l'abstrait classe et crée un objet pour elle, alors 🎜"Les définitions de méthodes doivent être fournies pour toutes les méthodes abstraites de la classe parent"🎜. Si vous ne le faites pas (vous pouvez choisir de ne pas le faire), la sous-classe sera toujours une classe abstraite et le compilateur nous forcera à ajouter le mot-clé abstract à la nouvelle classe. 🎜🎜Ce qui suit définit la sous-classe spécifique Student de la classe abstraite étendue Person : 🎜
<code>public interface Concept1 {<br>    void idea1();<br>    void idea2();<br>}<br><br>-------------------------------------------<br>    <br>public interface Concept2 extends Concept1{<br> double idea3();<br>}</code> 
Copier après la connexion
Copier après la connexion
🎜implémente la méthode abstraite dans la classe parent dans le Student classe getDescription. Par conséquent, 🎜"Toutes les méthodes de la classe Student sont non abstraites, et cette classe n'est plus une classe abstraite"🎜. 🎜🎜 ???? L'appel est le suivant : 🎜
<code>class Implementation implements Concept1, Concept2 // OK</code> 
Copier après la connexion
Copier après la connexion
🎜Puisque l'objet de la classe abstraite Person ne peut pas être construit, la variable p ne fera jamais référence à Person Object, mais fait référence à des objets de sous-classe spécifiques tels que Student, et la méthode getDescription est remplacée dans ces objets. 🎜

2. Qu'est-ce qu'une interface ? 🎜🎜L'essence d'une interface est en fait une classe, et c'est une classe qui est plus abstraite qu'une classe abstraite. Comment le dire ? Les classes abstraites peuvent contenir des méthodes concrètes, mais les interfaces éliminent cette possibilité. 🎜 "Avant Java 8, les interfaces étaient très pures et ne pouvaient contenir que des méthodes abstraites, c'est-à-dire des méthodes sans corps de méthode." Il y a eu quelques changements dans l'interface de Java 8, et l'interface a commencé à être autorisée à contenir des méthodes par défaut et des méthodes statiques, qui seront expliquées ci-dessous. 🎜🎜Java utilise le mot-clé interface au lieu de class pour créer des interfaces. Comme les classes, nous ajoutons généralement le mot-clé public avant le mot-clé interface. Sinon, l'interface n'a que des droits d'accès au package et ne peut être utilisée que sous le package avec la même interface. . 🎜
<code>public interface Concept {<br>    // 静态方法<br> public static void get(String name){<br>     System.out.println("hello " + name);<br>    }<br>    // 默认方法<br>    default void idea1(){<br>        System.out.println("this is idea1");<br>    };<br>}</code> 
Copier après la connexion
Copier après la connexion
🎜De même, puisqu'il existe une méthode abstraite dans l'interface, elle doit être étendue (héritée). Utilisez le mot-clé implements pour qu'une classe étende une interface spécifique (ou un groupe d'interfaces). En termes simples : l'interface n'est que l'apparence. Maintenant, cette sous-classe étendue doit expliquer comment elle fonctionne. 🎜
<code>interface A {<br> default void idea(){<br>  System.out.println("this is A");<br> }<br>}<br><br>interface B {<br> default void idea(){<br>  System.out.println("this is B");<br> }<br>}<br><br>// 需要在 D 类中覆盖 idea 方法<br>class D implements A, B{<br>    public void getName(){<br>     System.out.println("this is D");<br>    }<br>}</code> 
Copier après la connexion
Copier après la connexion
🎜Il convient de noter ici que vous pouvez choisir de déclarer explicitement les méthodes dans l'interface comme publique, mais 🎜"Même si vous ne faites pas cela, elles sont toujours publiques "🎜. Ainsi, lors de l'implémentation d'une interface, les méthodes de l'interface doivent être définies comme <code>public. Sinon, ils n'ont accès qu'aux packages, donc lorsqu'ils sont hérités, leur accessibilité est réduite, ce qui n'est pas autorisé par le compilateur Java. 🎜🎜De plus, les constantes sont autorisées dans l'interface. Tout comme les méthodes de l'interface sont automatiquement définies sur public, 🎜"Les champs de l'interface seront automatiquement définis sur public static final. tapez "🎜, par exemple : 🎜
<code>interface B {<br> void idea();<br>}</code> 
Copier après la connexion
Copier après la connexion
❝ 🎜Vous pouvez marquer la méthode d'interface comme public et le champ comme public static final. Certains programmeurs sont prêts à le faire par habitude ou pour améliorer la clarté, mais la spécification du langage Java "recommande de ne pas écrire ces mots-clés redondants". 🎜❞

3. Caractéristiques des interfaces 🎜🎜La différence entre les interfaces et les classes est que nous 🎜 ne pouvons pas utiliser l'opérateur new comme une classe pour instancier une interface"🎜:🎜rrreee🎜La raison est aussi très simple. L'interface n'a même pas de méthode de construction spécifique, elle ne doit donc pas être instanciée. 🎜🎜Bien entendu, bien que l'objet de l'interface ne puisse pas être construit, il est toujours possible de déclarer les variables de l'interface : 🎜
<code>Concept x; // OK</code> 
Copier après la connexion
Copier après la connexion

接口变量必须引用实现了接口的类对象:

<code>x = new Implementation(. . .); // OK provided Implementation implements Concept</code> 
Copier après la connexion
Copier après la connexion

接下来, 如同使用 instanceof 检查一个对象是否属于某个特定类一样, 也可以使用 instanceof检查一个对象是否实现了某个特定的接口:

<code>if(x instanceof Concept){<br> ...<br>}</code> 
Copier après la connexion
Copier après la connexion

另外,与可以建立类的继承关系一样,「接口也可以被继承」

<code>public interface Concept1 {<br>    void idea1();<br>    void idea2();<br>}<br><br>-------------------------------------------<br>    <br>public interface Concept2 extends Concept1{<br> double idea3();<br>}</code> 
Copier après la connexion
Copier après la connexion

当然,读到这里大家可能依然无法理解,既然有了抽象类,为什么 Java 程序设计语言还要不辞辛苦地引入接口这个概念?

很重磅!因为「一个类可以实现多个接口,但是一个类只能继承一个父类」。正是接口的出现打破了 Java 这种单继承的局限,为定义类的行为提供了极大的灵活性。

<code>class Implementation implements Concept1, Concept2 // OK</code> 
Copier après la connexion
Copier après la connexion

有一条实际经验:在合理的范围内尽可能地抽象。显然,接口比抽象类还要抽象。因此,一般更倾向使用接口而不是抽象类。

4. Java 8 接口新特性

上文提过一嘴,「在 Java 8 中,允许在接口中增加静态方法和默认方法」。理论上讲,没有任何理由认为这是不合法的,只是这有违于将接口作为抽象规范的初衷。举个例子:

<code>public interface Concept {<br>    // 静态方法<br> public static void get(String name){<br>     System.out.println("hello " + name);<br>    }<br>    // 默认方法<br>    default void idea1(){<br>        System.out.println("this is idea1");<br>    };<br>}</code> 
Copier après la connexion
Copier après la connexion

用 default 修饰符标记的方法就是默认方法,这样子类就不需要去实现这个方法了。

不过,引入默认方法后,就出现了一个「默认方法冲突」的问题。如果先在一个接口 A 中将一个方法 idea 定义为默认方法, 然后又在另一个接口 B 或者超类 C 中定义了同样的方法  idea,然后类 D 实现了这两个接口 A 和 B(或超类 C)。于是类 D 中就有了方法 idea 的两个默认实现,出现了冲突,为此,Java 制定了一套规则来解决这个二义性问题:

1 )  「超类优先」。如果超类提供了一个具体方法,接口中的同名且有相同参数类型的默认方法会被忽略。

2 )  「接口冲突」。如果一个父类接口提供了一个默认方法,另一个父类接口也提供了一个同名而且参数类型相同的方法,子类必须覆盖这个方法来解决冲突。例如:

<code>interface A {<br> default void idea(){<br>  System.out.println("this is A");<br> }<br>}<br><br>interface B {<br> default void idea(){<br>  System.out.println("this is B");<br> }<br>}<br><br>// 需要在 D 类中覆盖 idea 方法<br>class D implements A, B{<br>    public void getName(){<br>     System.out.println("this is D");<br>    }<br>}</code> 
Copier après la connexion
Copier après la connexion

现在假设 B接口没有为 idea 提供默认实现:

<code>interface B {<br> void idea();<br>}</code> 
Copier après la connexion
Copier après la connexion

那么 D 类会直接从 A 接口继承默认方法吗?这好像挺有道理, 不过,Java 设计者更强调一致性。两个接口如何冲突并不重要,「只要有一个接口提供了一个默认实现,编译器就会报告错误, 我们就必须解决这个二义性」

当然,如果两个接口都没有为共享方法提供默认实现, 那么就与 Java 8 之前的情况一样,这里不存在冲突。

5. 接口存在的意义

在我自己早期学习编程的时候,对接口存在的意义实在困惑,我自己乱写代码的时候基本上不可能意识到需要去写接口,不知道接口到底有什么用,为什么要定义接口,感觉定义接口只是提前做了个多余的工作。

其实不是,定义接口并非多余,「接口是用来提供公用的方法,规定子类的行为的」。举个例子,让大家直观的感受下接口的作用:

比如有个网站, 需要保存不同客户的信息, 有些客户从 Web 网站来, 有些客户从手机客户端来, 有些客户直接从后台管理系统录入。假设不同来源的客户有不同的处理业务流程, 这个时候我们定义接口来提供一个保存客户信息的方法,然后不同的平台实现我们这个保存客户信息的接口,以后保存客户信息的话, 我们只需要知道这个接口就可以了,具体调用的方法被封装成了黑盒子,这也就是 Java 的多态的体现,「接口帮助我们对这些有相同功能的方法做了统一管理」

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:yisu.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal