JavaRush /Java Blogu /Random-AZ /Java 8-də Defolt Metodlar: Nə edə bilər və nə edə bilməz?...
Spitfire
Səviyyə

Java 8-də Defolt Metodlar: Nə edə bilər və nə edə bilməz?

Qrupda dərc edilmişdir
2014-cü ilin aprelində Peter Verhasın yazdığı məqalənin tərcüməsi . Java 8-də Defolt Metodlar: Nə edə bilər və nə edə bilməz?  - 1Tərcüməçidən: " standart metod " termini Java-da təzəcə peyda olub və onun üçün rus dilinə müəyyən edilmiş tərcümənin olub-olmadığına əmin deyiləm. Mən "defolt metod" terminindən istifadə edəcəyəm, baxmayaraq ki, bunun ideal olduğunu düşünmürəm. Sizi daha uğurlu tərcüməni müzakirə etməyə dəvət edirəm.

Standart metod nədir

İndi Java 8-in buraxılması ilə siz interfeyslərə yeni metodlar əlavə edə bilərsiniz ki, interfeys onu həyata keçirən siniflərə uyğun qalsın. Kiyevdən Nyu-Yorka qədər bir çox proqramçının istifadə etdiyi bir kitabxana hazırlayırsınızsa, bu çox vacibdir. Java 8-dən əvvəl, əgər siz kitabxanada interfeys müəyyən etsəniz, interfeysinizdə işləyən bəzi proqramlar yeniləndikdə onun sıradan çıxması riski olmadan ona metodlar əlavə edə bilməzdiniz. Beləliklə, Java 8-də bundan artıq qorxmaq olmaz? Yox bacarmazsan. İnterfeys üçün standart metodun əlavə edilməsi bəzi sinifləri yararsız edə bilər. Əvvəlcə standart üsullarla bağlı yaxşı şeylərə baxaq. Java 8-də metod birbaşa interfeysdə həyata keçirilə bilər. (İnterfeysdə statik metodlar indi də həyata keçirilə bilər, lakin bu başqa hekayədir.) İnterfeysdə həyata keçirilən metod standart metod adlanır və default açar sözü ilə işarələnir . Əgər sinif interfeys tətbiq edirsə, o, interfeysdə həyata keçirilən metodları həyata keçirə bilər, lakin tələb olunmur. Sinif standart tətbiqi miras alır. Buna görə də, həyata keçirdikləri interfeysi dəyişdirərkən sinifləri dəyişdirmək lazım deyil.

Çoxlu miras?

Bir sinif birdən çox (məsələn, iki) interfeys tətbiq edərsə və eyni standart metodu tətbiq edərsə, işlər daha da mürəkkəbləşir. Sinif hansı metodu miras alacaq? Cavab heç biri deyil. Bu halda, sinif metodun özünü həyata keçirməlidir (ya birbaşa və ya onu başqa sinifdən miras alaraq). Yalnız bir interfeysdə standart metod varsa, vəziyyət oxşardır, digərində isə eyni üsul mücərrəddir. Java 8 intizamlı olmağa və qeyri-müəyyən hallardan qaçmağa çalışır. Metodlar birdən çox interfeysdə elan edilirsə, o zaman heç bir standart tətbiq sinif tərəfindən miras alınmır - siz tərtib etmə xətası alacaqsınız. Baxmayaraq ki, sinifiniz artıq tərtib olunubsa, siz tərtib etmə xətası almaya bilərsiniz. Java 8 bu baxımdan kifayət qədər güclü deyil. Bunun müzakirəyə girmək istəmədiyim səbəbləri var (məsələn: Java buraxılışı artıq buraxılıb və müzakirələr üçün vaxt çoxdan keçib və ümumiyyətlə, bura onlar üçün yer deyil).
  • Tutaq ki, sizin iki interfeysiniz var və bir sinif onların hər ikisini həyata keçirir.
  • İnterfeyslərdən biri standart m() metodunu tətbiq edir.
  • Bütün interfeysləri və sinfi tərtib edirsiniz.
  • Siz m() metodu olmayan interfeysi abstrakt metod kimi elan etməklə dəyişdirirsiniz.
  • Siz yalnız dəyişdirilmiş interfeysi tərtib edirsiniz.
  • Sinfə başlayın.
Java 8-də Defolt Metodlar: Nə edə bilər və nə edə bilməz?  - 2Bu vəziyyətdə sinif işləyir. Siz onu yenilənmiş interfeyslərlə tərtib edə bilməzsiniz, lakin o, köhnə versiyalarla tərtib edilib və buna görə də işləyir. İndi
  • abstrakt m() metodu ilə interfeysi dəyişdirin və standart tətbiq əlavə edin.
  • Dəyişdirilmiş interfeysi tərtib edin.
  • İşlətmə sinfi: səhv.
Metodun defolt tətbiqini təmin edən iki interfeys olduqda, o, sinfin özü tərəfindən həyata keçirilmədikcə (yenidən, ya tək başına, ya da başqa sinifdən miras alınmasa) bu metod sinifdə çağırıla bilməz. Java 8-də Defolt Metodlar: Nə edə bilər və nə edə bilməz?  - 3Sinif uyğun. O, dəyişdirilmiş interfeys ilə yüklənə bilər. O, hətta hər iki interfeysdə defolt tətbiqi olan metod çağırılana qədər işləyə bilər.

Nümunə kodu

Java 8-də Defolt Metodlar: Nə edə bilər və nə edə bilməz?  - 4Yuxarıdakıları nümayiş etdirmək üçün mən C.java sinfi üçün test kataloqu və I1.java və I2.java fayllarında interfeyslər üçün 3 alt kataloq yaratdım. Testin kök kataloqu C.java sinfi üçün mənbə kodunu ehtiva edir. Əsas kataloq interfeyslərin icra və tərtib üçün uyğun olan versiyasını ehtiva edir: I1 interfeysi standart metoda malikdir m(); I2 interfeysində hələ heç bir üsul yoxdur. Sinfin bir metodu var mainki, biz onu sınaqdan keçirmək üçün icra edək. O, hər hansı bir komanda xətti arqumentinin olub-olmadığını yoxlayır, ona görə də biz onu asanlıqla m().
~/github/test$ cat C.java
public class C implements I1, I2 {
  public static void main(String[] args) {
    C c = new C();
    if( args.length == 0 ){
      c.m();
    }
  }
}
~/github/test$ cat base/I1.java
public interface I1 {
  default void m(){
    System.out.println("hello interface 1");
  }
}
~/github/test$ cat base/I2.java
public interface I2 {
}
Siz sinifi komanda xəttindən tərtib edə və işlədə bilərsiniz.
~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1
Uyğun kataloqda m() metodunu mücərrəd elan edən I2 interfeysinin versiyası, həmçinin texniki səbəblərə görə I1.java-nın dəyişdirilməmiş nüsxəsi var.
~/github/test$ cat compatible/I2.java

public interface I2 {
  void m();
}
Belə bir dəst C sinifini tərtib etmək üçün istifadə edilə bilməz:
~/github/test$ javac -cp .:compatible C.java
C.java:1: error: C is not abstract and does not override abstract method m() in I2
public class C implements I1, I2 {
       ^
1 error
Səhv mesajı çox dəqiqdir. Bununla belə, bizdə əvvəlki kompilyasiyadan C.class var və interfeysləri uyğun kataloqa yığsaq, hələ də sinfi işə salmaq üçün istifadə edilə bilən iki interfeysimiz olacaq:
~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1
Üçüncü kataloq - wrong- I2 versiyasını ehtiva edir, o da metodu elan edir m():
~/github/test$ cat wrong/I2.java
public interface I2 {
  default void m(){
    System.out.println("hello interface 2");
  }
}
Kompilyasiya ilə bağlı narahat olmağa belə ehtiyac yoxdur. Metod iki dəfə elan olunsa da, sinif hələ də istifadə oluna və m() metodu çağırılana qədər işləyə bilər. Bunun üçün əmr satırı arqumentinə ehtiyacımız var:
~/github/test$ javac wrong/*.java
~/github/test$ java -cp .:wrong C
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting default methods: I1.m I2.m
    at C.m(C.java)
    at C.main(C.java:5)
~/github/test$ java -cp .:wrong C x
~/github/test$

Nəticə

Kitabxananızı Java 8-ə köçürdükdə və standart metodları daxil etmək üçün interfeyslərinizi dəyişdikdə, yəqin ki, heç bir probleminiz olmayacaq. Ən azı, Java 8 kitabxana tərtibatçılarının funksionallıq əlavə etdikləri üçün ümid etdikləri budur. Kitabxananızdan istifadə edən proqramlar onu hələ də standart metodların olmadığı Java 7 üçün istifadə edir. Bir neçə kitabxana birlikdə istifadə edilərsə, münaqişə ehtimalı var. Bunun qarşısını necə almaq olar? Kitabxananızın API-ni əvvəlki kimi dizayn edin. Standart metodların imkanlarına arxalanaraq özündən razı olmayın. Onlar son çarədir. Digər interfeyslərlə toqquşmamaq üçün adları diqqətlə seçin. Bu funksiyadan istifadə edərək Java-nın inkişafının necə inkişaf edəcəyinə baxaq.
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION