Jaki jest cel domyślnego słowa kluczowego w Javie?


98

Interfejs w Javie jest podobny do klasy, ale treść interfejsu może zawierać tylko abstrakcyjne metody i finalpola (stałe).

Niedawno zobaczyłem pytanie, które wygląda tak

interface AnInterface {
    public default void myMethod() {
        System.out.println("D");
    }
}

Zgodnie z definicją interfejsu dozwolone są tylko metody abstrakcyjne . Dlaczego pozwala mi skompilować powyższy kod? Jakie jest defaultsłowo kluczowe?

Z drugiej strony, gdy próbowałem napisać poniższy kod, to mówi modifier default not allowed here

default class MyClass{

}

zamiast

class MyClass {

}

Czy ktoś może mi powiedzieć, do czego służy defaultsłowo kluczowe? Czy jest to dozwolone tylko w interfejsie? Czym się różni od default(brak modyfikatora dostępu)?


4
domyślne metody w interfejsach zostały dodane w Javie 8. To nie jest modyfikator dostępu, to domyślna implementacja.
Eran

2
@Eran nie sądzisz, wprowadzenie domyślnej metody naruszającej definicję interfejsu? : s
Ravi

2
Zmienił definicję interfejsu. Ta definicja jest obecnie nieaktualna.
Louis Wasserman,

2
Zostały wprowadzone do obsługi lambd. Szczegóły, dlaczego są one wymagane, znajdują się w propozycji słomianego człowieka dla Projektu Lambda.
sprinter

Odpowiedzi:


76

Jest to nowa funkcja w Javie 8, która umożliwia interfaceimplementację. Opisane w Javie 8 JLS-13.5.6. Deklaracje metod interfejsu, które czyta (częściowo)

Dodanie defaultmetody lub zmiana metody z abstractna defaultnie powoduje zerwania zgodności z istniejącymi plikami binarnymi, ale może spowodować, IncompatibleClassChangeErrorże istniejący plik binarny spróbuje wywołać metodę. Ten błąd występuje, jeśli typ kwalifikujący T,, jest podtypem dwóch interfejsów, Ii J, gdzie oba Ii Jdeklarują defaultmetodę z tym samym podpisem i wynikiem, a żadenI nie Jjest podinterfejsem drugiego.

Co nowego w JDK 8 mówi (częściowo)

Metody domyślne umożliwiają dodanie nowych funkcjonalności do interfejsów bibliotek i zapewniają zgodność binarną z kodem napisanym dla starszych wersji tych interfejsów.


17
Wygląda na to, że teraz interfejs i klasa abstrakcyjna są prawie takie same. :)
Ravi

16
Interfejsy @jWeaver nadal nie mogą mieć konstruktorów, pól, metod prywatnych ani implementacji equals / hashCode / toString.
Louis Wasserman

10
@Louis Wasserman: W Javie 9 mogą mieć privatemetody.
Holger

6
@Dan Pantry: privatemetody nie są tak naprawdę częścią interfejsu, ale mogą służyć jako metody pomocnicze dla defaultimplementacji lub w ramach stałych inicjatorów. Zauważ, że istnieją one już w Javie 8, ponieważ podczas używania wyrażeń lambda w interfejsach privategenerowane są metody syntetyczne . Tak więc Java 9 umożliwia korzystanie z tej funkcji również w przypadku zastosowań niesyntetycznych i innych niż lambda…
Holger

14
@jWeaver Różnica między interfejsami i klasami sprowadza się do stanu i zachowania . Interfejsy mogą przenosić zachowanie, ale tylko klasy mogą mieć stan. (Pola, konstruktory i metody, takie jak equals / hashCode, dotyczą stanu.)
Brian Goetz

30

Metody domyślne zostały dodane do języka Java 8 głównie w celu obsługi wyrażeń lambda. Projektanci (moim zdaniem sprytnie) postanowili stworzyć składnię lambd do tworzenia anonimowych implementacji interfejsu. Ale dane lambdy mogą implementować tylko jedną metodę, byłyby ograniczone do interfejsów z jedną metodą, co byłoby dość poważnym ograniczeniem. Zamiast tego dodano metody domyślne, aby umożliwić korzystanie z bardziej złożonych interfejsów.

