Mungkin sampeyan wis nemoni konsep "refleksi" ing urip biasa. Tembung iki biasane nuduhake proses sinau dhewe. Ing pemrograman, nduweni makna sing padha - yaiku mekanisme kanggo nganalisa data babagan program, lan malah ngganti struktur lan prilaku program, nalika program kasebut mlaku.
Sing penting ing kene yaiku kita nindakake iki nalika runtime, dudu ing wektu kompilasi. Nanging kenapa mriksa kode nalika runtime? Sawise kabeh, sampeyan wis bisa maca kode kasebut: / Ana alesan kenapa ide refleksi bisa uga ora jelas: nganti saiki, sampeyan mesthi ngerti kelas sing digunakake. Contone, sampeyan bisa nulis
Kanggo ringkesan, kita ngilangi kode penanganan pangecualian sing tepat, sing mbutuhake papan luwih akeh tinimbang conto kasebut. Ing program nyata, mesthi, sampeyan kudu nangani kahanan nglibatno salah ngetik jeneng, etc. Konstruktor gawan cukup prasaja, supaya sampeyan bisa ndeleng, iku gampang kanggo nggunakake kanggo nggawe Kayata saka kelas :) Nggunakake

Cat
kelas:
package learn.codegym;
public class Cat {
private String name;
private int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public void sayMeow() {
System.out.println("Meow!");
}
public void jump() {
System.out.println("Jump!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Sampeyan ngerti kabeh babagan iki, lan sampeyan bisa ndeleng lapangan lan cara sing diduweni. Umpamane sampeyan kudu ngenalake kelas kewan liyane menyang program kasebut. Sampeyan mbokmenawa bisa nggawe struktur warisan kelas karo Animal
kelas induk kanggo penak. Sadurungé, kita malah nggawe kelas makili klinik Veterinary, kang kita bisa pass obyek Animal
(kayata kelas tiyang sepah), lan program dianggep kewan jumbuh adhedhasar apa iku asu utawa kucing. Sanajan iki dudu tugas sing paling gampang, program kasebut bisa sinau kabeh informasi sing dibutuhake babagan kelas ing wektu kompilasi. Patut, nalika sampeyan pass Cat
obyek kanggo cara saka kelas Clinic Veterinary ingmain()
cara, program wis ngerti sing iku kucing, ora asu. Saiki ayo bayangake yen kita ngadhepi tugas sing beda. Tujuan kita yaiku nulis penganalisa kode. Kita kudu nggawe CodeAnalyzer
kelas kanthi cara siji: void analyzeObject(Object o)
. Cara iki kudu:
- nemtokake kelas obyek liwati lan nampilake jeneng kelas ing console;
- nemtokake jeneng kabeh lapangan kelas liwati, kalebu pribadi, lan nampilake ing console;
- nemtokake jeneng kabeh cara saka kelas liwati, kalebu pribadi, lan nampilake ing console.
public class CodeAnalyzer {
public static void analyzeClass(Object o) {
// Print the name of the class of object o
// Print the names of all variables of this class
// Print the names of all methods of this class
}
}
Saiki kita bisa ndeleng kanthi jelas kepiye tugas iki beda karo tugas liyane sing wis dirampungake sadurunge. Kanthi tujuan kita saiki, kangelan dumunung ing kasunyatan manawa kita utawa program ora ngerti apa sing bakal diterusake menyanganalyzeClass()
cara. Yen sampeyan nulis program kuwi, programer liyane bakal miwiti nggunakake, lan padha bisa pass apa-apa kanggo cara iki - sembarang kelas Jawa standar utawa kelas liyane padha nulis. Kelas sing wis lulus bisa duwe sawetara variabel lan metode. Kanthi tembung liyane, kita (lan program kita) ora ngerti kelas apa sing bakal kita lakoni. Nanging isih, kita kudu ngrampungake tugas iki. Lan ing kene API Refleksi Java standar mbantu kita. API Refleksi minangka alat basa sing kuat. Dokumentasi resmi Oracle nyaranake mekanisme iki mung bisa digunakake dening programer sing berpengalaman sing ngerti apa sing ditindakake. Sampeyan bakal ngerti apa sebabe kita menehi bebaya kaya iki luwih dhisik :) Mangkene dhaptar perkara sing bisa ditindakake nganggo API Refleksi:
- Ngenali / nemtokake kelas obyek.
- Entuk informasi babagan modifiers kelas, kolom, metode, konstanta, konstruktor, lan superclass.
- Temokake cara sing kalebu antarmuka sing diimplementasikake.
- Nggawe conto kelas sing jeneng kelas ora dikenal nganti program dieksekusi.
- Entuk lan setel nilai lapangan conto kanthi jeneng.
- Nelpon cara conto kanthi jeneng.
Carane ngenali / nemtokake kelas obyek
Ayo dadi miwiti karo dhasar. Titik entri menyang mesin refleksi Jawa yaiku kelasClass
. Ya, iku katon tenan lucu, nanging sing apa bayangan :) Nggunakake kelas Class
, kita pisanan nemtokake kelas sembarang obyek liwati kanggo cara kita. Ayo nyoba nindakake iki:
import learn.codegym.Cat;
public class CodeAnalyzer {
public static void analyzeClass(Object o) {
Class clazz = o.getClass();
System.out.println(clazz);
}
public static void main(String[] args) {
analyzeClass(new Cat("Fluffy", 6));
}
}
Output konsol:
class learn.codegym.Cat
Pay manungsa waé kanggo rong perkara. Kaping pisanan, kita sengaja nyelehake Cat
kelas kasebut ing learn.codegym
paket sing kapisah. Saiki sampeyan bisa ndeleng manawa getClass()
metode kasebut ngasilake jeneng lengkap kelas kasebut. Kapindho, kita jenenge variabel kita clazz
. Sing katon rada aneh. Mesthi wae yen diarani "kelas", nanging "kelas" minangka tembung sing dilindhungi ing basa Jawa. Compiler ora ngidini variabel kasebut diarani. Kita kudu ngubengi sing piye wae :) Ora ala kanggo wiwitan! Apa maneh sing ana ing dhaptar kapabilitas kasebut?
Carane entuk informasi babagan modifiers kelas, kolom, metode, konstanta, konstruktor, lan superclasses.
Saiki samubarang dadi luwih menarik! Ing kelas saiki, kita ora duwe konstanta utawa kelas induk. Ayo ditambahake kanggo nggawe gambar lengkap. NggaweAnimal
kelas induk sing paling gampang:
package learn.codegym;
public class Animal {
private String name;
private int age;
}
Lan kita bakal nggawe Cat
kelas warisan Animal
lan nambah siji konstanta:
package learn.codegym;
public class Cat extends Animal {
private static final String ANIMAL_FAMILY = "Feline family";
private String name;
private int age;
// ...the rest of the class
}
Saiki kita duwe gambar lengkap! Ayo ndeleng refleksi apa sing bisa ditindakake :)
import learn.codegym.Cat;
import java.util.Arrays;
public class CodeAnalyzer {
public static void analyzeClass(Object o) {
Class clazz = o.getClass();
System.out.println("Class name: " + clazz);
System.out.println("Class fields: " + Arrays.toString(clazz.getDeclaredFields()));
System.out.println("Parent class: " + clazz.getSuperclass());
System.out.println("Class methods: " + Arrays.toString(clazz.getDeclaredMethods()));
System.out.println("Class constructors: " + Arrays.toString(clazz.getConstructors()));
}
public static void main(String[] args) {
analyzeClass(new Cat("Fluffy", 6));
}
}
Mangkene apa sing kita deleng ing konsol:
Class name: class learn.codegym.Cat
Class fields: [private static final java.lang.String learn.codegym.Cat.ANIMAL_FAMILY, private java.lang.String learn.codegym.Cat.name, private int learn.codegym.Cat.age]
Parent class: class learn.codegym.Animal
Class methods: [public java.lang.String learn.codegym.Cat.getName(), public void learn.codegym.Cat.setName(java.lang.String), public void learn.codegym.Cat.sayMeow(), public void learn.codegym.Cat.setAge(int), public void learn.codegym.Cat.jump(), public int learn.codegym.Cat.getAge()]
Class constructors: [public learn.codegym.Cat(java.lang.String, int)]
Deleng kabeh informasi kelas sing rinci sing bisa dipikolehi! Lan ora mung informasi umum, nanging uga informasi pribadi! Cathetan: private
variabel uga ditampilake ing dhaptar. "Analisis" kelas kita bisa dianggep pancen lengkap: kita nggunakake analyzeObject()
metode kanggo sinau kabeh sing bisa. Nanging iki ora kabeh sing bisa ditindakake kanthi refleksi. Kita ora diwatesi mung pengamatan prasaja - kita bakal nerusake kanggo njupuk tindakan! :)
Carane nggawe conto saka kelas kang jeneng kelas ora dikenal nganti program wis kaleksanan.
Ayo dadi miwiti karo konstruktor standar. Kelas kitaCat
durung duwe, mula ditambahake:
public Cat() {
}
Iki kode kanggo nggawe Cat
obyek nggunakake refleksi ( createCat()
metode):
import learn.codegym.Cat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static Cat createCat() throws IOException, IllegalAccessException, InstantiationException, ClassNotFoundException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String className = reader.readLine();
Class clazz = Class.forName(className);
Cat cat = (Cat) clazz.newInstance();
return cat;
}
public static Object createObject() throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String className = reader.readLine();
Class clazz = Class.forName(className);
Object result = clazz.newInstance();
return result;
}
public static void main(String[] args) throws IOException, IllegalAccessException, ClassNotFoundException, InstantiationException {
System.out.println(createCat());
}
}
Input konsol:
learn.codegym.Cat
Output konsol:
Cat{name='null', age=0}
Iki ora kesalahan: nilai name
lan age
ditampilake ing console amarga kita wrote kode kanggo output ing toString()
cara saka Cat
kelas. Ing kene kita maca jeneng kelas sing obyek bakal digawe saka console. Program kasebut ngenali jeneng kelas sing obyek bakal digawe. 
newInstance()
cara , kita nggawe obyek anyar saka kelas iki. Iku prakara liyane yen ingCat
konstruktor njupuk argumen minangka input. Ayo mbusak konstruktor standar kelas lan nyoba kanggo mbukak kode maneh.
null
java.lang.InstantiationException: learn.codegym.Cat
at java.lang.Class.newInstance(Class.java:427)
Ana sing salah! Kita entuk kesalahan amarga kita nelpon cara kanggo nggawe obyek nggunakake konstruktor standar. Nanging saiki kita ora duwe konstruktor kaya ngono. Dadi nalika newInstance()
metode kasebut mlaku, mekanisme refleksi nggunakake konstruktor lawas kita kanthi rong parameter:
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
Nanging kita ora nindakake apa-apa karo paramèter, kaya-kaya kita wis lali kabeh! Nggunakake refleksi kanggo ngirim argumen menyang konstruktor mbutuhake "kreativitas":
import learn.codegym.Cat;
import java.lang.reflect.InvocationTargetException;
public class Main {
public static Cat createCat() {
Class clazz = null;
Cat cat = null;
try {
clazz = Class.forName("learn.codegym.Cat");
Class[] catClassParams = {String.class, int.class};
cat = (Cat) clazz.getConstructor(catClassParams).newInstance("Fluffy", 6);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return cat;
}
public static void main(String[] args) {
System.out.println(createCat());
}
}
Output konsol:
Cat{name='Fluffy', age=6}
Ayo dideleng kanthi cetha apa sing kedadeyan ing program kita. Kita nggawe macem-macem Class
obyek.
Class[] catClassParams = {String.class, int.class};
Padha cocog karo paramèter konstruktor kita (sing mung duwe String
lan int
paramèter). We pass menyang clazz.getConstructor()
cara lan entuk akses menyang konstruktor dikarepake. Sawise iku, kabeh sing kudu kita lakoni yaiku nelpon newInstance()
metode kasebut kanthi argumen sing dibutuhake, lan aja lali masang obyek kasebut kanthi jelas menyang jinis sing dikarepake: Cat
.
cat = (Cat) clazz.getConstructor(catClassParams).newInstance("Fluffy", 6);
Saiki obyek kita wis kasil digawe! Output konsol:
Cat{name='Fluffy', age=6}
Langsung mlaku :)
Cara entuk lan nyetel nilai lapangan conto kanthi jeneng.
Bayangake yen sampeyan nggunakake kelas sing ditulis dening programmer liyane. Kajaba iku, sampeyan ora duwe kemampuan kanggo nyunting. Contone, perpustakaan kelas siap-digawe rangkep ing JAR a. Sampeyan bisa maca kode saka kelas, nanging sampeyan ora bisa ngganti. Upaminipun programmer sing nggawe salah siji saka kelas ing perpustakaan iki (ayo dadiCat
kelas lawas kita), gagal kanggo njaluk cukup turu ing wayah wengi sadurunge desain wis rampung, dibusak getter lan setter kanggo lapangan age
. Saiki kelas iki wis teka kanggo sampeyan. Iki nyukupi kabeh kabutuhan, amarga sampeyan mung butuh Cat
obyek ing program sampeyan. Nanging sampeyan kudu duwe age
lapangan! Iki masalah: kita ora bisa tekan lapangan, amarga wisprivate
modifier, lan getter lan setter dibusak dening pangembang turu sing nggawe kelas: / Inggih, bayangan bisa mbantu kita ing kahanan iki! Kita duwe akses menyang kode kanggo Cat
kelas, supaya kita bisa ngerti paling lapangan apa lan apa padha disebut. Bersenjata karo informasi iki, kita bisa ngatasi masalah kita:
import learn.codegym.Cat;
import java.lang.reflect.Field;
public class Main {
public static Cat createCat() {
Class clazz = null;
Cat cat = null;
try {
clazz = Class.forName("learn.codegym.Cat");
cat = (Cat) clazz.newInstance();
// We got lucky with the name field, since it has a setter
cat.setName("Fluffy");
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);
age.set(cat, 6);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return cat;
}
public static void main(String[] args) {
System.out.println(createCat());
}
}
Kaya sing kasebut ing komentar, kabeh sing ana ing name
lapangan iku gampang, amarga pangembang kelas nyedhiyakake setter. Sampeyan wis ngerti carane nggawe obyek saka konstruktor standar: kita duwe newInstance()
kanggo iki. Nanging kita kudu nindakake sawetara tinkering karo lapangan kapindho. Ayo ngerteni apa sing kedadeyan ing kene :)
Field age = clazz.getDeclaredField("age");
Ing kene, nggunakake Class clazz
obyek kita, kita ngakses age
lapangan liwat getDeclaredField()
metode kasebut. Ngidini kita entuk lapangan umur minangka Field age
obyek. Nanging iki ora cukup, amarga kita ora bisa mung menehi nilai menyang private
kolom. Kanggo nindakake iki, kita kudu nggawe lapangan bisa diakses kanthi nggunakake setAccessible()
metode:
age.setAccessible(true);
Sawise nindakake iki menyang lapangan, kita bisa nemtokake nilai:
age.set(cat, 6);
Nalika sampeyan bisa ndeleng, obyek kita Field age
duwe jinis setter nang-metu sing kita pass nilai int lan obyek kang lapangan bakal diutus. Kita mbukak main()
metode lan ndeleng:
Cat{name='Fluffy', age=6}
Banget! Kita nindakaken! :) Ayo ndeleng apa maneh sing bisa ditindakake ...
Cara nelpon metode conto kanthi jeneng.
Ayo rada ngganti kahanan ing conto sadurunge. Ayo ngomong yenCat
pangembang kelas ora nggawe kesalahan karo getter lan setter. Kabeh oke ing babagan iki. Saiki masalahe beda: ana cara sing mesthi dibutuhake, nanging pangembang nggawe pribadi:
private void sayMeow() {
System.out.println("Meow!");
}
Iki tegese yen kita nggawe Cat
obyek ing program kita, kita ora bakal bisa nelpon sayMeow()
cara ing wong. Kita bakal duwe kucing sing ora meow? Sing aneh : / Kepiye carane ndandani iki? Sawise maneh, API Refleksi mbantu kita! Kita ngerti jeneng metode sing dibutuhake. Kabeh liyane iku teknis:
import learn.codegym.Cat;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
public static void invokeSayMeowMethod() {
Class clazz = null;
Cat cat = null;
try {
cat = new Cat("Fluffy", 6);
clazz = Class.forName(Cat.class.getName());
Method sayMeow = clazz.getDeclaredMethod("sayMeow");
sayMeow.setAccessible(true);
sayMeow.invoke(cat);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
invokeSayMeowMethod();
}
}
Ing kene kita nindakake perkara sing padha karo sing ditindakake nalika ngakses lapangan pribadi. Kaping pisanan, kita entuk metode sing dibutuhake. Iku encapsulated ing Method
obyek:
Method sayMeow = clazz.getDeclaredMethod("sayMeow");
Cara kasebut getDeclaredMethod()
ngidini kita menyang metode pribadi. Sabanjure, kita nggawe cara sing bisa diarani:
sayMeow.setAccessible(true);
Lan pungkasane, kita nelpon metode ing obyek sing dikarepake:
sayMeow.invoke(cat);
Ing kene, telpon metode kita katon kaya "panggilan maneh": kita wis biasa nggunakake titik kanggo ngarahake obyek menyang metode sing dikarepake ( cat.sayMeow()
), nanging nalika nggarap refleksi, kita pindhah menyang metode obyek sing arep kita nelpon. metode kasebut. Apa sing ana ing konsol kita?
Meow!
Kabeh bisa! :) Saiki sampeyan bisa ndeleng kemungkinan akeh sing mekanisme bayangan Jawa menehi kita. Ing kahanan sing angel lan ora dikarepke (kayata conto kita karo kelas saka perpustakaan sing ditutup), pancen bisa mbantu kita akeh. Nanging, kaya kekuwatan gedhe, tanggung jawab kasebut uga gedhe. Kerugian refleksi diterangake ing bagean khusus ing situs web Oracle. Ana telung kekurangan utama:
-
Kinerja luwih elek. Metode sing diarani nggunakake refleksi nduweni kinerja sing luwih elek tinimbang metode sing diarani kanthi cara normal.
-
Ana watesan keamanan. Mekanisme refleksi ngidini kita ngganti prilaku program nalika runtime. Nanging ing papan kerja, nalika nggarap proyek nyata, sampeyan bisa ngadhepi watesan sing ora ngidini.
-
Risiko paparan informasi internal. Penting kanggo ngerti refleksi minangka pelanggaran langsung saka prinsip enkapsulasi: ngidini kita ngakses lapangan pribadi, metode, lan liya-liyane. mung ing kasus sing paling ekstrim, nalika ora ana cara liya kanggo ngatasi masalah kanthi alasan sing ora bisa dikontrol.
GO TO FULL VERSION