Salam! Başqa bir növ iç içə sinif haqqında danışaq. Məhz, yerli siniflər haqqında (Metod yerli daxili siniflər). Öyrənmədən əvvəl yadda saxlamalı olduğunuz ilk şey onların yuvalanmış siniflərin strukturunda yeridir. Diaqramımıza əsasən, yerli siniflərin əvvəlki materiallardan birindəYerli üsulla daxili siniflər - 2 ətraflı danışdığımız daxili siniflərin bir alt növü olduğunu başa düşə bilərik . Bununla belə, yerli siniflər daxili siniflərdən bir sıra mühüm xüsusiyyətlərə və fərqlərə malikdir. Əsas onların bəyannaməsindədir: Lokal sinif yalnız kod blokunda elan edilir. Çox vaxt - xarici sinifin bəzi metodu daxilində. Məsələn, bu belə görünə bilər:
public class PhoneNumberValidator {

   public void validatePhoneNumber(String number) {

        class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }

           public String getPhoneNumber() {
               return phoneNumber;
           }

           public void setPhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

       //...code валидации номера
   }
}
ƏHƏMİYYƏTLİ!Əgər sizdə Java 7 quraşdırılıbsa, bu kod IDEA-ya yapışdırıldıqda kompilyasiya edilməyəcək.Bunun səbəblərindən mühazirənin sonunda danışacağıq. Bir neçə sözlə, yerli siniflərin işi dil versiyasından çox asılıdır. Əgər bu kod sizin üçün tərtib edilmirsə, siz ya IDEA-da dil versiyasını Java 8-ə dəyişə bilərsiniz, ya da finalmetod parametrinə belə bir söz əlavə edə bilərsiniz ki, belə görünsün: validatePhoneNumber(final String number). Bundan sonra hər şey işləyəcək. Bu kiçik bir proqramdır - telefon nömrəsini təsdiqləyən. Onun metodu validatePhoneNumber()giriş kimi sətir götürür və onun telefon nömrəsi olub-olmadığını müəyyən edir. Və bu metodun içərisində yerli sinifimizi elan etdik PhoneNumber. Məntiqli sualınız ola bilər: niyə? Niyə metod daxilində sinif elan etmək lazımdır? Niyə adi daxili sinifdən istifadə etmirsiniz? Həqiqətən, bunu edə bilərsiniz: sinfi PhoneNumberdaxili edin. Başqa bir şey budur ki, son qərar proqramınızın strukturundan və məqsədindən asılıdır. Daxili siniflər haqqında mühazirədən nümunəmizi xatırlayaq:
public class Bicycle {

   private String model;
   private int mawWeight;

   public Bicycle(String model, int mawWeight) {
       this.model = model;
       this.mawWeight = mawWeight;
   }

   public void start() {
       System.out.println("Go!");
   }

   public class HandleBar {

       public void right() {
           System.out.println("Steering wheel to the right!");
       }

       public void left() {

           System.out.println("Steering wheel to the left!");
       }
   }
}
Orada biz HandleBar(sükanları) velosipedin daxili sinfini etdik. Fərq nədir? İlk növbədə, sinifdən istifadə etməklə. İkinci nümunədəki sinif birincidən HandleBardaha mürəkkəb varlıqdır . PhoneNumberBirincisi, y HandleBarictimai metodlara malikdir rightleft(setter və getter deyil). İkincisi, biz onun harada lazım ola biləcəyini və onun xarici sinfini əvvəlcədən proqnozlaşdıra bilmərik Bicycle- bunlar hətta eyni proqram çərçivəsində onlarla müxtəlif yerlər və üsullar ola bilər. Ancaq bir siniflə PhoneNumberhər şey daha sadədir. Proqramımız çox sadədir. Onun yalnız bir funksiyası var - nömrənin telefon nömrəsi olub-olmadığını yoxlamaq. Əksər hallarda, bizim PhoneNumberValidatorproqram müstəqil proqram olmayacaq, sadəcə əsas proqram üçün icazə məntiqinin bir hissəsi olacaq. Məsələn, müxtəlif saytlarda qeydiyyatdan keçərkən sizdən tez-tez telefon nömrəsini daxil etməyiniz xahiş olunur. Nömrələr əvəzinə bəzi cəfəngiyatlar yazsanız, sayt xəta verəcək: "Bu telefon nömrəsi deyil!" Belə bir saytın (daha doğrusu, istifadəçinin avtorizasiya mexanizminin) işləməsi üçün onun tərtibatçıları koda bizim analoqumuzu daxil edə bilərlər PhoneNumberValidator. Başqa sözlə, proqramda bir yerdə istifadə olunacaq və başqa heç bir yerdə istifadə edilməyəcək bir metodu olan bir xarici sinifimiz var. Əgər belədirsə, onda heç nə dəyişməyəcək: bir üsul öz işini görür - hamısı budur. Bu halda, bütün iş məntiqi bir üsulda toplandığı üçün orada əlavə bir sinfi əhatə etmək daha rahat və düzgün olacaqdır. Getter və setterdən başqa öz metodları yoxdur. Bizə mahiyyətcə ondan yalnız konstruktor məlumatlarına ehtiyacımız var. Digər üsullarda istifadə edilmir. Buna görə də, bu barədə məlumatı istifadə edildiyi vahid metoddan kənara çıxarmaq üçün heç bir səbəb yoxdur. Metodda lokal sinfi elan etmək nümunəsini verdik, lakin bu yeganə imkan deyil. Sadəcə kod blokunda elan edilə bilər:
public class PhoneNumberValidator {

   {
       class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

   }

   public void validatePhoneNumber(String phoneNumber) {


       //...code валидации номера
   }
}
Və ya hətta bir döngədə for!
public class PhoneNumberValidator {


   public void validatePhoneNumber(String phoneNumber) {

       for (int i = 0; i < 10; i++) {

           class PhoneNumber {

               private String phoneNumber;

               public PhoneNumber(String phoneNumber) {
                   this.phoneNumber = phoneNumber;
               }
           }

           //...Howая-то логика
       }

       //...code валидации номера
   }
}
Ancaq belə hallar olduqca nadirdir. Əksər hallarda, bəyannamə hələ də metod daxilində baş verəcək. Deməli, elanla məşğul olduq, “fəlsəfə”dən də danışdıq :) Yerli siniflərin daxili siniflərdən başqa hansı xüsusiyyətləri və fərqləri var? Yerli sinif obyekti elan olunduğu metod və ya blokdan kənarda yaradıla bilməz. Təsəvvür edin ki, bizə generatePhoneNumber()təsadüfi telefon nömrəsi yaradan və PhoneNumber. Hazırkı vəziyyətdə validator sinifimizdə belə bir metod yarada bilməyəcəyik:
public class PhoneNumberValidator {

   public void validatePhoneNumber(String number) {

        class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }

           public String getPhoneNumber() {
               return phoneNumber;
           }

           public void setPhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

       //...code валидации номера
   }

   //ошибка! компилятор не понимает, что это за класс - PhoneNumber
   public PhoneNumber generatePhoneNumber() {

   }

}
Lokal siniflərin digər mühüm xüsusiyyəti yerli dəyişənlərə və metod parametrlərinə daxil olmaq imkanıdır. Əgər unutmusunuzsa, “yerli” metod daxilində elan edilmiş dəyişəndir. Yəni bəzi məqsədlərimiz üçün String russianCountryCodemetod daxilində lokal dəyişən yaratsaq validatePhoneNumber(), ona yerli sinifdən daxil ola bilərik PhoneNumber. Bununla belə, burada proqramda istifadə olunan dilin versiyasından asılı olan bir çox incəliklər var. Mühazirənin əvvəlində qeyd etdik ki, nümunələrdən birində kod Java 7-də tərtib olunmaya bilər, yadınızdadır? İndi bunun səbəblərini nəzərdən keçirək :) Java 7-də lokal sinif yalnız metodda aşağıdakı kimi elan edildikdə lokal dəyişənə və ya metod parametrinə daxil ola bilər final:
public void validatePhoneNumber(String number) {

   String russianCountryCode = "+7";

   class PhoneNumber {

       private String phoneNumber;

       //ошибка! параметр метода должен быть объявлен How final!
       public PhoneNumber() {
           this.phoneNumber = number;
       }

       public void printRussianCountryCode() {

           //ошибка! локальная переменная должна быть объявлена How final!
           System.out.println(russianCountryCode);
       }

   }

   //...code валидации номера
}
Burada kompilyator iki səhv buraxdı. Ancaq burada hər şey qaydasındadır:
public void validatePhoneNumber(final String number) {

   final String russianCountryCode = "+7";

    class PhoneNumber {

       private String phoneNumber;


       public PhoneNumber() {
           this.phoneNumber = number;
       }

       public void printRussianCountryCode() {

           System.out.println(russianCountryCode);
       }

    }

   //...code валидации номера
}
İndi siz mühazirənin əvvəlindəki kodun tərtib edilməməsinin səbəbini bilirsiniz: Java 7-də yerli sinif yalnız final-metod parametrlərinə və final-lokal dəyişənlərə giriş imkanına malikdir. Java 8-də yerli siniflərin davranışı dəyişdi. Dilin bu versiyasında lokal sinif yalnız final-lokal dəyişənlərə və parametrlərə deyil, həm də effective-final. Effective-finalbaşlanğıcdan bəri dəyəri dəyişməmiş dəyişəndir. Məsələn, Java 8-də biz dəyişəni konsolda asanlıqla göstərə bilərik russianCountryCode, hətta olmasa belə final. Əsas odur ki, mənasını dəyişməsin. Bu nümunədə hər şey lazım olduğu kimi işləyir:
public void validatePhoneNumber(String number) {

  String russianCountryCode = "+7";

    class PhoneNumber {

       public void printRussianCountryCode() {

           //в Java 7 здесь была бы ошибка
           System.out.println(russianCountryCode);
       }

    }

   //...code валидации номера
}
Amma inisializasiyadan dərhal sonra dəyişənin qiymətini dəyişdirsək, kod tərtib edilməyəcək.
public void validatePhoneNumber(String number) {

  String russianCountryCode = "+7";
  russianCountryCode = "+8";

    class PhoneNumber {

       public void printRussianCountryCode() {

           //error!
           System.out.println(russianCountryCode);
       }

    }

   //...code валидации номера
}
Ancaq yerli sinifin daxili sinfin alt növü olması boş yerə deyil! Onların da ortaq nöqtələri var. Yerli sinfin xarici sinfin bütün (hətta özəl) sahələrinə və metodlarına çıxışı var: həm statik, həm də qeyri-statik. Məsələn, validator sinifimizə statik sahə əlavə edək String phoneNumberRegex:
public class PhoneNumberValidator {

   private static String phoneNumberRegex = "[^0-9]";

   public void validatePhoneNumber(String phoneNumber) {
       class PhoneNumber {

           //......
       }
   }
}
Doğrulama bu statik dəyişəndən istifadə edilməklə həyata keçiriləcək. Metod ona ötürülən sətirdə adi " " ifadəsinə uyğun gəlməyən simvolların olub-olmadığını yoxlayır [^0-9](yəni simvol 0-dan 9-a qədər rəqəm deyil). Bu dəyişənə yerli sinifdən asanlıqla daxil ola bilərik PhoneNumber. Məsələn, alıcı yazın:
public String getPhoneNumberRegex() {

   return phoneNumberRegex;
}
Yerli siniflər daxili siniflərə bənzəyir, çünki onlar heç bir statik üzvləri müəyyən edə və ya elan edə bilməzlər. Statik metodlardakı yerli siniflər yalnız əhatə edən sinfin statik üzvlərinə istinad edə bilər. Məsələn, əhatə edən sinifin dəyişənini (sahəsini) statik olaraq təyin etməsəniz, Java kompilyatoru xəta yaradır: “Statik olmayan dəyişənə statik kontekstdən istinad edilə bilməz”. Lokal siniflər statik deyil, çünki onlar blokun instansiya üzvlərinə daxil olurlar. Buna görə də, onlar statik bəyannamələrin əksər növlərini ehtiva edə bilməzlər. Siz blok daxilində interfeys elan edə bilməzsiniz; İnterfeyslər statik xarakter daşıyır. Bu kod tərtib edilməyəcək:
public class PhoneNumberValidator {
   public static void validatePhoneNumber(String number) {
       interface I {}

       class PhoneNumber implements I{
           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }
       }

       //...code валидации номера
   }
}
Lakin xarici sinif daxilində interfeys elan olunarsa, sinif PhoneNumberonu həyata keçirə bilər:
public class PhoneNumberValidator {
   interface I {}

   public static void validatePhoneNumber(String number) {

       class PhoneNumber implements I{
           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }
       }

       //...code валидации номера
   }
}
Yerli siniflər statik başlatıcıları (insializasiya blokları) və ya interfeysləri elan edə bilməz. Lakin yerli siniflərin sabit dəyişənlər ( ) olması şərtilə statik üzvlər ola bilər static final. Onlar budur, yerli siniflər! Gördüyünüz kimi, onların daxili siniflərdən çoxlu fərqləri var. Onların necə işlədiyini başa düşmək üçün hətta dil versiyasının xüsusiyyətlərinə dalmaq məcburiyyətində qaldıq :) Növbəti mühazirədə biz anonim daxili siniflər - yuvalanmış siniflərin sonuncu qrupu haqqında danışacağıq. Təhsilinizdə uğurlar! :)