İç İçe Sınıflar — static, Inner, Anonim ve Yerel
Önce şunu oku: final ve static — Kilitli Olan ve Ortak Olan , Erişim Belirleyiciler — Kim Hangi Kapıdan Girer?
30 saniyede özet
Bir sınıfın içine sınıf yazmanın dört yolu var. static iç içe sınıf bağımsızdır; inner sınıf onu kuran nesneye gizli bir ip ile bağlıdır. O ip, uzun yaşayan bir yerde tutulursa dış nesneyi de bırakmaz.
Bir uçurtmayı ipiyle uçurursun. Uçurtma ne kadar uzağa giderse gitsin, ipin öbür ucu hâlâ senin elinde.
Java’da bir sınıfın içine yazılan bazı sınıflar da böyle bir iple doğar. Bu ders o ipi görünür kılıyor.
Adım adım oku
- Büyük ve ağır bir kutu: bir hesap nesnesi.
- Kutudan küçük bir uçurtma çıkıyor: bir iç nesne.
- Uçurtmanın ipi hâlâ kutuya bağlı.
- Uçurtmayı tutan biri, farkında olmadan kutuyu da tutuyor.
-
Bayt: Hesap sınıfının içine küçük bir Hatırlatıcı sınıfı yazdım. Çok düzenli duruyor!
-
Sen: Ama ekranlar kapandıkça bellek artıyor.
-
Bayt: Hatırlatıcı zamanlayıcıda duruyor... ve içinde gizli bir şey taşıyor olabilir.
-
Bayt: Önce iç içe sınıfların dört çeşidine bakalım.
Bir sınıfın içinde sınıf
| Çeşit | Nerede yazılır | Dış nesneye bağlı mı? |
|---|---|---|
| static iç içe sınıf | Sınıfın içinde, static ile | Hayır |
| inner sınıfBaşka bir sınıfın içinde static olmadan yazılan sınıf. Her nesnesi onu kuran dış nesneye bağlı doğar ve onun alanlarını doğrudan kullanabilir.Dışarıdan dis.new Ic() ile kurulur. Dış nesneyi kullandığı sürece onu gizli bir alanda (derlenmiş kodda this$0) tutar.Sözlükte gör → | Sınıfın içinde, static olmadan | Evet |
| Yerel sınıf | Bir metodun içinde | Instance metotta, evet |
| anonim sınıfAdı olmayan, tek bir ifadenin içinde hem tanımlanıp hem kurulan sınıf. Tek metotlu arayüzler için yerini büyük ölçüde lambda'ya bıraktı.Instance metotta yazılıp dış nesneyi kullanırsa inner sınıf gibi onu tutar. İçindeki this, anonim nesnenin kendisidir.Sözlükte gör → | Bir ifadenin içinde, adı yok | Instance metotta, evet |
Hesap sınıfının içinde static olmayan bir Hatirlatici sınıfı var. Başka bir sınıfta `new Hesap.Hatirlatici()` yazarsan ne olur? Cevabı göster
Derlenmez. Inner sınıfın nesnesi bir hesaba bağlı doğmak zorunda; doğrusu hesap.new Hatirlatici(). static iç içe bir sınıf olsaydı new Hesap.Hatirlatici() çalışırdı.
Kafam karıştı, daha basit anlat
static olan iç sınıf kendi başına yaşar. static olmayan, onu kuran nesneye bağlı doğar.
static iç içe sınıf ile inner sınıf arasındaki temel fark nedir?
Bu kod derlenir mi, derlenirse ne yazdırır?
Gizli ip: dış nesneye referans
Inner sınıf, dış sınıfın alanlarını sanki kendi alanlarıymış gibi okuyabilir. Bunu, onu kuran nesneyi gizli bir alanda tutarak yapar: Hesap.this. Bu nesneye dış nesneBir inner sınıf nesnesini kuran ve ona bağlı olan dış sınıf nesnesi. İçeriden Dis.this ile erişilir.Inner nesne yaşadıkça, onu kullandığı sürece dış nesne de yaşar. Heap dump'ta bu bağ this$0 adlı alan olarak görünür.Sözlükte gör → denir.
Anonim ve yerel sınıflar da instance metotta yazılıp dış nesneyi kullanırsa aynı ipi taşır. Lambda ise yalnızca bir alan ya da metot üzerinden this’i kullanırsa onu yakalar.
Runnable a = () -> System.out.println(this.iban); // captures this: the whole accountString iban = this.iban;Runnable b = () -> System.out.println(iban); // captures only the StringJava 18 ile gelen küçük değişiklik· istersen atla
Java 18’den beri derleyici, dış nesneyi hiç kullanmayan inner sınıflardan bu gizli alanı çıkarıyor. Dış nesnenin bir alanını ya da metodunu kullanan her inner sınıf ise onu hâlâ tutar.
Bir inner sınıf nesnesi uzun yaşayan bir zamanlayıcıya veriliyor ve dış sınıfın bir alanını okuyor. Dış nesne için bu ne demek?
Hesap sınıfının instance metodunda yazılan her şeyi, hesabı (this) tutup tutmadığına göre ayır.
Ne zaman hangisi?
Varsayılan seçim static iç içe sınıftır: bir Builder, küçük bir yardımcı ya da sınıfa ait bir sonuç tipi. İhtiyacı olan değeri parametre olarak alır.
Inner sınıf, dış nesneye gerçekten ihtiyaç varsa yazılır: örneğin bir koleksiyonun kendi elemanlarını gezen Iterator’ı. Ömrü dış nesneden uzun olmamalıdır.
Tek metotlu bir arayüz için anonim sınıf yerine artık lambda yazılır. Yerel sınıf ise seyrek görülür.
Kafam karıştı, daha basit anlat
Önce static yaz. Dış nesneye gerçekten ihtiyacın olduğunu görürsen static’i kaldır.
Hesap için bir Builder yazacaksın. Hangi çeşit iç içe sınıf olmalı?
Kendin gör
Hesap ekranı bir hatırlatıcı üretip uygulama boyunca yaşayan bir zamanlayıcıya veriyor. Sonra ekran kapanıyor ve GC çalışıyor. Hatırlatıcının nasıl yazıldığını seç.
Hatırlatıcı hesabı bırakıyor mu?
Tohum 1Oynat ya da adımla.
Şu an ne oldu?
Bir hesap ekranı açılacak
Ekran bir hatırlatıcı üretip zamanlayıcıya verecek. Hatırlatıcı şöyle yazıldı: İç sınıf (inner), hesabın alanını okuyor.
Görevler0/3
Ekran kapandığı hâlde bellekte kalan hesabı göraçık
İpucu
Dışarıdan görünmeyen bir referans arıyorsun.
Hesabı tutan lambda'yı bulaçık
İpucu
Lambda bir alanı okursa neyi yakalar?
Hesabın toplanmasını sağla, IBAN'ı açıkça vererekaçık
İpucu
Dış nesnesi olmayan iç içe sınıf hangisi?
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanı oynat. Inner sınıf: ekran kapandı ama hesap ve geçmişi bellekte kaldı.
- Anonim sınıfı dene. Aynı gizli ip.
- İki lambda’yı karşılaştır. Biri
this.ibanokuyor, öteki yalnızca IBAN’ın kopyasını. - static iç içe sınıfa geç. Hesap toplanıyor.
Simülatörde iki lambda'dan biri hesabı bellekte tuttu, öteki tutmadı. Fark neydi?
Tuzaklar
Uzun yaşayan bir yere inner nesne vermek. Zamanlayıcıya, static bir listeye ya da bir cache’e konan inner nesne, dış nesneyi ve onun tuttuğu her şeyi canlı tutar.
Anonim sınıfta this sanmak. Anonim sınıfın içinde this anonim nesnenin kendisidir; lambda’da ise dış nesnedir.
Serileştirilen inner sınıf. Inner nesneyi serileştirmek dış nesneyi de serileştirmeye çalışır.
Her hesap ekranı kapandıktan sonra bellekte kalıyor. Sorunlu satırları işaretle.
Derinleş · Hesap: static Builder, gerçekten içeride yaşayan iterator ve kendi başına bir hatırlatıcı 3 dosya · ~97 satır · ilk okumada atlayabilirsin
Kendini sına
Önce hızlı bir ısınma: puan yok, kayıt yok. Sonra asıl sorular.
static iç içe sınıfın nesnesini kurmak için önce dış sınıfın bir nesnesi gerekir.
Bir anonim sınıfın run metodu içinde this yazınca neye ulaşırsın?
Aklında kalacak üç şey
- 1 static iç içe sınıf dış sınıfın bir nesnesine ihtiyaç duymaz; inner sınıfın her nesnesi onu kuran dış nesneye bağlıdır.
- 2 Dış nesnenin alanlarını kullanan inner sınıf, anonim sınıf ya da this'i yakalayan lambda o nesneyi canlı tutar; uzun yaşayan bir yerde saklanırsa sızıntı olur.
- 3 Varsayılan seçim static iç içe sınıftır. Inner sınıf yalnızca dış nesneye gerçekten ihtiyaç varsa yazılır.
4 kart sonraki derste seni bekliyor