class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
Məhz bu siniflər iç içə adlanır. Onlar 2 növə bölünür:
- Statik olmayan yuvalanmış siniflər - statik olmayan yuvalanmış siniflər. Onlara başqa bir şəkildə daxili siniflər də deyilir.
- Statik iç içə siniflər - statik yuvalanmış siniflər.
- yerli sinif
- anonim sinif
public class Bicycle {
private String model;
private int weight;
public Bicycle(String model, int weight) {
this.model = model;
this.weight = weight;
}
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!");
}
}
public class Seat {
public void up() {
System.out.println("The seat is up!");
}
public void down() {
System.out.println("The seat is down!");
}
}
}
Burada bir sinifimiz var Bicycle
- velosiped. Onun 2 sahəsi və 1 metodu var - start()
. Onun adi sinifdən fərqi ondadır ki, onun kodu içəridə yazılmış iki sinfə malikdir Bicycle
- bunlar siniflərdir HandleBar
(sükan çarxı) və Seat
(oturacaq). Bunlar tam hüquqlu siniflərdir: gördüyünüz kimi, onların hər birinin öz metodları var. Bu zaman sizdə belə bir sual yarana bilər: niyə biz bir sinfi digərinin içinə qoyduq? Niyə onları daxili edir? Yaxşı, deyək ki, proqramda sükan və oturacaq üçün ayrıca siniflərə ehtiyacımız var. Ancaq onları yerləşdirməyə ehtiyac yoxdur! Siz müntəzəm dərslər edə bilərsiniz. Məsələn, bu kimi:
public class HandleBar {
public void right() {
System.out.println("Steering wheel to the right!");
}
public void left() {
System.out.println("Steering wheel left");
}
}
public class Seat {
public void up() {
System.out.println("The seat is up!");
}
public void down() {
System.out.println("The seat is down!");
}
}
Çox yaxşı sual! Əlbəttə ki, texniki məhdudiyyətimiz yoxdur - biz bunu bu şəkildə edə bilərik. Söhbət daha çox müəyyən proqram baxımından və həmin proqramın mənasında dərslərin düzgün tərtib edilməsindən gedir. Daxili siniflər başqa bir varlıq ilə ayrılmaz şəkildə əlaqəli olan proqramda müəyyən bir obyekti vurğulamaq üçün siniflərdir. Sükan, oturacaq, pedallar velosipedin komponentləridir. Velosipeddən ayrılaraq, onların mənası yoxdur. Bütün bu sinifləri ayrı ictimai siniflər etsəydik, proqramımız, məsələn, aşağıdakı koda malik ola bilər:
public class Main {
public static void main(String[] args) {
HandleBar handleBar = new HandleBar();
handleBar.right();
}
}
Ummm... Bu kodun mənasını izah etmək belə çətindir. Bizdə qəribə bir velosiped sükanı var (bu, niyə lazımdır? Düzünü desəm, fikrim yoxdur). Və bu sükan sağa dönür... öz-özünə, velosipedsiz... nədənsə. Sükan çarxının mahiyyətini velosipedin mahiyyətindən ayırmaqla proqramımızın məntiqini itirmişik. Daxili sinifdən istifadə edərək kod tamamilə fərqli görünür:
public class Main {
public static void main(String[] args) {
Bicycle peugeot = new Bicycle("Peugeot", 120);
Bicycle.HandleBar handleBar = peugeot.new HandleBar();
Bicycle.Seat seat = peugeot.new Seat();
seat.up();
peugeot.start();
handleBar.left();
handleBar.right();
}
}
Konsol çıxışı:
Сиденье поднято выше!
Поехали!
Руль влево!
Руль вправо!
Birdən baş verənlər məna kəsb etdi! :) Biz velosiped obyekti yaratdıq. Biz onun iki "əsas obyektini" yaratdıq - sükan və oturacaq. Rahatlıq üçün oturacağı yuxarı qaldırdıq - və getdik: yuvarlanırıq və getməli olduğumuz yerə yönəlirik! :) Bizə lazım olan üsullar lazımi obyektlərə çağırılır. Hər şey sadə və rahatdır. Bu nümunədə sükan və oturacaqların vurğulanması inkapsulyasiyanı gücləndirir (biz müvafiq sinif daxilində velosipedin hissələri haqqında məlumatları gizlədirik) və bizə daha ətraflı abstraksiya yaratmağa imkan verir. İndi başqa bir vəziyyətə baxaq. Deyək ki, biz velosiped və ehtiyat hissələri mağazasını modelləşdirən bir proqram yaratmaq istəyirik. Bu vəziyyətdə əvvəlki həllimiz uğursuz olacaq. Ehtiyat hissələri mağazasının hüdudları daxilində, velosipedin hər bir fərdi hissəsi hətta velosipedin mahiyyətindən başqa bir məna daşıyır. Məsələn, “alıcıya pedal satmaq”, “yeni oturacaq almaq” kimi üsullara ehtiyacımız olacaq. Burada daxili siniflərdən istifadə etmək səhv olardı - yeni proqramımız çərçivəsində velosipedin hər bir fərdi hissəsinin öz mənası var: o, velosipedin mahiyyətindən ayrıdır və heç bir şəkildə onunla bağlı deyil. Daxili siniflərdən istifadə etməyiniz və ya bütün obyektləri ayrı-ayrı siniflərə ayırmağınızla maraqlanırsınızsa, buna diqqət yetirməlisiniz. Obyekt yönümlü proqramlaşdırma əladır, çünki real dünya obyektlərini modelləşdirməyi asanlaşdırır. Daxili siniflərdən istifadə edib-etməmək barədə qərar verərkən bələdçi kimi istifadə edə biləcəyiniz budur. Həqiqi mağazada hissələr velosipedlərdən ayrıdır - bu normaldır. Bu o deməkdir ki, proqram tərtib edərkən bu düzgün olacaq. Yaxşı, biz “fəlsəfəni” sıraladıq :) İndi isə daxili siniflərin vacib “texniki” xüsusiyyətləri ilə tanış olaq. Burada mütləq yadda saxlamalı və başa düşməlisiniz:
-
Daxili sinfin obyekti “xarici” sinfin obyekti olmadan mövcud ola bilməz.
Bu məntiqlidir: buna görə də biz onu
Seat
daxiliHandleBar
siniflər etdik ki, sahibsiz sükan çarxları və oturacaqlar proqramımızda orada-burada görünməsin.Bu kod tərtib edilməyəcək:
public static void main(String[] args) { HandleBar handleBar = new HandleBar(); }
Aşağıdakı mühüm xüsusiyyət bundan irəli gəlir:
-
Daxili sinfin obyekti “xarici” sinfin dəyişənlərinə çıxışa malikdir.
Bicycle
Məsələn, sinfimizə bir dəyişən əlavə edəkint seatPostDiameter
- oturacaq dirəyinin diametri.Sonra daxili sinifdə oturacaq parametrini bizə bildirəcək
Seat
bir üsul yarada bilərik :getSeatParam()
public class Bicycle { private String model; private int weight; private int seatPostDiameter; public Bicycle(String model, int weight, int seatPostDiameter) { this.model = model; this.weight = weight; this.seatPostDiameter = seatPostDiameter; } public void start() { System.out.println("Go!"); } public class Seat { public void up() { System.out.println("The seat is up!"); } public void down() { System.out.println("The seat is down!"); } public void getSeatParam() { System.out.println("Seat parameter: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
İndi bu məlumatı proqramımızda əldə edə bilərik:
public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); Bicycle.Seat seat = bicycle.new Seat(); seat.getSeatParam(); } }
Konsol çıxışı:
Параметр сиденья: диаметр подседельного штыря = 40
Diqqət edin:yeni dəyişən ən sərt dəyişdirici ilə elan edilir -
private
. Və hələ də daxili sinifin girişi var! -
Объект внутреннего класса нельзя создать в статическом методе «внешнего» класса.
Это объясняется особенностями устройства внутренних классов. У внутреннего класса могут быть конструкторы с параметрами or только конструктор по умолчанию. Но независимо от этого, когда мы создаем an object внутреннего класса, в него незаметно передается link на an object «внешнего» класса. Ведь наличие такого an object — обязательное condition. Иначе мы не сможем создавать an objectы внутреннего класса.
Но если метод внешнего класса статический, значит, an object внешнего класса может вообще не существовать! А значит, логика работы внутреннего класса будет нарушена. В такой ситуации компилятор выбросит ошибку:
public static Seat createSeat() { //Bicycle.this cannot be referenced from a static context return new Seat(); }
-
Внутренний класс не может содержать статические переменные и методы.
Логика здесь та же: статические методы и переменные могут существовать и вызваться даже при отсутствии an object.
Но без an object «внешнего» класса доступа к внутреннему классу у нас не будет.
Явное противоречие! Поэтому наличие статических переменных и методов во внутренних классах запрещено.
Компилятор выбросит ошибку при попытке их создать:
public class Bicycle { private int weight; public class Seat { //inner class cannot have static declarations public static void getSeatParam() { System.out.println("Seat parameter: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
-
При создании an object внутреннего класса важную роль играет его модификатор доступа.
Внутренний класс можно обозначить стандартными модификаторами доступа —
public
,private
,protected
иpackage private
.Почему это важно?
Это влияет на то, где в нашей программе мы сможем создавать экземпляры внутреннего класса.
Если наш класс
Seat
объявлен Howpublic
, мы можем создавать его an objectы в любом другом классе. Единственное требование — an object «внешнего» класса тоже обязательно должен существовать.Кстати, мы уже это делали вот здесь:
public class Main { public static void main(String[] args) { Bicycle peugeot = new Bicycle("Peugeot", 120); Bicycle.HandleBar handleBar = peugeot.new HandleBar(); Bicycle.Seat seat = peugeot.new Seat(); seat.up(); peugeot.start(); handleBar.left(); handleBar.right(); } }
Мы легко получor доступ к внутреннему классу
HandleBar
из классаMain
.Если же мы объявим внутренний класс How
private
, доступ к созданию an objectов у нас будет только внутри «внешнего» класса.Создать an object
Seat
снаружи мы уже не сможем:private class Seat { //methods } public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); //Bicycle.Seat has a private access in 'Bicycle' Bicycle.Seat seat = bicycle.new Seat(); } }
Наверное, ты уже понял логику :)
-
Модификаторы доступа для внутренних классов работают так же, How и для обычных переменных.
Модификатор
protected
предоставляет доступ к переменной класса в его классах-наследниках и в классах, которые находятся в том же пакете.Так же
protected
работает и для внутренних классов. Объектыprotected
внутреннего класса можно создавать:- внутри «внешнего» класса;
- в его классах-наследниках;
- в тех классах, которые находятся в том же пакете.
Если у внутреннего класса нет модификатора доступа (
package private
), an objectы внутреннего класса можно создавать- внутри «внешнего» класса;
- в классах, которые находятся в том же пакете.
С модификаторами ты уже давно знаком, так что тут проблем не будет.
GO TO FULL VERSION