Питер Верхас 2014-жылдын апрелинде жазылган макаланын котормосу . Котормочудан: " демейки метод " термини Java-да жаңы эле пайда болду жана мен анын орус тorне котормосу бар-жокпу билбейм. Мен "демейки ыкма" деген терминди колдоном, бирок мен аны идеалдуу эмес деп эсептейм. Мен сизди ийгorктүү котормо боюнча талкуулоого чакырам.
Демейки ыкма деген эмне
Эми, Java 8дин чыгышы менен, интерфейс аны ишке ашырган класстарга шайкеш келиши үчүн интерфейстерге жаңы ыкмаларды кошо аласыз. Эгер сиз Киевден Нью-Йоркко чейин көптөгөн программисттер колдонгон китепкана иштеп жатсаңыз, бул абдан маанилүү. Java 8ге чейин, эгер сиз китепканада интерфейсти аныктасаңыз, интерфейсиңизди иштетип жаткан кээ бир тиркемелер жаңыртылганда бузулуп калуу коркунучу жок эле ага ыкмаларды кошо алган жоксуз. Демек, Java 8де мындан ары мындан коркпойсузбу? Жок болбойт. Интерфейске демейки ыкманы кошуу кээ бир класстарды жараксыз кылып коюшу мүмкүн. Келгиле, адегенде демейки ыкмалардын жакшы жактарын карап көрөлү. Java 8де ыкманы түздөн-түз интерфейсте ишке ашырууга болот. (Интерфейстеги статикалык ыкмалар эми ишке ашырылышы мүмкүн, бирок бул башка окуя.) Интерфейсте ишке ашырылган метод демейки метод деп аталат жана демейки ачкыч сөз менен белгиленет . Эгерде класс интерфейсти ишке ашырса, анда ал интерфейсте ишке ашырылган методдорду ишке ашыра алат, бирок талап кылынbyte. Класс демейки ишке ашырууну мурастайт. Ошондуктан алар ишке ашырган интерфейсти өзгөртүүдө класстарды өзгөртүүнүн кажети жок.Бир нече тукум куучулук?
Эгерде класс бирден ашык (мисалы, эки) интерфейсти ишке ашырса жана алар бирдей демейки ыкманы ишке ашырса, иштер татаалдашат. Класс кайсы ыкманы мурастайт? Жооп эч ким эмес. Бул учурда класс методдун өзүн ишке ашырышы керек (же түз же башка класстан мурастоо жолу менен). Эгерде бир интерфейсте демейки ыкма болсо, экинчисинде ошол эле ыкма абстракттуу болсо, абал окшош. Java 8 тартиптүү болууга жана түшүнүксүз кырдаалдардан качууга аракет кылат. Эгерде методдор бир нече интерфейсте жарыя кылынса, класстын демейки ишке ашыруу эч кандай мураска алынbyte - сиз компиляция катасын аласыз. Бирок, классыңыз мурунтан эле компиляцияланган болсо, сиз компиляция катасын ала албайсыз. Java 8 бул жагынан жетиштүү бекем эмес. Мунун себептери бар, мен аларды талкуулагым келбейт (мисалы: Java релизинин мурунтан эле чыгарылганы жана талкуулоо үчүн убакыт көп убакыт өткөн жана жалпысынан бул алар үчүн орун эмес).- Сизде эки интерфейс бар жана класс алардын экөөнү тең ишке ашырат дейли.
- Интерфейстердин бири демейки m() ыкмасын ишке ашырат.
- Сиз бардык интерфейстерди жана классты түзөсүз.
- m() методу жок интерфейсти абстракттуу ыкма катары жарыялоо менен өзгөртөсүз.
- Сиз өзгөртүлгөн интерфейсти гана түзөсүз.
- Класс башта.
- абстракттуу m() ыкмасы менен интерфейсти өзгөртүп, демейки ишке киргизүүнү кошуңуз.
- Өзгөртүлгөн интерфейсти түзүңүз.
- Классты иштетүү: ката.
Мисал code
Жогорудагыларды көрсөтүү үчүн мен C.java классы үчүн тест каталогун жана I1.java жана I2.java файлдарындагы интерфейстер үчүн 3 подкаталогдорду түздүм. Сынактын түпкү каталогу C.java классынын баштапкы codeун камтыйт. Негизги каталог аткарууга жана компиляцияга ылайыктуу интерфейстердин versionсын камтыйт: 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 интерфейсинин versionсы, ошондой эле техникалык себептерден улам I1.javaнын өзгөртүлбөгөн көчүрмөсү бар.
~/github/test$ cat compatible/I2.java
public interface I2 {
void m();
}
Мындай топтом C классын компиляциялоо үчүн колдонулbyte:
~/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 versionсын камтыйт, ал ошондой эле ыкманы жарыялайт 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$
GO TO FULL VERSION