JavaRush /Java блогы /Random-KK /Java 8-дегі әдепкі әдістер: олар не істей алады және не і...
Spitfire
Деңгей

Java 8-дегі әдепкі әдістер: олар не істей алады және не істей алмайды?

Топта жарияланған
2014 жылдың сәуірінде Питер Верхас жазған мақаланың аудармасы . Java 8-дегі әдепкі әдістер: олар не істей алады және не істей алмайды?  - 1Аудармашыдан: Java тілінде « әдепкі әдіс » термині жаңа ғана пайда болды және мен оның орыс тіліне бекітілген аудармасы бар-жоғын білмеймін. Мен «әдепкі әдіс» терминін қолданамын, бірақ мен оны идеалды деп санамаймын. Мен сізді сәтті аударманы талқылауға шақырамын.

Әдепкі әдіс дегеніміз не

Енді Java 8 шығарылымымен интерфейс оны жүзеге асыратын сыныптармен үйлесімді болып қалатындай интерфейстерге жаңа әдістерді қосуға болады. Егер сіз Киевтен Нью-Йоркке дейінгі көптеген бағдарламашылар пайдаланатын кітапхананы жасап жатсаңыз, бұл өте маңызды. Java 8-ге дейін, кітапханада интерфейсті анықтасаңыз, интерфейсіңізде жұмыс істейтін кейбір қолданба жаңартылған кезде бұзылып қалу қаупінсіз оған әдістерді қоса алмас едіңіз. Сонымен, Java 8-де сіз бұдан былай қорықпайсыз ба? Жоқ болмайды. Интерфейске әдепкі әдісті қосу кейбір сыныптарды жарамсыз етуі мүмкін. Алдымен әдепкі әдістердің жақсы жақтарын қарастырайық. Java 8-де әдісті тікелей интерфейсте іске асыруға болады. (Интерфейстегі статикалық әдістер енді жүзеге асырылуы мүмкін, бірақ бұл басқа әңгіме.) Интерфейсте іске асырылған әдіс әдепкі әдіс деп аталады және әдепкі кілт сөзімен белгіленеді . Егер сынып интерфейсті жүзеге асырса, ол интерфейсте іске асырылған әдістерді жүзеге асыра алады, бірақ талап етілмейді. Класс әдепкі іске асыруды иеленеді. Сондықтан олар жүзеге асыратын интерфейсті өзгерткен кезде сыныптарды өзгерту қажет емес.

Көп мұрагерлік?

Класс бірнеше (айталық, екі) интерфейстерді іске асырса және олар бірдей әдепкі әдісті орындаса, жағдай күрделене түседі. Класс қандай әдісті мұраға алады? Жауабы жоқ. Бұл жағдайда класс әдісті өзі жүзеге асыруы керек (тікелей немесе оны басқа класстан мұраға алу арқылы). Жағдай ұқсас, егер тек бір интерфейсте әдепкі әдіс болса, ал екіншісінде сол әдіс дерексіз. Java 8 тәртіпті болуға және түсініксіз жағдайлардан аулақ болуға тырысады. Егер әдістер бірнеше интерфейсте жарияланған болса, сыныпқа ешқандай әдепкі іске асыру мұраланбайды - сіз компиляция қатесін аласыз. Дегенмен, сіздің сыныпыңыз әлдеқашан құрастырылған болса, компиляция қатесін алмауыңыз мүмкін. Java 8 бұл тұрғыда жеткілікті сенімді емес. Мұның себептері бар, мен оларды талқылағым келмейді (мысалы: Java шығарылымы қазірдің өзінде шығарылды және талқылау уақыты әлдеқашан өтті және жалпы алғанда, бұл олар үшін орын емес).
  • Сізде екі интерфейс бар делік және класс олардың екеуін де жүзеге асырады.
  • Интерфейстердің бірі әдепкі m() әдісін жүзеге асырады.
  • Сіз барлық интерфейстер мен сыныпты құрастырасыз.
  • Сіз m() әдісі жоқ интерфейсті дерексіз әдіс ретінде жариялау арқылы өзгертесіз.
  • Сіз тек өзгертілген интерфейсті құрастырасыз.
  • Сабақты бастаңыз.
Java 8-дегі әдепкі әдістер: олар не істей алады және не істей алмайды?  - 2Бұл жағдайда сынып жұмыс істейді. Сіз оны жаңартылған интерфейстермен құрастыра алмайсыз, бірақ ол ескі нұсқалармен құрастырылған, сондықтан жұмыс істейді. Қазір
  • дерексіз m() әдісімен интерфейсті өзгертіңіз және әдепкі енгізуді қосыңыз.
  • Өзгертілген интерфейсті құрастырыңыз.
  • Сыныпты іске қосу: қате.
Әдістің әдепкі орындалуын қамтамасыз ететін екі интерфейс болған кезде, бұл әдісті сыныптың өзі жүзеге асырмайынша, сыныпта шақыруға болмайды (қайтадан, өздігінен немесе басқа сыныптан мұраланған). Java 8-дегі әдепкі әдістер: олар не істей алады және не істей алмайды?  - 3Сынып үйлесімді. Оны өзгертілген интерфейспен жүктеуге болады. Ол тіпті екі интерфейсте де әдепкі орындалуы бар әдіс шақырылғанға дейін жұмыс істей алады.

Мысал code

Java 8-дегі әдепкі әдістер: олар не істей алады және не істей алмайды?  - 4Жоғарыда айтылғандарды көрсету үшін мен C.java класы үшін сынақ каталогын және I1.java және I2.java файлдарындағы интерфейстер үшін 3 ішкі каталогты жасадым. Сынақ үшін түбірлік каталог C.java сыныбының бастапқы codeын қамтиды. Негізгі каталогта интерфейстердің орындауға және құрастыруға қолайлы нұсқасы бар: I1 интерфейсінде әдепкі m() әдісі бар; I2 интерфейсінде әлі ешқандай әдістер жоқ. Сыныпта әдіс бар main, сондықтан оны сынау үшін орындай аламыз. Ол пәрмен жолы аргументтерінің бар-жоғын тексереді, сондықтан біз оны шақыру арқылы немесе шақырмай-ақ оңай орындай аламыз 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 {
}
Пәрмен жолынан сыныпты құрастыруға және іске қосуға болады.
~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1
Үйлесімді каталогта m() әдісін дерексіз деп жариялайтын I2 интерфейсінің нұсқасы, сонымен қатар техникалық себептерге байланысты I1.java нұсқасының өзгертілмеген көшірмесі бар.
~/github/test$ cat compatible/I2.java

public interface I2 {
  void m();
}
Мұндай жинақты C класын құрастыру үшін қолдануға болмайды:
~/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
Қате туралы хабар өте дәл. Дегенмен, бізде алдыңғы жинақтағы C.class бар және интерфейстерді үйлесімді каталогқа құрастыратын болсақ, бізде әлі де сыныпты іске қосу үшін пайдалануға болатын екі интерфейс болады:
~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1
Үшінші каталог - wrong- I2 нұсқасын қамтиды, ол әдісті де жариялайды m():
~/github/test$ cat wrong/I2.java
public interface I2 {
  default void m(){
    System.out.println("hello interface 2");
  }
}
Сіз тіпті компиляция туралы алаңдамайсыз. Әдіс екі рет жарияланғанына қарамастан, сынып әлі де қолданыла алады және m() әдісі шақырылғанша жұмыс істей алады. Бұл бізге пәрмен жолы аргументі қажет:
~/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$

Қорытынды

Кітапханаңызды Java 8 нұсқасына көшіріп, интерфейстерді әдепкі әдістерді қосу үшін өзгерткен кезде, сізде ешқандай мәселе болмауы мүмкін. Кем дегенде, Java 8 кітапханасының әзірлеушілері функционалдылықты қосқанда үміттенетін нәрсе. Кітапханаңызды пайдаланатын қолданбалар оны әлі де Java 7 үшін пайдаланады, мұнда әдепкі әдістер жоқ. Бірнеше кітапхана бірге пайдаланылса, қақтығыстар болуы мүмкін. Оны қалай болдырмауға болады? Кітапхананың API интерфейсін бұрынғыдай етіп жасаңыз. Әдепкі әдістердің мүмкіндіктеріне сүйеніп, жайбарақат болмаңыз. Олар соңғы шара. Басқа интерфейстермен соқтығысуды болдырмау үшін атауларды мұқият таңдаңыз. Осы мүмкіндікті қолданатын Java үшін әзірлеу қалай дамитынын көрейік.
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION