kelas java.lang.reflect.Field

Kelas Field menyediakan informasi tentang dan akses dinamis ke satu bidang kelas atau antarmuka. Field juga memungkinkan konversi tipe pelebaran selama operasi akses get atau set, tetapi melontarkan IllegalArgumentException jika penyempitan akan terjadi.

Untuk mendapatkan objek Field , pertama-tama kita akan menulis kelas:


public class Person {
    private String name;
    private int age;
    
    public boolean isMale;
    
    protected String address;
    
    public static final int MAX_AGE = 120;
    public static final int MIN_AGE = 0;
}

Dan inilah kode kami untuk bekerja dengan kelas itu:


public class Main {
    public static void main(String[] args) {
        Field[] fields = Person.class.getDeclaredFields();
        List<Field> actualFields = getFieldNames(fields);
        System.out.println(actualFields);
    }

    static List<Field> getFieldNames(Field[] fields) {
        return List.of(fields);
    }
}

Beginilah cara kami mendapatkan daftar bidang kelas kami, yang akan kami kerjakan nanti. Inilah hasilnya:

[java.lang.String pribadi com.company.Person.name, com.company.Person.age int pribadi, com.company.Person.isMale boolean publik, dilindungi java.lang.String com.company.Person.address, publik static final int com.company.Person.MAX_AGE, public static final int com.company.Person.MIN_AGE]

Sekarang mari kita cari tahu apa yang bisa kita lakukan dengan data ini. Mari kita bicara tentang metode kelas Field :

metode Keterangan
getType() Mengembalikan objek Kelas yang mengidentifikasi jenis bidang yang dideklarasikan yang diwakili oleh iniBidangobyek.
getAnnotatedType() Mengembalikan sebuahJenis Beranotasiobjek yang mewakili penggunaan tipe untuk menentukan tipe yang dideklarasikan dari bidang yang diwakili oleh Bidang ini.
getGenericType() pengembalian aJenisobjek yang mewakili jenis bidang yang dideklarasikan yang diwakili oleh iniBidangobyek.
getName() Mengembalikan nama bidang yang diwakili oleh iniBidangobyek.
getModifiers() Mengembalikan pengkodean int pengubah bahasa Java untuk bidang yang diwakili oleh iniBidangobyek.
getAnnotations() Mengembalikan anotasi untuk bidang ini. Jika tidak ada anotasi, ia mengembalikan larik kosong.

metode getType(), getName(), dan getModifiers()

Kita bisa menggunakan metode getType() untuk mendapatkan tipe bidang kita. Mari kita menulis sebuah metode:


static void printTypes(List<Field> fields){
      fields.forEach(e -> System.out.println(e.getType()));
  }

Dan kami mendapatkan hasil ini:

kelas java.lang.String
int
boolean
kelas java.lang.String
int
int

Sekarang mari tambahkan metode ke kelas kita untuk mendapatkan nama bidang. Ini akan memudahkan navigasi bidang kelas kita.


static void printTypesAndNames(List<Field> fields){
   fields.forEach(e -> System.out.printf("Field type - %s\nField name - %s\n\n", e.getType(), e.getName()));
}

Sekarang hasilnya lebih bisa dimengerti:

Jenis bidang - kelas java.lang.String
Nama bidang - nama

Jenis bidang - int
Nama bidang - umur

Jenis bidang - boolean
Nama bidang - isMale

Jenis bidang - kelas java.lang.String
Nama bidang - alamat

Jenis bidang - int
Nama bidang - MAX_AGE

Jenis bidang - int
Nama bidang - MIN_AGE

Besar! Mari ubah metode kita lagi! Kami akan menambahkan pengubah akses di sini


static void printFieldInfo(List<Field> fields){
   fields.forEach(e -> System.out.printf("Field type - %s\nField name - %s\nModifiers - %s\n\n", e.getType(), e.getName(), Modifier.toString(e.getModifiers())));
}

Dan mari kita lihat apa yang dikembalikan oleh e.getModifiers() . Metode ini mengembalikan int yang memungkinkan kita menentukan status pengubah akses bidang kita. Kelas Pengubah berisi variabel statis yang bertanggung jawab untuk setiap pengubah bidang tertentu.

Mari bungkus nilai pengembalian kita di Modifier.toString() dan segera dapatkan nilainya sebagai teks:

Jenis bidang - kelas java.lang.String
Nama bidang -
pengubah nama - pribadi

