Piter Verxas tomonidan 2014 yil aprelda yozilgan maqolaning tarjimasi . Tarjimondan: " standart usul " atamasi Java-da hozirgina paydo bo'ldi va men uning rus tiliga o'rnatilgan tarjimasi bor-yo'qligiga ishonchim komil emas. Men "standart usul" atamasini ishlataman, garchi bu ideal deb o'ylamayman. Men sizni yanada muvaffaqiyatli tarjimani muhokama qilishga taklif qilaman.
Standart usul nima
Endi, Java 8-ning chiqarilishi bilan siz interfeyslarga yangi usullarni qo'shishingiz mumkin, shunda interfeys uni amalga oshiradigan sinflarga mos keladi. Agar siz Kievdan Nyu-Yorkgacha bo'lgan ko'plab dasturchilar tomonidan foydalaniladigan kutubxonani ishlab chiqayotgan bo'lsangiz, bu juda muhim. Java 8-dan oldin, agar siz kutubxonada interfeysni aniqlagan bo'lsangiz, interfeysingiz bilan ishlaydigan ba'zi ilovalar yangilanganda ishdan chiqishi xavfisiz unga usullar qo'sha olmaysiz. Xo'sh, Java 8 da endi bundan qo'rqolmaysizmi? Mumkin emas. Interfeysga standart usulni qo'shish ba'zi sinflarni yaroqsiz holga keltirishi mumkin. Keling, avvalo standart usullarning yaxshi tomonlarini ko'rib chiqaylik. Java 8 da usul to'g'ridan-to'g'ri interfeysda amalga oshirilishi mumkin. (Interfeysdagi statik usullar endi amalga oshirilishi mumkin, lekin bu boshqa gap.) Interfeysda amalga oshirilgan usul standart usul deb ataladi va standart kalit so'zi bilan belgilanadi . Agar sinf interfeysni amalga oshirsa, u interfeysda amalga oshirilgan usullarni amalga oshirishi mumkin, lekin talab qilinmaydi. Sinf standart amalga oshirishni meros qilib oladi. Shuning uchun ular amalga oshiradigan interfeysni o'zgartirganda sinflarni o'zgartirish shart emas.Ko'p meros?
Agar sinf bir nechta (aytaylik, ikkita) interfeyslarni qo'llasa va ular bir xil standart usulni qo'llasa, ishlar yanada murakkablashadi. Sinf qaysi usulni meros qilib oladi? Javob yo'q. Bunday holda, sinf metodni o'zi amalga oshirishi kerak (to'g'ridan-to'g'ri yoki uni boshqa sinfdan meros qilib olish orqali). Vaziyat o'xshash, agar faqat bitta interfeys standart usulga ega bo'lsa, ikkinchisida esa xuddi shu usul mavhum bo'lsa. Java 8 intizomli bo'lishga va noaniq vaziyatlardan qochishga harakat qiladi. Agar usullar bir nechta interfeysda e'lon qilingan bo'lsa, u holda hech qanday standart dastur sinf tomonidan meros qilib olinmaydi - siz kompilyatsiya xatosini olasiz. Agar sinfingiz allaqachon tuzilgan bo'lsa-da, siz kompilyatsiya xatosiga duch kelmasligingiz mumkin. Java 8 bu borada etarlicha mustahkam emas. Buning sabablari bor, men ularni muhokama qilishni istamayman (masalan: Java versiyasi allaqachon chiqarilgan va muhokama qilish vaqti allaqachon o'tgan va umuman olganda, bu ular uchun joy emas).- Aytaylik, sizda ikkita interfeys bor va sinf ikkalasini ham amalga oshiradi.
- Interfeyslardan biri standart m() usulini amalga oshiradi.
- Siz barcha interfeyslarni va sinfni kompilyatsiya qilasiz.
- Siz m() usuliga ega bo'lmagan interfeysni mavhum usul sifatida e'lon qilish orqali o'zgartirasiz.
- Siz faqat o'zgartirilgan interfeysni tuzasiz.
- Sinfni boshlang.
- mavhum m() usuli bilan interfeysni o'zgartiring va standart dasturni qo'shing.
- O'zgartirilgan interfeysni kompilyatsiya qiling.
- Sinfni ishga tushirish: xato.
Misol kod
Yuqoridagilarni ko'rsatish uchun men C.java sinfi uchun test katalogini va I1.java va I2.java fayllaridagi interfeyslar uchun 3 ta kichik katalog yaratdim. Sinov uchun asosiy katalog C.java sinfi uchun manba kodini o'z ichiga oladi. Asosiy katalog interfeyslarning bajarish va kompilyatsiya qilish uchun mos bo'lgan versiyasini o'z ichiga oladi: I1 interfeysida standart usul m(); I2 interfeysi hali hech qanday usullarga ega emas. Sinfda metod bormain
, shuning uchun uni sinab ko'rishimiz mumkin. U buyruq qatori argumentlari mavjudligini tekshiradi, shuning uchun biz uni chaqirmasdan yoki chaqirmasdan osongina bajarishimiz mumkin 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 sinfni buyruq satridan kompilyatsiya qilishingiz va ishga tushirishingiz mumkin.
~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1
Mos keladigan katalog I2 interfeysining m() usulini mavhum deb e'lon qiladigan versiyasini, shuningdek, texnik sabablarga ko'ra I1.java ning o'zgartirilmagan nusxasini o'z ichiga oladi.
~/github/test$ cat compatible/I2.java
public interface I2 {
void m();
}
Bunday to'plamni C sinfini kompilyatsiya qilish uchun ishlatib bo'lmaydi:
~/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
Xato xabari juda aniq. Biroq, bizda avvalgi kompilyatsiyadan C.class bor va agar biz interfeyslarni mos keladigan katalogga kompilyatsiya qilsak, biz hali ham sinfni ishga tushirish uchun ishlatilishi mumkin bo'lgan ikkita interfeysga ega bo'lamiz:
~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1
Uchinchi katalog - wrong
- I2 versiyasini o'z ichiga oladi, u ham usulni e'lon qiladi m()
:
~/github/test$ cat wrong/I2.java
public interface I2 {
default void m(){
System.out.println("hello interface 2");
}
}
Siz kompilyatsiya haqida tashvishlanishingiz shart emas. Usul ikki marta e'lon qilingan bo'lsa ham, sinfdan foydalanish va m() usuli chaqirilguncha ishlashi mumkin. Buning uchun bizga buyruq qatori argumenti kerak:
~/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$
GO TO FULL VERSION