Jeśli potrzebujesz trochę przekonania do twierdzenia, które defaultzostało wprowadzone z powodu lambd, zwróć uwagę, że propozycja słomianego człowieka Projektu Lambda, autorstwa Marka Reinholda z 2009 r., Wspomina o „metodach rozszerzania” jako obowiązkowej funkcji dodawanej w celu obsługi lambd.

Oto przykład demonstrujący tę koncepcję:

interface Operator {
    int operate(int n);
    default int inverse(int n) {
        return -operate(n);
    }
}

public int applyInverse(int n, Operator operator) {
    return operator.inverse(n);
}

applyInverse(3, n -> n * n + 7);

Zdaję sobie sprawę, że bardzo wymyślne, ale powinienem zilustrować, jak defaultobsługuje lambdy. Ponieważ inversejest to ustawienie domyślne, w razie potrzeby można je łatwo zastąpić klasą implementującą.


8
To nie jest poprawne. Baranki mogą być bezpośrednią przyczyną, ale tak naprawdę były tylko słomą, która złamała grzbiet wielbłąda. Prawdziwą motywacją było umożliwienie ewolucji interfejsu (umożliwienie kompatybilnej ewolucji istniejących interfejsów w celu obsługi nowego zachowania); lambdy mogły być czynnikiem, który wysunął tę potrzebę na pierwszy plan, ale cecha ta jest bardziej ogólna.
Brian Goetz

@BrianGoetz: IMHO, zarówno Java, jak i .NET przyniosłyby ogromne korzyści, gdyby istniały domyślne metody od samego początku. Jeśli jakaś typowa operacja mogłaby zostać wykonana na dowolnej implementacji interfejsu przy użyciu tylko elementów członkowskich interfejsu, ale niektóre implementacje prawdopodobnie miałyby bardziej efektywny sposób ich wykonywania, interfejs powinien zdefiniować metody dla tych operacji i zapewnić ich domyślne implementacje. Brak możliwości określenia domyślnych implementacji wywołał presję, aby interfejsy pomijały takie metody i uniemożliwił ich późniejsze dodanie.
supercat

@BrianGoetz Zgadzam się, że metody domyślne mają znaczącą wartość poza lambdami. Byłbym jednak zainteresowany wszelkimi odniesieniami, jakie mógłbyś udzielić na temat tej szerszej wartości, która wpłynęła na decyzję o ich włączeniu. Czytam, że głównym powodem były lambdy (dlatego w mojej odpowiedzi użyłem słowa „przede wszystkim”).
sprinter

2
Być może ten dokument pomoże: cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html . Rozdział 10 mówi jasno: „Celem metod domyślnych (wcześniej nazywanych metodami rozszerzania wirtualnego lub metodami obrony) jest umożliwienie ewolucji interfejsów w kompatybilny sposób po ich pierwszej publikacji”. Jako ilustrację ewolucji interfejsu przytacza się następnie metody przyjazne dla lambdy .
Brian Goetz

2
@Kartik Zadajesz złe pytanie! Nie wybieramy składni w oparciu o „jakie jest absolutne minimum potrzebne kompilatorowi do poprawnego przeanalizowania programu”; wybieramy to na podstawie tego, „co sprawiłoby, że intencja programisty byłaby bardziej widoczna dla czytelników”. Projektujemy najpierw dla użytkowników, a po drugie dla kompilatorów (a jeśli chodzi o użytkowników, najpierw projektujemy do czytania, a po drugie do pisania).
Brian Goetz

17

Coś, co zostało przeoczone w innych odpowiedziach, to jej rola w adnotacjach. Już w Javie 1.5 defaultsłowo kluczowe służyło jako sposób na podanie domyślnej wartości dla pola adnotacji.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Processor {
    String value() default "AMD";
}

Użycie było przeciążone wraz z wprowadzeniem Java 8, aby umożliwić zdefiniowanie domyślnej metody w interfejsach.

Coś jeszcze, co zostało przeoczone: powodem, dla którego deklaracja default class MyClass {}jest nieważna, jest sposób, w jaki klasy są w ogóle deklarowane . Nie ma przepisu w języku, który umożliwia pojawienie się tego słowa kluczowego. To nie pojawiają się na deklaracji metody interfejsu , choć.


16