Jenis bidang - int
Nama bidang -
pengubah usia - pribadi

Jenis bidang - boolean
Nama bidang -
Pengubah isMale - publik

Jenis bidang - kelas java.lang.String
Nama bidang - pengubah alamat
-

tipe bidang yang dilindungi -
nama bidang int -
pengubah MAX_AGE - akhir statis publik

Jenis bidang - nama bidang int - pengubah
MIN_AGE - akhir statis publik

Inilah tampilannya tanpa Modifier.toString() :

Jenis bidang - kelas java.lang.String
Nama bidang -
Pengubah nama - 2

Jenis bidang - int
Nama bidang -
Pengubah usia - 2

Jenis bidang - boolean
Nama bidang -
Pengubah isMale - 1

Jenis bidang - kelas java.lang.String
Nama bidang - Pengubah alamat
- 4

Jenis bidang - int
Nama bidang -
Pengubah MAX_AGE - 25

Jenis bidang - int
Nama bidang -
Pengubah MIN_AGE - 25

metode getAnnotations(), getAnnotatedType(), dan getGenericType()

Mari kita modifikasi kelas Person untuk bekerja dengan metode ini. Kami akan menulis anotasi kami sendiri dan menerapkannya ke bidang kami. Dan kami akan menambahkan beberapa bidang lagi.

Mari buat dua anotasi. Kami akan meneruskan nama variabel dalam Pig Latin ke satu, dan kami akan menggunakan yang kedua untuk elemen:


@Target(value=ElementType.FIELD)
@Retention(value= RetentionPolicy.RUNTIME)
public @interface Name {
    String name();
}

@Target({ ElementType.TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Number {
}

Dan kami akan mengubah kelas utama kami dan kelas Person :


public class Person {
    @Name(name = "Ame-nay")
    private String name;

    @Name(name = "User nicknames")
    List<String> nicknames;

    private final Class<Object> type;

    private int @Number[] number;

    public Person(Class<Object> type) {
        this.type = type;
    }
}

public static void main(String[] args) {
    Field[] fields = Person.class.getDeclaredFields();
    List<Field> actualFields = getFieldNames(fields);
    
    printAdditionalInfo(actualFields);
}

static void printAdditionalInfo(List<Field> fields) {
   System.out.println("\ngetAnnotatedType:");
   fields.forEach(e -> System.out.println(e.getAnnotatedType()));

   System.out.println("\ngetGenericType:");
   fields.forEach(e -> System.out.println(e.getGenericType()));

   System.out.println("\ngetAnnotations:");
   fields.forEach(e -> System.out.println(Arrays.toString(e.getAnnotations())));
}

Saatnya untuk melihat hasil dari metode kami dan mencari tahu untuk apa metode itu:

getAnnotatedType:
java.lang.Class<java.lang.Object>
java.util.List<java.lang.String>
java.lang.String
int @Number()[]

getGenericType:
java.lang.Class<java.lang. Objek>
java.util.List<java.lang.String>
kelas java.lang.String
kelas [Saya

getAnnotations:
[]
[@Nama(nama="\u0055\u0073\u0065\u0072\u0020\u006e\u0069\u0063 \u006b\u006e\u0061\u006d\u0065\u0073")]
[@Nama(nama="\u0041\u006d\u0065\u002d\u006e\u0061\u0079")] [
]
  • getAnnotatedType mengembalikan anotasi untuk bidang tertentu, jika ada. Kami mendapatkan anotasi untuk bidang tersebut dan kami dapat melihatnya dengan sempurna.

  • getGenericType memungkinkan Anda menampilkan tipe parameter dengan benar.

  • getAnnotations mengembalikan anotasi yang diterapkan ke objek kita.

Ini adalah cara kami dapat dengan mudah mendapatkan semua data tentang setiap bidang di kelas kami, serta pengubah akses, anotasi, dan tipe datanya.

kelas java.lang.reflect.Method

Super! Kami telah berbicara tentang bidang kelas kami. Sekarang saatnya berbicara tentang metode.

Untuk mendapatkan objek Metode , kami memanggil metode getMethod , meneruskannya dengan nama metode kami. Ini adalah cara dasar untuk mendapatkan objek Metode :


Method getNameMethod =  Person.class.getMethod("getName");

Kami akan terus bekerja dengan kelas kami. Mari tambahkan getter dan setter, dan metode hashCode, equals dan toString :


public class Person {
    private String name;
    private int age;

    public boolean isMale;

    protected String address;

    public static final int MAX_AGE = 120;
    public static final int MIN_AGE = 0;

    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;
    }

    public boolean isMale() {
        return isMale;
    }

    public void setMale(boolean male) {
        isMale = male;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", isMale=" + isMale +
                ", address='" + address + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && isMale == person.isMale && Objects.equals(name, person.name) && Objects.equals(address, person.address);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, isMale, address);
    }
}

Sekarang mari siapkan satu set metode yang akan kita periksa menggunakan kelas Metode . Berikut adalah daftar metode yang paling penting:

metode Keterangan
getName() Mengembalikan nama metode.
getModifiers() Mengembalikan pengubah akses dari metode ini.
getReturnType() Mengembalikan tipe kembalian dari metode.
getGenericReturnType() Mengembalikan jenis pengembalian metode, memperhitungkan metode generik.
getParameterTypes() Mengembalikan array parameter metode.
getGenericParameterTypes() Mengembalikan array parameter metode, memperhitungkan metode generik.
getExceptionTypes() Mengembalikan pengecualian yang dapat dilontarkan oleh metode.
getGenericExceptionTypes() Mengembalikan pengecualian yang dapat dilontarkan oleh metode, memperhitungkan tipe berparameter.
getAnnotations() Mengembalikan anotasi untuk metode, termasuk anotasi induk.
getDeclaredAnnotations() Mengembalikan anotasi untuk metode, tidak termasuk anotasi induk.

Untuk mendapatkan array dari metode class kita, kita dapat memanggil metode ini:


Method[] methods = Person.class.getDeclaredMethods();

Ini akan memberi kita semua metode di kelas kita.

metode getName() dan getModifiers()

Kita dapat menggunakan getName untuk mendapatkan nama dari setiap metode:


static List<String> getMethodsName(Method[] methods) {
    return Arrays.asList(methods)
            .stream()
            .map(Method::getName)
            .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}

Sekarang untuk mendapatkan pengubah, mari tulis metode yang menggunakan getModifiers :


static List<String> getModifiers(Method[] methods) {
    return Arrays
            .stream(methods)
            .map(Method::getModifiers)
            .map(String::valueOf)
            .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}

Inilah metode utama kami :


public static void main(String[] args) {
    Method[] methods = Person.class.getDeclaredMethods();

    System.out.println(getMethodsName(methods));
    System.out.println(getModifiers(methods));
}

Hasil kami:

[getName, sama dengan, toString, kode hash, setName, getAddress, isMale, getAge, setAge, setMale, setAddress]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

Semua metode kami memiliki pengubah publik , jadi metode terakhir mengembalikan array satu. Jika kami memodifikasi kode kami, kami akan melihat pengubah kami sendiri:


public static void main(String[] args) {
    Method[] methods = Person.class.getDeclaredMethods();

    System.out.println(getMethodsName(methods));
    System.out.println(modifyModifiers(getModifiers(methods)));
}
[getName, sama dengan, toString, kode hash, setName, getAddress, isMale, getAge, setAge, setMale, setAddress] [publik, publik, publik, publik, publik, publik, publik, publik, publik,
publik, publik]

getReturnedType()

Metode ini memungkinkan kita mendapatkan tipe kembalian dari metode ini:


static void getReturnedType(Method[] methods) {
    Arrays.stream(methods)
            .map(Method::getReturnType)
            .forEach(System.out::println);
}
kelas java.lang.String
boolean
kelas java.lang.String
int
batal
kelas java.lang.String
boolean
int
batal
batal
batal

getGenericReturnType()

Mari berikan kelas Person kita sebuah metode yang mengembalikan tipe yang terbungkus dalam tipe berparameter, dan mencoba untuk mendapatkan nilai pengembaliannya:


public List<String> someMethod() {
    // Very useful and important method
    return null;
}

Dan kami akan memperbarui metode utama kami:


static void getGenericReturnType(Method[] methods) {
    Arrays.stream(methods)
            .map(Method::getGenericReturnType)
            .forEach(System.out::println);
}

Hasil dari metode kami:

kelas java.lang.String
boolean
kelas java.lang.String
int
batal
kelas java.lang.String
boolean
int
batal
batal
batal
java.util.List<java.lang.String>

metode getParameterTypes() dan getGenericParameterTypes()

Kami terus memodifikasi kelas Person kami , menambahkan dua metode lagi:


public List<String> someMethod(List<String> list, String s) {
    // Very useful and important method
    return null;
}

Yang pertama akan membiarkan kita mendapatkan parameter dari metode kita, dan yang kedua akan memberi kita tipe parameter juga.


static void getParameterTypes(Method[] methods) {
    Class<?>[] types = method.getParameterTypes();
        for (Class<?> type : types) {
            System.out.println(type);
        }
}

static void getGenericParameterTypes(Method[] methods) {
   Type[] types = method.getGenericParameterTypes();
        for (Type type : types) {
            System.out.println(type);
        }
}

Kami hanya akan mengakses salah satu metode kami. Untuk mengakses metode dengan nama tertentu, kami memanggil getMethod dan meneruskan nama dan parameter metode yang kami inginkan:


public static void main(String[] args) throws NoSuchMethodException {
    Method currentMethod = Person.class.getMethod("someMethod", List.class, String.class);

    getParameterTypes(currentMethod);
    System.out.println();
    getGenericParameterTypes(currentMethod);
}

Menjalankan kode kita, kita akan melihat perbedaan metode dan apa yang dikembalikannya:

antarmuka
kelas java.util.List java.lang.String

java.util.List<java.lang.String>
kelas java.lang.String

metode getExceptionTypes() dan getGenericExceptionTypes()

Kita dapat menggunakan metode ini untuk mendapatkan array pengecualian yang dapat dilontarkan oleh metode kita, serta pengecualian dengan tipe berparameter (jika ada). Mari gunakan contoh baru yang memiliki kelas statis tersembunyi:


private static class Processor {
    private void init() {}

    private void process() throws IOException {}
}

Dan kami akan memanggil metode di kelas Prosesor kami :


public static void main(String... args) throws NoSuchMethodException {
    Method method = Processor.class.getDeclaredMethod("process");
    Type[] type = method.getExceptionTypes();
    System.out.println(Arrays.toString(type));
}

Sekarang kita bisa melihat pengecualian kita:

[kelas java.io.IOException]

Sekarang mari parameterkan jenisnya. Kami akan memodifikasi kelas utama kami:


private static class Processor<E extends IOException> {

    private void process() throws E {
    }
}

Dan kode dari metode utama :


public static void main(String... args) throws NoSuchMethodException {
    Method m = Processor.class.getDeclaredMethod("process");
    Type[] t = m.getGenericExceptionTypes();
    System.out.println(Arrays.toString(t));

    for (Type type : t) {
        if (type instanceof TypeVariable) {
            for (Type type1 : ((TypeVariable) type).getBounds()) {
                System.out.println(type1);
            }
        }
    }
}

Di dalam metode ini, kami mendapatkan objek TypeVariables , yang merupakan antarmuka induk generik untuk variabel tipe. Dan di dalamnya, kita sekarang bisa mendapatkan parameter internal, yaitu pengecualian bersarang kita:

[E]
kelas java.io.IOException

metode getAnnotations() dan getDeclaredAnnotations()

Mari lanjutkan menggunakan kelas baru ini dan tambahkan beberapa anotasi ke dalamnya. Kami akan membuat anotasi Anotasi kami sendiri :


@Retention(RetentionPolicy.RUNTIME)
@interface Annotation {

    public String key();
    public String value();
}

Dan menerapkannya ke metode kami:


@Annotation(key = "key", value = "value")
private void process() throws E{

}

Dan tentu saja kami akan menambahkan metode untuk menampilkan semua anotasi kami:


static void getMethodAnnotations(Class<?> clazz) {
    Method[] methods = clazz.getDeclaredMethods();
    for (Method method : methods) {
        System.out.println(method.getName());
        System.out.println(Arrays.toString(method.getAnnotations()));
        System.out.println();
    }
}

Implementasi metode utama kami :


public static void main(String... args) {
    Class clazz = Processor.class;
    getMethodAnnotations(clazz);
}

Output layar yang dihasilkan adalah:

proses
[@com.company.Main&Annotation(key="key", value="value")]

Ini adalah bagaimana kita bisa mendapatkan anotasi yang telah diterapkan pada metode kita, dan metode getAnnotations juga memungkinkan kita mengakses anotasi induk kelas.

Hari ini kami berkenalan dengan bagaimana refleksi dapat bekerja dengan metode dan bidang, dan data apa yang dapat kami peroleh darinya!