JavaRush /Java Blog /Random-ID /Kelas dalam dalam metode lokal

Kelas dalam dalam metode lokal

Dipublikasikan di grup Random-ID
Halo! Mari kita bicara tentang jenis kelas bersarang lainnya. Yakni tentang kelas lokal (Metode kelas dalam lokal). Hal pertama yang perlu Anda ingat sebelum belajar adalah tempatnya dalam struktur kelas yang disarangkan. Kelas dalam dalam metode lokal - 2Berdasarkan diagram kita, kita dapat memahami bahwa kelas lokal adalah subtipe dari kelas internal, yang telah kita bahas secara rinci di salah satu materi sebelumnya . Namun, kelas lokal memiliki sejumlah fitur dan perbedaan penting dari kelas internal. Kuncinya ada pada deklarasinya: Kelas lokal dideklarasikan hanya dalam blok kode. Paling sering - di dalam beberapa metode kelas eksternal. Misalnya, mungkin terlihat seperti ini:
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 валидации номера
   }
}
PENTING!Kode ini tidak dapat dikompilasi ketika ditempelkan ke IDEA jika Anda menginstal Java 7. Kami akan membicarakan alasannya di akhir kuliah. Singkatnya, pekerjaan kelas lokal sangat bergantung pada versi bahasa. Jika kode ini tidak dapat dikompilasi untuk Anda, Anda dapat mengganti versi bahasa di IDEA ke Java 8, atau menambahkan kata finalke parameter metode sehingga terlihat seperti ini: validatePhoneNumber(final String number). Setelah ini semuanya akan berjalan lancar. Ini adalah program kecil - validator nomor telepon. Metodenya validatePhoneNumber()mengambil string sebagai masukan dan menentukan apakah itu nomor telepon. Dan di dalam metode ini kami mendeklarasikan kelas lokal kami PhoneNumber. Anda mungkin memiliki pertanyaan logis: mengapa? Mengapa mendeklarasikan kelas di dalam suatu metode? Mengapa tidak menggunakan kelas dalam biasa? Memang, seseorang dapat melakukan ini: menjadikan kelas PhoneNumberinternal. Hal lainnya adalah keputusan akhir bergantung pada struktur dan tujuan program Anda. Mari kita ingat contoh kita dari perkuliahan tentang kelas batin:
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!");
       }
   }
}
Di dalamnya kami membuat HandleBar(stang) kelas internal sepeda. Apa bedanya? Pertama-tama, dalam menggunakan kelas. Kelas HandleBardari contoh kedua adalah entitas yang lebih kompleks dibandingkan PhoneNumberdengan contoh pertama. Pertama, y HandleBar​​memiliki metode publik rightdan left(bukan penyetel dan pengambil). Kedua, kita tidak dapat memprediksi sebelumnya di mana Bicyclekita mungkin membutuhkannya dan kelas eksternalnya - ini bisa berupa lusinan tempat dan metode yang berbeda, bahkan dalam program yang sama. Tapi dengan kelas PhoneNumbersemuanya jauh lebih sederhana. Program kami sangat sederhana. Fungsinya hanya satu - untuk memeriksa apakah nomor tersebut adalah nomor telepon. Dalam kebanyakan kasus, program kita PhoneNumberValidatorbahkan bukan program independen, tetapi hanya bagian dari logika otorisasi untuk program utama. Misalnya saja di berbagai website, saat mendaftar, Anda sering diminta memasukkan nomor telepon. Dan jika Anda mengetikkan omong kosong alih-alih angka, situs tersebut akan menampilkan kesalahan: "Ini bukan nomor telepon!" Untuk pengoperasian situs tersebut (atau lebih tepatnya, mekanisme otorisasi pengguna), pengembangnya dapat memasukkan analog kami ke dalam kode PhoneNumberValidator. Dengan kata lain, kita mempunyai satu kelas eksternal dengan satu metode yang akan digunakan di satu tempat dalam program dan tidak di tempat lain. Dan jika ya, maka tidak ada yang berubah di dalamnya: satu metode berhasil - itu saja. Dalam hal ini, karena seluruh logika kerja dikumpulkan dalam satu metode, akan jauh lebih mudah dan tepat untuk merangkum kelas tambahan di sana. Ia tidak memiliki metode sendiri selain pengambil dan penyetel. Kami pada dasarnya hanya membutuhkan data konstruktor darinya. Itu tidak digunakan dalam metode lain. Oleh karena itu, tidak ada alasan untuk memperluas informasi tentang hal ini di luar metode tunggal yang digunakan. Kami memberikan contoh mendeklarasikan kelas lokal dalam suatu metode, tapi ini bukan satu-satunya kemungkinan. Itu dapat dideklarasikan secara sederhana dalam blok kode:
public class PhoneNumberValidator {

   {
       class PhoneNumber {

           private String phoneNumber;

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

   }

