Detaljno objašnjenje upotrebe i razlika između Java this i super ključnih reči
"Brate, kako je osećaj kada te zovu 'veliki brat'?" Sanmej me je upitala sa zlonamernim osmehom, a u očima joj se videlo nepoštovanje.
"Iskreno, prilično je prijatan osećaj." pomalo postideno sam joj odgovorio. "Ali, jedna stvar me malo razočarava. Čini se da su svi fokusirani na tvoj izgled, potpuno zanemarujući moju lepotu!"
"Brate, o čemu pričaš, to je zato što dobro pišeš članke, inače niko ne bi znao ko sam ja! Imati brata kao što si ti, zaista sam ponosna." Sanmej je svečano rekla. "Dakle, šta danas učimo?"
"Sanmej, baš mi se sviđa kako to kažeš. Danas da učimo o this ključnoj reči u Javi." Nakon gutljaja vode, rekao sam Sanmej.
"this ključna reč ima mnogo upotreba, a jedna od najčešćih je da služi kao referentna promenljiva koja ukazuje na trenutni objekat." nastavio sam sa prostim osmehom. "Pored toga, this ključna reč može obaviti i sledeće poslove."
- Poziva metode trenutne klase;
this()može pozvati konstruktor trenutne klase;- this može biti prosleđen kao parametar unutar metode;
- this može biti prosleđen kao parametar unutar konstruktora;
- this može biti povratna vrednost metoda, koja vraća objekat trenutne klase.
01. Pokazivač na trenutni objekat
"Sanmej, pogledaj sledeći kod." Jedva što sam izgovorio to, već sam počeo da brzo kucam po tastaturi.
public class WithoutThisStudent {
String name;
int age;
WithoutThisStudent(String name, int age) {
name = name;
age = age;
}
void out() {
System.out.println(name+" " + age);
}
public static void main(String[] args) {
WithoutThisStudent s1 = new WithoutThisStudent("Chenmo Wang Er", 18);
WithoutThisStudent s2 = new WithoutThisStudent("Chenmo Wang San", 16);
s1.out();
s2.out();
}
}"U gornjem primeru, ime parametra konstruktora i ime instancne promenljive su iste; pošto se ne koristi this ključna reč, nije moguće dodeliti vrednost instancnoj promenljivoj." Podigao sam kažiprst desne ruke, pokazao na name i age na ekranu i rekao Sanmej.
"Da pogledamo izlaz programa."
null 0
null 0"Iz rezultata se može videti da, iako su prosleđeni parametri pri kreiranju objekta, instancne promenljive nisu dobile vrednost. To je zato što ako se u konstruktoru ne koristi this ključna reč, name i age ne ukazuju na instancne promenljive, već na same parametre." Okrenuo sam vrat udesno i pogledao Sanmej.
"Kako onda da rešimo ovaj problem, brate?" Sanmej je zabrinuto pitala.
"Ako su ime parametra i ime instancne promenljive u konfliktu..." spremao sam da dam odgovor, a Sanmej me prekinula.
"Da li da koristimo this?" Sanmej je izustila.
"O, sve bolje i bolje!" Osetio sam da Sanmej sve više razvija sopstvenu želju za razmišljanjem na putu učenja Jave.
"Da, pogledaj kod nakon dodavanja this ključne reči."
U tihoj sobi ponovo su odjekivali zvuci kucanja po tastaturi.
public class WithThisStudent {
String name;
int age;
WithThisStudent(String name, int age) {
this.name = name;
this.age = age;
}
void out() {
System.out.println(name+" " + age);
}
public static void main(String[] args) {
WithThisStudent s1 = new WithThisStudent("Chenmo Wang Er", 18);
WithThisStudent s2 = new WithThisStudent("Chenmo Wang San", 16);
s1.out();
s2.out();
}
}"Da ponovo pogledamo izlaz programa."
Chenmo Wang Er 18
Chenmo Wang San 16"Ovaj put instancne promenljive imaju vrednosti; u konstruktoru, this.xxx ukazuje na instancnu promenljivu, a ne više na sam parametar." polako sam govorio. "Naravno, ako se ime parametra i ime instancne promenljive razlikuju, onda nije potrebno koristiti this ključnu reč, ali preporučujem da je ipak koristite jer takav kod ima više smisla."
02. Pozivanje metoda trenutne klase
"Pažljivo slušaj, Sanmej, da vidimo da li kucam dovoljno brzo."
public class InvokeCurrentClassMethod {
void method1() {}
void method2() {
method1();
}
public static void main(String[] args) {
new InvokeCurrentClassMethod().method1();
}
}"Pogledaj pažljivo, Sanmej, u gornjem kodu nigde se ne vidi this ključna reč, zar ne?" rekao sam sa tajanstvenim osmehom, spreman da pokažem Sanmej trik.
"Zaista nema, brate, proverila sam."
"Onda, sada će se desiti nešto čarobno." Najednom sam osetio kao da me obuzeo Liu Qian.
Brzo sam pronašao fajl InvokeCurrentClassMethod.class u direktorijumu classes, a zatim ga dvaput kliknuo (IDEA će podrazumevano otvoriti bajtkod fajl pomoću FernFlower-a).
public class InvokeCurrentClassMethod {
public InvokeCurrentClassMethod() {
}
void method1() {
}
void method2() {
this.method1();
}
public static void main(String[] args) {
(new InvokeCurrentClassMethod()).method1();
}
}"Otvori oči i pogledaj pažljivo, Sanmej, nije li se pojavila this ključna reč?"
"O, zaista, kako je čarobno!" Sanmej se prilično potrudila da pravi mom nastupu.
"Možemo koristiti this ključnu reč u jednoj klasi da pozovemo drugi metod; ako se ne koristi, kompajler će je automatski dodati za nas." Bio sam pun samopouzdanja u svoje duboko poznavanje programiranja. "U izvornom kodu, method2() nije koristio this ključnu reč pri pozivu method1(), ali se to može videti u dekompajliranom bajtkodu."
03. Pozivanje konstruktora trenutne klase
"Pogledaj ponovo sledeći kod."
public class InvokeConstrutor {
InvokeConstrutor() {
System.out.println("hello");
}
InvokeConstrutor(int count) {
this();
System.out.println(count);
}
public static void main(String[] args) {
InvokeConstrutor invokeConstrutor = new InvokeConstrutor(10);
}
}"U parametrizovanom konstruktoru InvokeConstrutor(int count), koristi se this() da pozove konstruktor bez parametara InvokeConstrutor()." Ovaj put sam koristio kažiprst leve ruke, pokazujući na ekran prema Sanmej. "this() se može koristiti za pozivanje konstruktora trenutne klase — konstruktor se može ponovo koristiti."
"Da pogledamo izlaz."
hello
10"Zaista, i konstruktor bez parametara je pozvan, pa je program ispisao hello." Sanmej je bez razmišljanja rekla kada je videla izlaz.
"Takođe se može koristiti this() u konstruktoru bez parametara i proslediti parametre da bi se pozvao parametrizovani konstruktor." Jedva što sam završio rečenicu, već sam počeo da kucam po tastaturi. "Pogledaj sledeći kod."
public class InvokeParamConstrutor {
InvokeParamConstrutor() {
this(10);
System.out.println("hello");
}
InvokeParamConstrutor(int count) {
System.out.println(count);
}
public static void main(String[] args) {
InvokeParamConstrutor invokeConstrutor = new InvokeParamConstrutor();
}
}"Da ponovo pogledamo izlaz."
10
hello"Međutim, važno je zapaziti da this() mora biti na prvom redu konstruktora, inače će doći do greške."

