Quelle est l'implémentation «par défaut» de la méthode définie dans une interface?

91

Dans l'interface de collection, j'ai trouvé une méthode nommée removeIf()qui contient son implémentation.

default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);  
    boolean removed = false;  
    final Iterator<E> each = iterator();   
    while (each.hasNext()) {  
        if (filter.test(each.next())) {  
            each.remove();  
            removed = true;  
        }  
    }  
    return removed;  
}  

Je veux savoir s'il existe un moyen de définir le corps de la méthode dans une interface?
Quel est le defaultmot - clé et comment ça marche?

gifpif
la source
3
voir ce post sur le zeroturnaround
rebellabs

Réponses:

162

De https://dzone.com/articles/interface-default-methods-java

Java 8 introduit une nouvelle fonctionnalité «Méthode par défaut» ou (Méthodes Defender), qui permet au développeur d'ajouter de nouvelles méthodes aux interfaces sans interrompre l'implémentation existante de ces interfaces. Il offre une flexibilité pour permettre à l'interface de définir une implémentation qui sera utilisée par défaut dans la situation où une classe concrète ne parvient pas à fournir une implémentation pour cette méthode.

public interface A {
    default void foo(){
       System.out.println("Calling A.foo()");
    }
}

public class ClassAB implements A {
}

Il y a une question courante que les gens posent sur les méthodes par défaut lorsqu'ils entendent parler de la nouvelle fonctionnalité pour la première fois:

Que faire si la classe implémente deux interfaces et que ces deux interfaces définissent une méthode par défaut avec la même signature?

Exemple pour illustrer cette situation:

public interface A {  
    default void foo(){  
        System.out.println("Calling A.foo()");  
    }  
}

public interface B {
    default void foo(){
        System.out.println("Calling B.foo()");
    }
}


public class ClassAB implements A, B {

}  

Ce code ne parvient pas à se compiler avec le résultat suivant:

java: class Clazz inherits unrelated defaults for foo() from types A and B

Pour résoudre ce problème, dans Clazz, nous devons le résoudre manuellement en remplaçant la méthode en conflit:

public class Clazz implements A, B {
    public void foo(){}
}

Mais que se passe-t-il si nous voulons appeler l'implémentation par défaut de la méthode foo () depuis l'interface A au lieu d'implémenter la nôtre.

Il est possible de faire référence à A # foo () comme suit:

public class Clazz implements A, B {
    public void foo(){
       A.super.foo();
    }
}
gifpif
la source
18
Merci, très bonne exposition. Vous avez répondu à toutes mes questions avant que j'aie eu l'occasion de les poser.
Jeff Hutchins
pourquoi ne pas utiliser abstrait à la place?
Astolfo Hoscher le
1
@AstolfoHoscher Vous ne pouvez étendre qu'une seule classe, mais vous pouvez implémenter plusieurs interfaces.
Charles Wood
49

Ces méthodes sont appelées méthodes par défaut. La méthode par défaut ou la méthode Defender est l'une des nouvelles fonctionnalités ajoutées à Java 8.

Ils seront utilisés pour permettre à une méthode d'interface de fournir une implémentation utilisée par défaut dans le cas où une classe concrète ne fournit pas d'implémentation pour cette méthode.

Donc, si vous avez une interface, avec une méthode par défaut:

public interface Hello {
    default void sayHello() {
        System.out.println("Hello");
    }
}

La classe suivante est parfaitement valable:

public class HelloImpl implements Hello {

}

Si vous créez une instance de HelloImpl:

Hello hello = new HelloImpl();
hello.sayHello();  // This will invoke the default method in interface

Liens utiles:

Rohit Jain
la source
Alors, c'est ok si une classe implémente une interface et non sa méthode? En ce qui concerne Java7 que j'utilise, cela n'est pas autorisé.
Aniket Thakur
2
@AniketThakur. Cela n'est pas autorisé avant Java 8. Cette fonctionnalité est ajoutée dans Java 8 uniquement. Vous pouvez éviter de donner l'implémentation des méthodes par défaut dans votre classe d'implémentation.
Rohit Jain
1
@PawanMishra. Voir mon commentaire précédent. Non, vous n'avez pas besoin de fournir l'implémentation des méthodes d'interface par défaut dans l'implémentation de la classe.
Rohit Jain
1
@PawanMishra, vous pouvez cependant le remplacer. Il n'y a aucune restriction telle que vous devez utiliser uniquement l'implémentation par défaut.
Aniket Thakur
4
Un pas en avant qui évitera enfin d'être intrigué par l'héritage multiple!
Xtreme Biker
17

J'ai fait un peu de recherche et j'ai trouvé ce qui suit. J'espère que cela t'aides.

Problème existant

Les méthodes d'interface normales sont déclarées comme abstraites et doivent être définies dans la classe qui implémente l'interface. Ceci «charge» l'implémenteur de classe avec la responsabilité d'implémenter chaque méthode déclarée. Plus important encore, cela signifie également que l'extension d'une interface n'est pas possible après la «publication». Sinon, tous les implémenteurs devraient adapter leur implémentation, rompant la compatibilité ascendante des sources et des binaires.

Solution adoptée en Java 8

Pour faire face à ces problèmes, l'une des nouvelles fonctionnalités de JDK 8 est la possibilité d'étendre les interfaces existantes avec des méthodes par défaut. Les méthodes par défaut ne sont pas seulement déclarées, mais également définies dans l'interface.

Points importants à noter

  1. Les développeurs peuvent choisir de ne pas implémenter les méthodes par défaut dans l'implémentation de la classe.
  2. Les implémenteurs peuvent toujours remplacer les méthodes par défaut, comme les méthodes de classe non finales régulières peuvent être remplacées dans les sous-classes.
  3. Les classes abstraites peuvent même (re) déclarer les méthodes par défaut comme abstraites, forçant les sous-classes à réimplémenter la méthode (parfois appelée «ré-abstraction»).
Aniket Thakur
la source