   public void validatePhoneNumber(String phoneNumber) {


       //...code валидации номера
   }
}
Atau bahkan dalam satu lingkaran 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 валидации номера
   }
}
Namun kasus seperti ini sangat jarang terjadi. Dalam kebanyakan kasus, deklarasi akan tetap terjadi di dalam metode. Jadi kita bahas pengumumannya, kita juga ngomong soal “filosofi” :) Apa ciri dan perbedaan lain yang dimiliki kelas lokal dengan kelas internal? Objek kelas lokal tidak dapat dibuat di luar metode atau blok yang dideklarasikannya. Bayangkan kita membutuhkan metode generatePhoneNumber()yang menghasilkan nomor telepon acak dan mengembalikan nomor telepon PhoneNumber. Kami tidak akan dapat membuat metode seperti itu di kelas validator kami dalam situasi saat ini:
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() {

   }

}
Fitur penting lainnya dari kelas lokal adalah kemampuan untuk mengakses variabel lokal dan parameter metode. Jika Anda lupa, “lokal” adalah variabel yang dideklarasikan di dalam suatu metode. String russianCountryCodeArtinya, jika kita membuat variabel lokal di dalam suatu metode untuk beberapa tujuan kita validatePhoneNumber(), kita dapat mengaksesnya dari kelas lokal PhoneNumber. Namun, ada banyak kehalusan di sini yang bergantung pada versi bahasa yang digunakan dalam program. Di awal kuliah, kami mencatat bahwa kode di salah satu contoh mungkin tidak dapat dikompilasi di Java 7, ingat? Sekarang mari kita lihat alasannya :) Di Java 7, kelas lokal hanya dapat mengakses variabel lokal atau parameter metode jika dideklarasikan dalam metode sebagai 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 валидации номера
}
Di sini kompiler membuat dua kesalahan. Tapi di sini semuanya beres:
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 валидации номера
}
Sekarang Anda tahu alasan mengapa kode di awal kuliah tidak dapat dikompilasi: kelas lokal di Java 7 hanya memiliki akses ke finalparameter -metode dan finalvariabel -lokal. Di Java 8, perilaku kelas lokal telah berubah. Dalam versi bahasa ini, kelas lokal memiliki akses tidak hanya ke finalvariabel dan parameter -lokal, tetapi juga ke effective-final. Effective-finaladalah variabel yang nilainya tidak berubah sejak inisialisasi. Misalnya, di Java 8 kita dapat dengan mudah menampilkan variabel ke konsol russianCountryCode, meskipun sebenarnya bukan final. Yang penting tidak mengubah maknanya. Dalam contoh ini, semuanya berfungsi sebagaimana mestinya:
public void validatePhoneNumber(String number) {

  String russianCountryCode = "+7";

    class PhoneNumber {

       public void printRussianCountryCode() {

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

    }

   //...code валидации номера
}
Namun jika kita mengubah nilai variabel segera setelah inisialisasi, kode tidak akan dapat dikompilasi.
public void validatePhoneNumber(String number) {

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

    class PhoneNumber {

       public void printRussianCountryCode() {

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

    }

   //...code валидации номера
}
Namun bukan tanpa alasan bahwa kelas lokal adalah subtipe dari kelas internal! Mereka juga memiliki kesamaan. Kelas lokal memiliki akses ke semua bidang (bahkan pribadi) dan metode kelas luar: statis dan non-statis. Misalnya, mari tambahkan bidang statis ke kelas validator kita String phoneNumberRegex:
public class PhoneNumberValidator {

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

   public void validatePhoneNumber(String phoneNumber) {
       class PhoneNumber {

           //......
       }
   }
}
Validasi akan dilakukan menggunakan variabel statis ini. Metode ini memeriksa apakah string yang diteruskan ke dalamnya berisi karakter yang tidak cocok dengan ekspresi reguler " [^0-9]" (yaitu, karakter tersebut bukan angka dari 0 hingga 9). Kita dapat dengan mudah mengakses variabel ini dari kelas lokal PhoneNumber. Misalnya, tulis pengambil:
public String getPhoneNumberRegex() {

   return phoneNumberRegex;
}
Kelas lokal mirip dengan kelas dalam karena mereka tidak dapat mendefinisikan atau mendeklarasikan anggota statis apa pun. Kelas lokal dalam metode statis hanya dapat mereferensikan anggota statis dari kelas terlampir. Misalnya, jika Anda tidak mendefinisikan variabel (bidang) dari kelas yang melingkupinya sebagai statis, kompiler Java akan menghasilkan kesalahan: “Variabel non-statis tidak dapat direferensikan dari konteks statis.” Kelas lokal tidak statis karena mereka memiliki akses ke anggota instance blok yang memuatnya. Oleh karena itu, mereka tidak dapat memuat sebagian besar jenis deklarasi statis. Anda tidak dapat mendeklarasikan antarmuka di dalam blok; antarmuka bersifat statis. Kode ini tidak dapat dikompilasi:
public class PhoneNumberValidator {
   public static void validatePhoneNumber(String number) {
       interface I {}

       class PhoneNumber implements I{
           private String phoneNumber;

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

       //...code валидации номера
   }
}
Tetapi jika sebuah antarmuka dideklarasikan di dalam kelas luar, kelas tersebut PhoneNumberdapat mengimplementasikannya:
public class PhoneNumberValidator {
   interface I {}

   public static void validatePhoneNumber(String number) {

       class PhoneNumber implements I{
           private String phoneNumber;

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

       //...code валидации номера
   }
}
Kelas lokal tidak dapat mendeklarasikan inisialisasi statis (blok inisialisasi) atau antarmuka. Tapi kelas lokal dapat memiliki anggota statis, asalkan mereka adalah variabel konstan ( static final). Itulah mereka, kelas lokal! Seperti yang Anda lihat, mereka memiliki banyak perbedaan dari kelas internal. Kami bahkan harus mendalami fitur-fitur versi bahasa untuk memahami cara kerjanya :) Pada kuliah berikutnya, kita akan membahas tentang kelas dalam anonim - kelompok terakhir dari kelas bertingkat. Semoga sukses dengan studimu! :)
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION