Pertanyaan Apa itu refleksi dan mengapa itu berguna?


Apa itu refleksi, dan mengapa itu berguna?

Saya sangat tertarik dengan Java, tetapi saya menganggap prinsipnya sama dalam bahasa apa pun.


1690
2017-09-01 08:39


asal


Jawaban:


Refleksi nama digunakan untuk menggambarkan kode yang mampu memeriksa kode lain dalam sistem yang sama (atau dirinya sendiri).

Misalnya, Anda memiliki objek dari jenis yang tidak dikenal di Java, dan Anda ingin memanggil metode 'doSomething' di dalamnya jika ada. Sistem pengetikan statis Java tidak benar-benar dirancang untuk mendukung ini kecuali objek sesuai dengan antarmuka yang dikenal, tetapi menggunakan refleksi, kode Anda dapat melihat objek dan mencari tahu apakah ia memiliki metode yang disebut 'doSomething' dan kemudian memanggilnya jika Anda ingin.

Jadi, untuk memberi Anda contoh kode ini di Java (bayangkan objek yang dimaksud adalah foo):

Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);

Satu kasus penggunaan yang sangat umum di Java adalah penggunaan dengan anotasi. JUnit 4, misalnya, akan menggunakan refleksi untuk melihat melalui kelas Anda untuk metode yang ditandai dengan anotasi @Test, dan kemudian akan memanggilnya ketika menjalankan tes unit.

Ada beberapa contoh refleksi yang bagus untuk Anda mulai http://docs.oracle.com/javase/tutorial/reflect/index.html

Dan akhirnya, ya, konsepnya cukup mirip dalam bahasa tipe statis lainnya yang mendukung refleksi (seperti C #). Dalam bahasa yang diketik secara dinamis, use case yang dideskripsikan di atas kurang diperlukan (karena compiler akan mengijinkan metode apa pun untuk dipanggil pada objek apa pun, gagal saat runtime jika tidak ada), tetapi kasus kedua mencari metode yang ditandai atau bekerja dengan cara tertentu masih umum.

Pembaruan dari komentar:

Kemampuan untuk memeriksa kode dalam sistem dan melihat jenis objek   bukan refleksi, melainkan Tipe Introspeksi. Refleksi inilah yang kemudian   kemampuan untuk membuat modifikasi pada saat runtime dengan memanfaatkan   introspeksi. Perbedaannya diperlukan di sini sebagai beberapa bahasa   mendukung introspeksi, tetapi tidak mendukung refleksi. Salah satu contohnya   adalah C ++


1414
2017-09-01 08:44



Refleksi adalah kemampuan bahasa untuk memeriksa dan secara dinamis memanggil kelas, metode, atribut, dll. pada waktu proses.

Misalnya, semua objek di Jawa memiliki metode getClass(), yang memungkinkan Anda menentukan kelas objek bahkan jika Anda tidak mengetahuinya pada waktu kompilasi (misalnya jika Anda menyatakannya sebagai Object) - ini mungkin tampak sepele, tetapi refleksi semacam itu tidak mungkin dalam bahasa yang kurang dinamis seperti C++. Penggunaan lebih lanjut memungkinkan Anda mencantumkan dan memanggil metode, konstruktor, dll.

Refleksi penting karena memungkinkan Anda menulis program yang tidak harus "mengetahui" semuanya pada waktu kompilasi, membuatnya lebih dinamis, karena dapat diikat bersamaan saat runtime. Kode dapat ditulis terhadap antarmuka yang dikenal, tetapi kelas yang sebenarnya untuk digunakan dapat dipakai menggunakan refleksi dari file konfigurasi.

Banyak kerangka modern menggunakan refleksi secara ekstensif untuk alasan ini. Sebagian besar bahasa modern lainnya juga menggunakan refleksi, dan dalam bahasa scripting (seperti Python) mereka bahkan lebih terintegrasi secara erat, karena terasa lebih alami dalam model pemrograman umum dari bahasa-bahasa tersebut.


195
2017-09-01 08:52



Salah satu kegunaan refleksi favorit saya adalah metode dump Jawa di bawah ini. Dibutuhkan objek apa pun sebagai parameter dan menggunakan Java reflection API mencetak setiap nama dan nilai bidang.

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public static String dump(Object o, int callCount) {
    callCount++;
    StringBuffer tabs = new StringBuffer();
    for (int k = 0; k < callCount; k++) {
        tabs.append("\t");
    }
    StringBuffer buffer = new StringBuffer();
    Class oClass = o.getClass();
    if (oClass.isArray()) {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("[");
        for (int i = 0; i < Array.getLength(o); i++) {
            if (i < 0)
                buffer.append(",");
            Object value = Array.get(o, i);
            if (value.getClass().isPrimitive() ||
                    value.getClass() == java.lang.Long.class ||
                    value.getClass() == java.lang.String.class ||
                    value.getClass() == java.lang.Integer.class ||
                    value.getClass() == java.lang.Boolean.class
                    ) {
                buffer.append(value);
            } else {
                buffer.append(dump(value, callCount));
            }
        }
        buffer.append(tabs.toString());
        buffer.append("]\n");
    } else {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("{\n");
        while (oClass != null) {
            Field[] fields = oClass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                buffer.append(tabs.toString());
                fields[i].setAccessible(true);
                buffer.append(fields[i].getName());
                buffer.append("=");
                try {
                    Object value = fields[i].get(o);
                    if (value != null) {
                        if (value.getClass().isPrimitive() ||
                                value.getClass() == java.lang.Long.class ||
                                value.getClass() == java.lang.String.class ||
                                value.getClass() == java.lang.Integer.class ||
                                value.getClass() == java.lang.Boolean.class
                                ) {
                            buffer.append(value);
                        } else {
                            buffer.append(dump(value, callCount));
                        }
                    }
                } catch (IllegalAccessException e) {
                    buffer.append(e.getMessage());
                }
                buffer.append("\n");
            }
            oClass = oClass.getSuperclass();
        }
        buffer.append(tabs.toString());
        buffer.append("}\n");
    }
    return buffer.toString();
}

84
2017-09-02 16:15



Penggunaan Refleksi

Refleksi umumnya digunakan oleh program yang membutuhkan kemampuan untuk memeriksa atau memodifikasi perilaku runtime dari aplikasi yang berjalan di mesin virtual Java. Ini adalah fitur yang relatif maju dan harus digunakan hanya oleh pengembang yang memiliki pemahaman yang kuat tentang dasar-dasar bahasa. Dengan mengingat itu, refleksi adalah teknik yang kuat dan dapat memungkinkan aplikasi untuk melakukan operasi yang tidak mungkin dilakukan.

Fitur Ekstensibilitas

Aplikasi dapat memanfaatkan kelas-kelas eksternal yang ditentukan oleh pengguna dengan membuat contoh-contoh objek ekstensibilitas menggunakan nama-nama mereka yang memenuhi syarat sepenuhnya. Browser Kelas dan Lingkungan Pengembangan Visual Browser kelas harus dapat menyebutkan anggota kelas. Lingkungan pengembangan visual dapat mengambil manfaat dari penggunaan jenis informasi yang tersedia dalam refleksi untuk membantu pengembang dalam menulis kode yang benar. Debugger dan Alat Uji Para debugger harus bisa memeriksa anggota pribadi di kelas. Alat uji dapat menggunakan refleksi untuk secara sistematis memanggil API set yang dapat ditemukan yang ditentukan di kelas, untuk memastikan cakupan kode tingkat tinggi dalam rangkaian uji.

Kelemahan dari Refleksi

Refleksi sangat kuat, tetapi tidak boleh digunakan tanpa pandang bulu. Jika mungkin untuk melakukan operasi tanpa menggunakan refleksi, maka lebih baik untuk menghindari menggunakannya. Kekhawatiran berikut harus diingat ketika mengakses kode melalui refleksi.

  • Overhead Kinerja

Karena refleksi melibatkan jenis yang diselesaikan secara dinamis, optimisasi mesin virtual Java tertentu tidak dapat dilakukan. Akibatnya, operasi reflektif memiliki kinerja lebih lambat daripada rekan-rekan non-reflektif dan harus dihindari dalam bagian kode yang sering disebut dalam aplikasi yang peka terhadap kinerja.

  • Pembatasan Keamanan

Refleksi membutuhkan izin runtime yang mungkin tidak ada ketika berjalan di bawah manajer keamanan. Ini merupakan pertimbangan penting untuk kode yang harus dijalankan dalam konteks keamanan yang terbatas, seperti di Applet.

  • Paparan Internal

Karena refleksi memungkinkan kode untuk melakukan operasi yang ilegal dalam kode non-reflektif, seperti mengakses bidang dan metode pribadi, penggunaan refleksi dapat mengakibatkan efek samping yang tidak diharapkan, yang dapat membuat kode tidak berfungsi dan dapat merusak portabilitas. Kode reflektif memecah abstraksi dan karena itu dapat mengubah perilaku dengan peningkatan platform.

sumber: API Refleksi


55
2017-10-17 11:59



Refleksi adalah mekanisme kunci untuk memungkinkan aplikasi atau kerangka kerja untuk bekerja dengan kode yang mungkin belum pernah ditulis!

Ambil contoh file web.xml khas Anda. Ini akan berisi daftar elemen servlet, yang berisi elemen kelas servlet bertingkat. Wadah servlet akan memproses file web.xml, dan membuat baru contoh baru dari setiap kelas servlet melalui refleksi.

Contoh lain adalah Java API for XML Parsing (JAXP). Di mana penyedia parser XML 'terpasang' melalui properti sistem yang terkenal, yang digunakan untuk membangun instance baru melalui refleksi.

Dan akhirnya, contoh yang paling komprehensif adalah Musim semi yang menggunakan refleksi untuk menciptakan kacangnya, dan untuk penggunaan proxy yang berat


30
2017-09-01 09:30



Tidak semua bahasa mendukung refleksi tetapi prinsipnya biasanya sama dalam bahasa yang mendukungnya.

Refleksi adalah kemampuan untuk "mencerminkan" pada struktur program Anda. Atau lebih konkret. Untuk melihat objek dan kelas yang Anda miliki dan secara terprogram mendapatkan kembali informasi tentang metode, bidang, dan antarmuka yang mereka terapkan. Anda juga dapat melihat hal-hal seperti anotasi.

Ini berguna dalam banyak situasi. Di mana pun Anda ingin dapat secara dinamis memasukkan kelas ke dalam kode Anda. Banyak objek pemetaan relasional menggunakan refleksi untuk dapat instantiate objek dari database tanpa mengetahui terlebih dahulu objek apa yang akan mereka gunakan. Arsitektur plug-in adalah tempat lain di mana refleksi berguna. Mampu secara dinamis memuat kode dan menentukan apakah ada tipe di sana yang mengimplementasikan antarmuka yang tepat untuk digunakan sebagai plugin penting dalam situasi tersebut.


27
2017-09-01 08:50



Refleksi memungkinkan instantiasi objek baru, meminta metode, dan menjalankan / mengatur operasi pada variabel kelas secara dinamis pada waktu berjalan tanpa memiliki pengetahuan sebelumnya tentang implementasinya.

Class myObjectClass = MyObject.class;
Method[] method = myObjectClass.getMethods();

//Here the method takes a string parameter if there is no param, put null.
Method method = aClass.getMethod("method_name", String.class); 

Object returnValue = method.invoke(null, "parameter-value1");

Di contoh di atas, parameter nol adalah objek yang Anda inginkan untuk mengaktifkan metode. Jika metode statis Anda berikan nol. Jika metode tidak statis, maka saat memohon Anda perlu menyediakan contoh MyObject yang valid, bukan null.

Refleksi juga memungkinkan Anda untuk mengakses anggota / metode pribadi suatu kelas:

public class A{

  private String str= null;

  public A(String str) {
  this.str= str;
  }
}

.

A obj= new A("Some value");

Field privateStringField = A.class.getDeclaredField("privateString");

//Turn off access check for this field
privateStringField.setAccessible(true);

String fieldValue = (String) privateStringField.get(obj);
System.out.println("fieldValue = " + fieldValue);
  • Untuk pemeriksaan kelas (juga dikenal sebagai introspeksi) Anda tidak perlu mengimpor paket refleksi (java.lang.reflect). Metadata kelas dapat diakses melalui java.lang.Class.

Refleksi adalah API yang sangat kuat tetapi dapat memperlambat aplikasi jika digunakan secara berlebihan, karena menyelesaikan semua jenis saat runtime.


26
2017-07-08 16:12