04. this kao parametar u metodi
"Pogledaj sledeći kod."
public class ThisAsParam {
void method1(ThisAsParam p) {
System.out.println(p);
}
void method2() {
method1(this);
}
public static void main(String[] args) {
ThisAsParam thisAsParam = new ThisAsParam();
System.out.println(thisAsParam);
thisAsParam.method2();
}
}"this ključna reč može biti prosleđena kao parametar u metodi; u tom slučaju ona ukazuje na objekat trenutne klase." Iznenada, pola sata je prošlo, osetio sam da mi je grlo suvo, pa sam brzo popio gutljaj vode i nastavio.
"Pogledaj izlaz, pa ćeš razumeti, Sanmej."
com.itwanger.twentyseven.ThisAsParam@77459877
com.itwanger.twentyseven.ThisAsParam@77459877"method2() je pozvao method1() i prosledio parametar this; method1() je ispisao string trenutnog objekta. U main() metodi ispisan je string thisAsParam objekta. Iz rezultata se može videti da je u pitanju isti objekat."
05. this kao parametar u konstruktoru
"Nastavimo sa kodom."
public class ThisAsConstrutorParam {
int count = 10;
ThisAsConstrutorParam() {
Data data = new Data(this);
data.out();
}
public static void main(String[] args) {
new ThisAsConstrutorParam();
}
}
class Data {
ThisAsConstrutorParam param;
Data(ThisAsConstrutorParam param) {
this.param = param;
}
void out() {
System.out.println(param.count);
}
}"U konstruktoru ThisAsConstrutorParam() koristili smo this ključnu reč kao parametar prosleđen Data objektu; ona zapravo ukazuje na taj objekat new ThisAsConstrutorParam()."
"this ključna reč se takođe može proslediti kao parametar u konstruktoru i ukazuje na objekat trenutne klase. Ovo je veoma korisno kada nam je potreban jedan objekat u više klasa."
"Pogledajmo izlaz."
1006. this kao povratna vrednost metode
"Da li ti treba pauza, Sanmej?"
"Ne, brate, pažnja mi je i dalje potpuno koncentrisana, nastavi."
"Dobro, onda da nastavimo sa kodom."
public class ThisAsMethodResult {
ThisAsMethodResult getThisAsMethodResult() {
return this;
}
void out() {
System.out.println("hello");
}
public static void main(String[] args) {
new ThisAsMethodResult().getThisAsMethodResult().out();
}
}"Metod getThisAsMethodResult() vraća this ključnu reč, koja ukazuje na taj objekat new ThisAsMethodResult(), pa se može odmah pozvati out() metod — čime se postiže ulančavanje poziva, što je takođe jedna veoma klasična upotreba this ključne reči."
"Oblik ulančavanja poziva je češći u JavaScript kodu." Da bih to dokazao Sanmej, otvorio sam izvorni kod jQuery-ja.
"Zaista mnogo ulančavanja!" Sanmej je uzviknula.
"Da." Klimnuo sam, a zatim pokazao na povratnu vrednost metoda getThisAsMethodResult() i rekao Sanmej: "Važno je napomenuti da kada je this ključna reč povratna vrednost metode, tip povratne vrednosti metode je tip klase."
"Pogledajmo izlaz."
hello"Dakle, to bi bilo sve o this ključnoj reči." Protegnuo sam ukočeni vrat i rekao Sanmej. "Ako ti još uvek imaš volje za učenjem, možemo usput da prođemo i super ključnu reč, šta kažeš?"
"Nema potrebe, čula sam da je super ključna reč jednostavnija, pročitaću je sama, ne moraš mi objašnjavati!"
"Ne ne ne, Sanmej, moraš se pretvarati da slušaš, inače kako ću se izvući pred čitaocima."
"Oh oh oh oh." Sanmej se duboko značajno nasmejala.
07. super ključna reč
"super ključna reč ima uglavnom tri načina upotrebe."
- Ukazuje na objekat roditeljske klase;
- Poziva metod roditeljske klase;
super()može pozvati konstruktor roditeljske klase.
"Zapravo je prilično slično sa this, samo je namena drugačija." Podigao sam flašu s vodom, gutljaj-po-gutljaj popio još nekoliko velikih gutljaja — bio sam žedan. "Svaki put kada se kreira objekat izvedene klase, implicitno se kreira i objekat roditeljske klase, na koji ukazuje super ključna reč."
"Ako roditeljska klasa i izvedena klasa imaju polje sa istim imenom, super ključna reč se može koristiti za pristup istoimenom polju roditeljske klase."
"Pogledaj sledeći kod."
public class ReferParentField {
public static void main(String[] args) {
new Dog().printColor();
}
}
class Animal {
String color = "bela";
}
class Dog extends Animal {
String color = "crna";
void printColor() {
System.out.println(color);
System.out.println(super.color);
}
}"U roditeljskoj klasi Animal postoji polje imenom color; u izvedenoj klasi Dog takođe postoji polje imenom color; u metodu printColor() izvedene klase, preko super ključne reči može se pristupiti color-u roditeljske klase."
"Pogledajmo izlaz."
crna
bela"Kada su imena metoda u izvedenoj i roditeljskoj klasi ista, može se koristiti super ključna reč da pozove metod roditeljske klase. Drugim rečima, super ključna reč se može koristiti za pristup metodi roditeljske klase prilikom prepisivanja metoda."
public class ReferParentMethod {
public static void main(String[] args) {
new Dog().work();
}
}
class Animal {
void eat() {
System.out.println("jede...");
}
}
class Dog extends Animal {
@Override
void eat() {
System.out.println("jede...");
}
void bark() {
System.out.println("vau vau vau...");
}
void work() {
super.eat();
bark();
}
}"Gledaj, Sanmej. I roditeljska klasa Animal i izvedena klasa Dog imaju metod eat(); preko super.eat() može se pristupiti eat() metodi roditeljske klase."
Dok je Sanmej razmišljala o tome, ja sam za to vreme otkucao još jedan komad koda.
public class ReferParentConstructor {
public static void main(String[] args) {
new Dog();
}
}
class Animal {
Animal(){
System.out.println("životinja je došla");
}
}
class Dog extends Animal {
Dog() {
super();
System.out.println("pas je došao");
}
}"U konstruktoru izvedene klase Dog, prvi red koda je super(), koji služi da pozove konstruktor roditeljske klase."
"Pogledajmo izlaz."
životinja je došla
pas je došao"Naravno, podrazumevano, super() se može izostaviti, kompajler će sam pozvati konstruktor roditeljske klase. Drugim rečima, čak i ako izvedena klasa ne koristi super() da aktivno pozove konstruktor roditeljske klase, konstruktor roditeljske klase će se i dalje izvršiti prvi."
public class ReferParentConstructor {
public static void main(String[] args) {
new Dog();
}
}
class Animal {
Animal(){
System.out.println("životinja je došla");
}
}
class Dog extends Animal {
Dog() {
System.out.println("pas je došao");
}
}"Izlaz je isti kao i pre."
životinja je došla
pas je došao"super() se takođe može koristiti za poziv parametrizovanog konstruktora roditeljske klase, što može poboljšati ponovnu iskoristivost koda."
class Person {
int id;
String name;
Person(int id, String name) {
this.id = id;
this.name = name;
}
}
class Emp extends Person {
float salary;
Emp(int id, String name, float salary) {
super(id, name);
this.salary = salary;
}
void display() {
System.out.println(id + " " + name + " " + salary);
}
}
public class CallParentParamConstrutor {
public static void main(String[] args) {
new Emp(1, "Chenmo Wang Er", 20000f).display();
}
}"Klasa Emp nasleđuje klasu Person, što znači da nasleđuje id i name polja; kada se u Emp doda novo polje salary, u konstruktoru se može koristiti super(id, name) da pozove parametrizovani konstruktor roditeljske klase."
"Pogledajmo izlaz."
1 Chenmo Wang Er 20000.0Sanmej je klimnula glavom, zamišljena.