W Javie 8 wprowadzono nową koncepcję zwaną metodami domyślnymi. Metody domyślne to te metody, które mają pewną domyślną implementację i pomagają w rozwijaniu interfejsów bez przerywania istniejącego kodu. Spójrzmy na przykład:

 public interface SimpleInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword

    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

 class SimpleInterfaceImpl implements SimpleInterface{

  @Override
  public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Not required to override to provide an implementation
  * for doSomeOtherWork.
  */

 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

a wynik to:

Implementacja Do Some Work w klasie
DoSomeOtherWork w interfejsie


3

Nowa funkcja Java 8 ( metody domyślne ) umożliwia interfejsowi udostępnienie implementacji, gdy zostanie oznaczona defaultsłowem kluczowym.

Na przykład:

interface Test {
    default double getAvg(int avg) {
        return avg;
    }
}
class Tester implements Test{
 //compiles just fine
}

Interface Test używa domyślnego słowa kluczowego, które umożliwia interfejsowi zapewnienie domyślnej implementacji metody bez konieczności implementowania tych metod w klasach korzystających z interfejsu.

Kompatybilność wsteczna: Wyobraź sobie, że twój interfejs jest zaimplementowany przez setki klas, modyfikacja tego interfejsu zmusi wszystkich użytkowników do zaimplementowania nowo dodanej metody, nawet jeśli nie jest to niezbędne dla wielu innych klas, które implementują twój interfejs.

Fakty i ograniczenia:

1-Może być zadeklarowany tylko w interfejsie, a nie w klasie lub klasie abstrakcyjnej.

2-Musi zapewnić ciało

3-Nie zakłada się, że jest to publiczne lub abstrakcyjne, jak inne normalne metody używane w interfejsie.


3

Domyślne metody w interfejsie pozwalają nam dodawać nowe funkcje bez łamania starego kodu.

Przed Java 8, jeśli nowa metoda została dodana do interfejsu, wszystkie klasy implementacji tego interfejsu były zobowiązane do przesłonięcia tej nowej metody, nawet jeśli nie używały nowej funkcji.

W Javie 8 możemy dodać domyślną implementację nowej metody, używając defaultsłowa kluczowego przed implementacją metody.

Nawet w przypadku anonimowych klas lub interfejsów funkcjonalnych, jeśli widzimy, że jakiś kod nadaje się do ponownego wykorzystania i nie chcemy definiować tej samej logiki w każdym miejscu kodu, możemy napisać ich domyślne implementacje i użyć ich ponownie.

Przykład

public interface YourInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword
    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

    class SimpleInterfaceImpl implements YourInterface{

     /*
     * Not required to override to provide an implementation
     * for doSomeOtherWork.
     */
      @Override
      public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Main method
  */
 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

2

Bardzo dobre wyjaśnienie można znaleźć w samouczkach Java ™ , część wyjaśnień jest następująca:

Rozważmy przykład obejmujący producentów samochodów sterowanych komputerowo, którzy publikują interfejsy zgodne ze standardami branżowymi, opisujące metody, które można zastosować do obsługi ich samochodów. A jeśli producenci samochodów sterowanych komputerowo dodadzą do swoich samochodów nowe funkcje, takie jak latanie? Producenci ci musieliby określić nowe metody, aby umożliwić innym firmom (np. Producentom elektronicznych przyrządów naprowadzania) dostosowanie ich oprogramowania do latających samochodów. Gdzie ci producenci samochodów zadeklarowaliby te nowe metody związane z lotem? Jeśli dodają je do swoich oryginalnych interfejsów, wówczas programiści, którzy zaimplementowali te interfejsy, musieliby przepisać swoje implementacje. Gdyby dodali je jako metody statyczne, programiści potraktowaliby je jako metody użytkowe, a nie podstawowe, podstawowe.

Metody domyślne umożliwiają dodawanie nowych funkcji do interfejsów bibliotek i zapewniają zgodność binarną z kodem napisanym dla starszych wersji tych interfejsów.


1

Metody domyślne umożliwiają dodawanie nowych funkcji do interfejsów aplikacji. Może również służyć do dziedziczenia wielokrotnego . Oprócz metod domyślnych w interfejsach można definiować metody statyczne. Ułatwia to organizowanie metod pomocniczych

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.