Hi! Ngayon ay titingnan natin ang isang mahalagang mekanismo: pamana sa mga nested na klase. Naisip mo na ba kung ano ang iyong gagawin kung kailangan mong gawin ang isang nested class na magmana ng ibang klase. Kung hindi, maniwala ka sa akin: ang sitwasyong ito ay maaaring nakalilito, dahil mayroong maraming mga nuances.
Ang kanilang mga panuntunan sa pamana ay ang pinakasimple. Dito maaari mong gawin ang halos anumang naisin ng iyong puso. Ang isang static na nested na klase ay maaaring magmana ng:
Muli, lumipat tayo mula sa simple patungo sa kumplikado :)
- Gumagawa ba tayo ng nested class na magmana ng ilang klase? O ginagawa ba natin ang ilang klase na magmana ng nested class?
- Ang klase ba ng bata/magulang ay isang ordinaryong pampublikong klase, o isa rin itong nested na klase?
- Panghuli, anong uri ng mga nested na klase ang ginagamit namin sa lahat ng sitwasyong ito?
Mga static na nested na klase

- isang ordinaryong klase
- isang static na nested class na idineklara sa isang outer class o sa mga ninuno nito
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
Subukan nating baguhin ang code at lumikha ng isang Drawing
static na nested class at ang descendant nito — Boeing737Drawing
.
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
public static class Boeing737Drawing extends Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
Tulad ng nakikita mo, walang problema. Maaari pa nga nating i-pull out ang Drawing
klase at gawin itong ordinaryong pampublikong klase sa halip na isang static na nested na klase — walang magbabago.
public class Drawing {
}
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Boeing737Drawing extends Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
Naiintindihan namin ito. Ngunit anong mga klase ang maaaring magmana ng isang static na nested na klase? Halos kahit ano! Nested/non-nested, static/non-static — hindi mahalaga. Dito ginagawa namin ang Boeing737Drawing
panloob na klase na magmana ng Drawing
static na nested na klase:
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
public class Boeing737Drawing extends Drawing {
public int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
Maaari kang lumikha ng isang halimbawa ng Boeing737Drawing
ganito:
public class Main {
public static void main(String[] args) {
Boeing737 boeing737 = new Boeing737(1990);
Boeing737.Boeing737Drawing drawing = boeing737.new Boeing737Drawing();
System.out.println(drawing.getMaxPassengersCount());
}
}
Bagama't ang aming Boeing737Drawing
klase ay nagmamana ng isang static na klase, ito ay hindi static mismo! Bilang resulta, ito ay palaging nangangailangan ng isang halimbawa ng panlabas na klase. Maaari nating alisin ang Boeing737Drawing
klase sa Boeing737
klase at gawin itong isang simpleng pampublikong klase. Walang nagbago. Maaari pa rin itong magmana ng Drawing
static na nested na klase.
public class Boeing737 {
private int manufactureYear;
public static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
}
public class Boeing737Drawing extends Boeing737.Drawing {
public int getMaxPassengersCount() {
return Boeing737.maxPassengersCount;
}
Ang tanging mahalagang punto ay sa kasong ito kailangan nating gawing maxPassengersCount
pampubliko ang static na variable. Kung ito ay mananatiling pribado, kung gayon ang isang ordinaryong pampublikong klase ay hindi magkakaroon ng access dito. Nalaman namin ang mga static na klase! :) Ngayon ay lumipat tayo sa mga panloob na klase. May 3 uri ang mga ito: mga simpleng panloob na klase, lokal na klase, at hindi kilalang panloob na klase. 
Anonymous na mga panloob na klase
Ang isang hindi kilalang panloob na klase ay hindi maaaring magmana ng isa pang klase. Walang ibang klase ang maaaring magmana ng anonymous na klase. Hindi ito maaaring maging mas simple! :)Mga lokal na klase
Ang mga lokal na klase (kung sakaling nakalimutan mo) ay idineklara sa loob ng isang bloke ng code ng isa pang klase. Kadalasan, nangyayari ito sa loob ng ilang paraan ng panlabas na klase. Sa lohikal na paraan, tanging ang iba pang mga lokal na klase sa loob ng parehong pamamaraan (o block ng code) ang maaaring magmana ng isang lokal na klase. Narito ang isang halimbawa:
public class PhoneNumberValidator {
public void validatePhoneNumber(final 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;
}
}
class CellPhoneNumber extends PhoneNumber {
}
class LandlinePhoneNumber extends PhoneNumber {
}
// ...number validation code
}
}
Ito ang code mula sa aming aralin sa mga lokal na klase. Ang aming klase ng validator ng numero ay may PhoneNumber
lokal na klase. Kung kailangan namin itong kumatawan sa dalawang natatanging entity, halimbawa, isang numero ng mobile phone at isang landline na numero ng telepono, magagawa lang namin ito sa loob ng parehong paraan. Ang dahilan ay simple: ang saklaw ng lokal na klase ay limitado sa pamamaraan (code block) kung saan ito idineklara. Bilang resulta, hindi namin ito magagamit sa labas (kabilang ang para sa class inheritance). Gayunpaman, ang mga posibilidad para sa pamana sa loob ng lokal na klase mismo ay mas malawak! Ang isang lokal na klase ay maaaring magmana ng:
- Isang ordinaryong klase.
- Isang panloob na uri na idineklara sa parehong klase ng lokal na klase o sa isa sa mga ninuno nito.
- Ang isa pang lokal na klase ay ipinahayag sa parehong pamamaraan (block ng code).
public class PhoneNumberValidator {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
public void validatePhoneNumber(final String number) {
class CellPhoneNumber extends PhoneNumber {
public CellPhoneNumber(String phoneNumber) {
super(number);
}
}
class LandlinePhoneNumber extends PhoneNumber {
public LandlinePhoneNumber(String phoneNumber) {
super(number);
}
}
// ...number validation code
}
}
Dito namin inalis ang PhoneNumber
klase mula sa validatePhoneNumber()
pamamaraan at ginawa itong isang panloob na klase sa halip na isang lokal na klase. Hindi ito pumipigil sa amin na gawin itong mamanahin ng aming 2 lokal na klase. Halimbawa 2 — "... o sa mga ninuno ng klase na ito." Ngayon ito ay mas kawili-wili. Maaari tayong lumipat PhoneNumber
nang mas mataas sa chain ng mana. Magdeklara tayo ng abstract AbstractPhoneNumberValidator
na klase, na magiging ninuno ng ating PhoneNumberValidator
klase:
public abstract class AbstractPhoneNumberValidator {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
}
Gaya ng nakikita mo, hindi lang namin ito idineklara — inilipat din namin ang PhoneNumber
panloob na klase dito. Gayunpaman, sa inapo nito PhoneNumberValidator
, ang mga lokal na klase na idineklara sa mga pamamaraan ay maaaring magmana PhoneNumber
nang walang anumang problema!
public class PhoneNumberValidator extends AbstractPhoneNumberValidator {
public void validatePhoneNumber(final String number) {
class CellPhoneNumber extends PhoneNumber {
public CellPhoneNumber(String phoneNumber) {
super(number);
}
}
class LandlinePhoneNumber extends PhoneNumber {
public LandlinePhoneNumber(String phoneNumber) {
super(number);
}
}
// ...number validation code
}
}
Dahil sa relasyon sa mana, ang mga lokal na klase sa loob ng isang descendant na klase ay "nakikita" ang mga panloob na klase sa loob ng isang ninuno. At sa wakas, magpatuloy tayo sa huling grupo :)
Mga panloob na klase
Ang isang panloob na uri na idineklara sa parehong panlabas na uri (o sa inapo nito) ay maaaring magmana ng isa pang panloob na uri. Tuklasin natin ito gamit ang ating halimbawa sa mga bisikleta mula sa aralin sa mga panloob na klase.
public class Bicycle {
private String model;
private int maxWeight;
public Bicycle(String model, int maxWeight) {
this.model = model;
this.maxWeight = maxWeight;
}
public void start() {
System.out.println("Let's go!");
}
class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
class SportSeat extends Seat {
// ...methods
}
}
Dito namin idineklara ang Seat
inner class sa loob ng Bicycle
klase. Isang espesyal na uri ng racing seat, SportSeat
, ang namamana nito. Ngunit, maaari tayong lumikha ng isang hiwalay na uri ng "karera ng bisikleta" at ilagay ito sa isang hiwalay na klase:
public class SportBicycle extends Bicycle {
public SportBicycle(String model, int maxWeight) {
super(model, maxWeight);
}
class SportSeat extends Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
}
Isa rin itong opsyon. "Nakikita" ng panloob na klase ng inapo ( SportBicycle.SportSeat
) ang mga panloob na klase ng ninuno at maaaring magmana ng mga ito. Ang pagmamana ng mga panloob na klase ay may isang napakahalagang tampok! Sa nakaraang dalawang halimbawa, ang aming SportSeat
klase ay isang panloob na klase. Ngunit paano kung magpasya tayong gumawa SportSeat
ng ordinaryong pampublikong klase na sabay-sabay na nagmamana ng Seat
panloob na uri?
// Error! No enclosing instance of type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {
public SportSeat() {
}
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
Nagkaroon kami ng error! Maaari mo bang hulaan kung bakit? :) Diretso lang lahat. Nang pag-usapan natin ang tungkol sa Bicycle.Seat
panloob na klase, binanggit namin na ang isang sanggunian sa isang halimbawa ng panlabas na klase ay tahasang ipinapasa sa tagabuo ng panloob na klase. Nangangahulugan ito na hindi ka makakalikha ng isang Seat
bagay nang hindi gumagawa ng isang Bicycle
bagay. Ngunit ano ang tungkol sa paglikha ng isang SportSeat
? Hindi tulad ng Seat
, wala itong built-in na mekanismo para sa tahasang pagpasa sa tagabuo ng isang sanggunian sa isang halimbawa ng panlabas na klase. Hanggang sa, kung walang Bicycle
bagay, hindi tayo makakalikha ng isang SportSeat
bagay, tulad ng sa kaso ng Seat
. Samakatuwid, isang bagay na lang ang natitira para sa amin - tahasang ipasa sa SportSeat
constructor ang isang reference sa isang Bicycle
bagay. Narito kung paano ito gawin:
class SportSeat extends Bicycle.Seat {
public SportSeat(Bicycle bicycle) {
bicycle.super();
}
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
Tinatawag namin ang superclass constructor gamit super();
ang Now, kung gusto naming lumikha ng isang SportSeat
bagay, walang makakapigil sa aming gawin ito:
public class Main {
public static void main(String[] args) {
Bicycle bicycle = new Bicycle("Peugeot", 120);
SportSeat peugeotSportSeat = new SportSeat(bicycle);
}
}
Phew! Medyo mahaba ang lesson na ito :) Pero marami kang natutunan! Ngayon ay oras na upang malutas ang ilang mga gawain! :)
GO TO FULL VERSION