class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
Ang mga panloob na klase na ito ay tinatawag na nested. Nahahati sila sa 2 uri:
- Mga non-static na nested na klase. Ang mga ito ay tinatawag ding mga panloob na klase.
- Mga static na nested na klase.
- isang lokal na klase
- isang hindi kilalang klase
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("Let's go!");
}
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left!");
}
}
public class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
}
Eto na ang klase namin Bicycle
. Mayroon itong 2 field at 1 method: start()
. Naiiba ito sa isang ordinaryong klase dahil naglalaman ito ng dalawang klase: Handlebar
at Seat
. Ang kanilang code ay nakasulat sa loob ng Bicycle
klase. Ang mga ito ay ganap na mga klase: tulad ng nakikita mo, bawat isa sa kanila ay may sariling mga pamamaraan. Sa puntong ito, maaaring may tanong ka: bakit sa mundo natin ilalagay ang isang klase sa isa pa? Bakit ginagawa silang mga panloob na klase? Well, ipagpalagay na kailangan namin ng hiwalay na mga klase para sa mga konsepto ng handlebar at upuan sa aming programa. Syempre, hindi naman natin kailangan gawin silang nested! Maaari tayong gumawa ng mga ordinaryong klase. Halimbawa, tulad nito:
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left");
}
}
public class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
Napakagandang tanong! Siyempre, hindi tayo nalilimitahan ng teknolohiya. Ang paggawa nito ay tiyak na isang opsyon. Dito, ang mahalagang bagay ay mas tamang disenyo ng mga klase mula sa pananaw ng isang partikular na programa at layunin nito. Ang mga panloob na klase ay para sa paghihiwalay ng isang entity na hindi mapaghihiwalay na konektado sa isa pang entity. Ang mga handlebar, upuan, at pedal ay mga bahagi ng isang bisikleta. Hiwalay sa bisikleta, wala silang katuturan. Kung ginawa naming hiwalay ang lahat ng mga konseptong ito sa mga pampublikong klase, magkakaroon kami ng ganitong code sa aming programa:
public class Main {
public static void main(String[] args) {
Handlebar handlebar = new Handlebar();
handlebar.right();
}
}
Hmm... Mahirap pa ngang ipaliwanag ang kahulugan ng code na ito. Mayroon kaming ilang hindi malinaw na manibela (Bakit kailangan? Walang ideya, sa totoo lang). At ang hawakan na ito ay lumiliko sa kanan... mag-isa, walang bisikleta... sa ilang kadahilanan. Sa pamamagitan ng paghihiwalay ng konsepto ng manibela mula sa konsepto ng bisikleta, nawalan kami ng ilang lohika sa aming programa. Gamit ang isang panloob na klase, ang code ay mukhang ibang-iba:
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();
}
}
Output ng console:
Seat up!
Let's go!
Steer left!
Steer right!
Ngayon ang nakikita natin ay biglang may katuturan! :) Gumawa kami ng bagay sa bisikleta. Gumawa kami ng dalawang "subobject" ng bisikleta — isang manibela at isang upuan. Itinaas namin ang upuan para komportable at umalis na kami: pagpedal at pagpipiloto kung kinakailangan! :) Ang mga pamamaraan na kailangan namin ay tinatawag sa naaangkop na mga bagay. Ang lahat ng ito ay simple at maginhawa. Sa halimbawang ito, ang paghihiwalay sa handlebar at upuan ay nagpapahusay ng encapsulation (tinatago namin ang data tungkol sa mga bahagi ng bisikleta sa loob ng nauugnay na klase) at hinahayaan kaming gumawa ng mas detalyadong abstraction. Ngayon tingnan natin ang ibang sitwasyon. Ipagpalagay na gusto naming lumikha ng isang programa na gayahin ang isang tindahan ng bisikleta at mga ekstrang bahagi para sa mga bisikleta. Sa sitwasyong ito, hindi gagana ang dati nating solusyon. Sa isang tindahan ng bisikleta, ang bawat indibidwal na bahagi ng bisikleta ay may katuturan kahit na nakahiwalay sa isang bisikleta. Halimbawa, kakailanganin namin ng mga pamamaraan tulad ng "magbenta ng mga pedal sa isang customer", "bumili ng bagong upuan", atbp. Magiging isang pagkakamali na gumamit ng mga panloob na klase dito — bawat indibidwal na bahagi ng bisikleta sa aming bagong programa ay may kahulugan na nakatayo sa sarili nito: maaari itong ihiwalay sa konsepto ng isang bisikleta. Ito mismo ang kailangan mong bigyang pansin kung iniisip mo kung dapat mong gamitin ang mga panloob na klase o ayusin ang lahat ng entity bilang magkakahiwalay na klase. Mahusay ang Object-oriented na programming dahil ginagawa nitong madali ang pag-modelo ng mga real-world na entity. Maaaring ito ang iyong gabay na prinsipyo kapag nagpapasya kung gagamit ng mga panloob na klase. Sa totoong tindahan, Ang mga ekstrang bahagi ay hiwalay sa mga bisikleta — ayos lang ito. Nangangahulugan ito na okay din kapag nagdidisenyo ng isang programa. Okay, nalaman na natin ang "pilosopiya" :) Ngayon ay kilalanin natin ang mahahalagang "teknikal" na mga tampok ng mga panloob na klase. Narito ang tiyak na kailangan mong tandaan at maunawaan:
-
Ang isang bagay ng isang panloob na klase ay hindi maaaring umiral nang walang isang bagay ng isang panlabas na klase.
Makatuwiran ito: ito ang dahilan kung bakit ginawa namin ang
Seat
atHandlebar
panloob na mga klase sa aming programa — upang hindi kami mauwi sa mga ulilang manibela at upuan.Ang code na ito ay hindi nag-compile:
public static void main(String[] args) { Handlebar handlebar = new Handlebar(); }
Ang isa pang mahalagang tampok ay sumusunod mula dito:
-
Ang isang bagay ng isang panloob na klase ay may access sa mga variable ng panlabas na klase.
Halimbawa, magdagdag tayo ng
int seatPostDiameter
variable (kumakatawan sa diameter ng seatpost) sa atingBicycle
klase.Pagkatapos sa
Seat
panloob na klase, maaari tayong lumikha ng isangdisplaySeatProperties()
paraan na nagpapakita ng mga katangian ng upuan: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("Let's go!"); } public class Seat { public void up() { System.out.println("Seat up!"); } public void down() { System.out.println("Seat down!"); } public void displaySeatProperties() { System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
At ngayon ay maipapakita namin ang impormasyong ito sa aming programa:
public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); Bicycle.Seat seat = bicycle.new Seat(); seat.displaySeatProperties(); } }
Output ng console:
Seat properties: seatpost diameter = 40
Tandaan:ang bagong variable ay idineklara na may pinakamahigpit na access modifier (
private
). At mayroon pa ring access ang panloob na klase! -
Ang isang bagay ng isang panloob na klase ay hindi maaaring gawin sa isang static na pamamaraan ng isang panlabas na klase.
Ito ay ipinaliwanag sa pamamagitan ng mga partikular na tampok kung paano nakaayos ang mga panloob na klase. Ang isang panloob na klase ay maaaring magkaroon ng mga konstruktor na may mga parameter, o ang default na konstruktor lamang. Ngunit anuman, kapag lumikha tayo ng isang bagay ng isang panloob na klase, ang isang sanggunian sa bagay ng panlabas na klase ay hindi nakikitang ipinapasa sa nilikha na bagay ng panloob na klase. Pagkatapos ng lahat, ang pagkakaroon ng naturang object reference ay isang ganap na kinakailangan. Kung hindi, hindi kami makakagawa ng mga bagay ng inner class.
Ngunit kung ang isang paraan ng panlabas na klase ay static, kung gayon maaari tayong walang object ng panlabas na klase! At ito ay magiging isang paglabag sa lohika kung paano gumagana ang isang panloob na klase. Sa sitwasyong ito, bubuo ng error ang compiler:
public static Seat createSeat() { // Bicycle.this cannot be referenced from a static context return new Seat(); }
-
Ang isang panloob na klase ay hindi maaaring maglaman ng mga static na variable at pamamaraan.
Ang lohika ay pareho: ang mga static na pamamaraan at mga variable ay maaaring umiral at matatawag o i-reference kahit na wala ang isang bagay.
Ngunit kung walang object ng outer class, hindi tayo magkakaroon ng access sa inner class.
Isang malinaw na kontradiksyon! Ito ang dahilan kung bakit hindi pinapayagan ang mga static na variable at pamamaraan sa mga panloob na klase.
Ang compiler ay bubuo ng error kung susubukan mong likhain ang mga ito:
public class Bicycle { private int weight; public class Seat { // An inner class cannot have static declarations public static void displaySeatProperties() { System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
-
Kapag lumilikha ng isang bagay ng isang panloob na klase, ang access modifier nito ay mahalaga.
Maaaring markahan ang isang panloob na klase ng mga karaniwang modifier ng access:
public
,private
,protected
, atpackage private
.Bakit ito mahalaga?
Nakakaapekto ito kung saan tayo makakagawa ng mga instance ng inner class sa ating programa.
Kung ang aming
Seat
klase ay idineklara bilangpublic
, maaari kaming lumikhaSeat
ng mga bagay sa anumang iba pang klase. Ang tanging kinakailangan ay ang isang bagay ng panlabas na uri ay dapat ding umiral.By the way, nagawa na namin ito dito:
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(); } }
Madali kaming nakakuha ng access sa
Handlebar
inner class mula saMain
klase.Kung idedeklara natin ang inner class bilang
private
, makakagawa lang tayo ng mga object sa loob ng outer class.Hindi na kami makakagawa ng
Seat
object "sa labas":private class Seat { // Methods } public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); // Bicycle.Seat has private access in Bicycle Bicycle.Seat seat = bicycle.new Seat(); } }
Malamang naiintindihan mo na ang logic :)
-
Ang mga modifier ng access para sa mga panloob na klase ay gumagana katulad ng para sa mga ordinaryong variable.
Ang
protected
modifier ay nagbibigay ng access sa isang instance variable sa mga subclass at class na nasa parehong package.protected
gumagana din para sa mga panloob na klase. Maaari tayong lumikhaprotected
ng mga bagay ng panloob na klase:- sa panlabas na uri;
- sa mga subclass nito;
- sa mga klase na nasa parehong pakete.
Kung ang inner class ay walang access modifier (
package private
), ang mga object ng inner class ay maaaring malikha:- sa panlabas na uri;
- sa mga klase na nasa parehong pakete.
Matagal ka nang pamilyar sa mga modifier, kaya walang problema dito.
GO TO FULL VERSION