java.lang.reflect.Field klassi
Field klassi o'z ichida klass yoki interfeysning bitta maydoni haqida ma'lumot va dinamik kirishni taqdim etadi. Field ham kengaytirilgan o'zgarishlarga ruxsat beradi, lekin IllegalArgumentException istisnosini chiqaradi, agar o'zgarish toraytirilsa.
Filed klassini olish uchun, biz foydalanmoqchi bo'lgan klassni va uning ishlov beruvchisini yozamiz:
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;
}
Va ishlov beruvchining o'zi:
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);
}
}
Shunday qilib, biz klassimizning maydonlar ro'yxatini olamiz, bu bilan kelajakda ishlaymiz. Natija quyidagicha ko'rinadi:
Endi biz ushbu ma'lumotlar to'plami bilan nima qilishi mumkinligimizni ko'rib chiqamiz. Field klassining metodlari haqida gaplashamiz:
| Metod | Tavsif |
|---|---|
| getType() | Bu obyekt Field tomonidan ifodalangan deklaratsiyalangan maydonning tipini aniqlovchi klass obyektini qaytaradi. |
| getAnnotatedType() | Bu maydon tomonidan ifodalangan maydonning deklaratsiyalangan tipini belgilash uchun foydalaniladigan tipni ifodalaydigan AnnotatedType obyektini qaytaradi. |
| getGenericType() | Bu obyekt Field tomonidan ifodalangan deklaratsiyalangan maydonning tipini ifodalaydigan Type obyektini qaytaradi. |
| getName() | Bu obyekt Field tomonidan ifodalangan maydon nomini qaytaradi. |
| getModifiers() | Bu obyekt Field tomonidan ifodalangan maydon uchun Java tilidagi modifikatorlarni butun son sifatida qaytaradi. |
| getAnnotations() | Bu maydonning annotatsiyalarini qaytaradi. Agar annotatsiyalar yo'q bo'lsa - bo'sh massiv. |
getType(), getName(), getModifiers() metodlari
getType() metodi yordamida biz o'zimizning maydonimizning turini olishimiz mumkin. Metod yozamiz:
static void printTypes(List<Field> fields){
fields.forEach(e -> System.out.println(e.getType()));
}
Va natijani quyidagicha olamiz:
int
boolean
class java.lang.String
int
int
Va darhol klassimizda maydon nomini olish uchun metod qo'shamiz. Shunda biz klassimiz maydonlariga ko'proq yo'naltirilgan bo'lamiz.
static void printTypesAndNames(List<Field> fields){
fields.forEach(e -> System.out.printf("Field type - %s\nField name - %s\n\n", e.getType(), e.getName()));
}
Foydalanuvchi uchun tushunarliroq bo'lgan natijani olamiz:
Field name - name
Field type - int
Field name - age
Field type - boolean
Field name - isMale
Field type - class java.lang.String
Field name - address
Field type - int
Field name - MAX_AGE
Field type - int
Field name - MIN_AGE
Ajoyib, keling, metodimizni yana modifikatsiya qilamiz! Bu yerga kirish modifikatorlarini qo'shamiz:
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())));
}
Va e.getModifiers() nima qaytarishini tahlil qilamiz. Bu metod modifikatorlarni aniqlash uchun ichida o'z ichiga oladigan butun int sonni qaytaradi. Modifier klassida maydonning ma'lum modifikatori uchun javob beradigan statik o'zgaruvchilar mavjud.
Bizning qaytariladigan qiymatimizni Мodifier.toString() bilan o'rab olamiz — va darhol matnli ko'rinishda qiymatni olamiz:
Field name - name
Modifiers - private
Field type - int
Field name - age
Modifiers - private
Field type - boolean
Field name - isMale
Modifiers - public
Field type - class java.lang.String
Field name - address
Modifiers - protected
Field type - int
Field name - MAX_AGE
Modifiers - public static final
Field type - int
Field name - MIN_AGE
Modifiers - public static final
Va bu qanday ko'rinishga ega Мodifier.toString() holda:
Field name - name
Modifiers - 2
Field type - int
Field name - age
Modifiers - 2
Field type - boolean
Field name - isMale
Modifiers - 1
Field type - class java.lang.String
Field name - address
Modifiers - 4
Field type - int
Field name - MAX_AGE
Modifiers - 25
Field type - int
Field name - MIN_AGE
Modifiers - 25
getAnnotations(), getAnnotatedType(), getGenericType() metodlari
Dasturimizni mavjud metodlar bilan ishlash uchun modifikatsiya qilaylik. Biz o'z annotationimizni yozamiz, uni maydonlarimizga qo'shamiz va yana bir nechta maydon qo'shamiz.
Ikki annotation yaratamiz. Biriga o'zgaruvchining nomini rus tilida uzatamiz, ikkinchi annotation elementlar uchun ishlatiladi:
@Target(value=ElementType.FIELD)
@Retention(value= RetentionPolicy.RUNTIME)
public @interface Name {
String name();
}
@Target({ ElementType.TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Number {
}
Asosiy klassimiz va Person klassini o'zgartiramiz:
public class Person {
@Name(name = "Имя")
private String name;
@Name(name = "Никнэймы пользователя")
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())));
}
Metod natijalarini tekshirish va ularning maqsadini yana bir bor ko'rib chiqish vaqti keldi:
java.lang.Class<java.lang.Object>
java.util.List<java.lang.String>
java.lang.String
int @Number()[]
getGenericType:
java.lang.Class<java.lang.Object>
java.util.List<java.lang.String>
class java.lang.String
class [I
getAnnotations:
[]
[@Name(name="\u041d\u0438\u043a\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f")]
[@Name(name="\u0418\u043c\u044f")]
[]
getAnnotatedType agar mavjud bo'lsa, ushbu maydon uchun annotationni qaytaradi. Bizda maydon uchun annotation bor va biz uni ko'rib turibmiz.
getGenericType jeneralizatsiyalangan parametrlarni to'g'ri ko'rsatadi.
getAnnotations obyekt ustida turgan annotationlarni qaytaradi.
Shunday qilib, biz klassimizdagi har bir maydon haqida, uning kirish modifikatorlari, annotationlar va ma'lumotlar turlari haqida barcha ma'lumotlarni osonlik bilan olamiz.
java.lang.reflect.Method klassi
Zo'r, biz klassimizning maydonlari haqida gaplashdik, endi metodlar haqida gaplashadigan vaqt keldi.
Method klassi obyektini olish uchun biz getMethod chaqiramiz va metod nomini unga uzatamiz. Bu Method klassi olish uchun asosiy usul:
Method getNameMethod = Person.class.getMethod("getName");
Dasturimiz bilan ishlashni davom ettiramiz. Getter va setterlar, hash code, equals va toString qo'shamiz:
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);
}
}
Endi, Method klassida ko'rmoqchi bo'lgan metodlar to'plamini tayyorlaymiz. Mana asosiy metodlar ro'yxati:
| Metod | Tavsif |
|---|---|
| getName() | Metod nomini qaytaradi. |
| getModifiers() | Ushbu metodning kirish modifikatorini qaytaradi. |
| getReturnType() | Metodning qaytariladigan turini qaytaradi. |
| getGenericReturnType() | Jeneralizatsiyalangan metodlarni hisobga olgan holda metodning qaytariladigan turini qaytaradi. |
| getParameterTypes() | Metod parametrlarining massivini qaytaradi. |
| getGenericParameterTypes() | Jeneralizatsiyalangan metodlarni hisobga olgan holda metod parametrlarining massivini qaytaradi. |
| getExceptionTypes() | Metod chiqarishi mumkin bo'lgan istisnolarni qaytaradi. |
| getGenericExceptionTypes() | Jeneralizatsiyalangan parametrlarni hisobga olgan holda metod chiqarishi mumkin bo'lgan istisnolarni qaytaradi. |
| getAnnotations() | Metod uchun, shu jumladan ota-annotationlarni, annotationlar qaytaradi. |
| getDeclaredAnnotations() | Metod uchun, ota-annotationlarni hisobga olmasdan, annotationlar qaytaradi. |
Klassimiz qaytaradigan metodlar massivini olish uchun biz quyidagi metodni chaqiramiz:
Method[] methods = Person.class.getDeclaredMethods();
Bu yordamida biz klassimizdagi barcha metodlarni olamiz.
getName() va getModifiers() metodlari
Barcha metodlarning nomlarini olish uchun biz getName dan foydalanishimiz mumkin:
static List<String> getMethodsName(Method[] methods) {
return Arrays.asList(methods)
.stream()
.map(Method::getName)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}
Va modifikatorlarni olish uchun, getModifiers dan foydalanib metod yozamiz:
static List<String> getModifiers(Method[] methods) {
return Arrays
.stream(methods)
.map(Method::getModifiers)
.map(String::valueOf)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}
Bizning main metodimiz:
public static void main(String[] args) {
Method[] methods = Person.class.getDeclaredMethods();
System.out.println(getMethodsName(methods));
System.out.println(getModifiers(methods));
}
Bizning natijamiz:
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Barcha modifikatorlarimiz public kirishga ega, shuning uchun oxirgi metod bizga birliklarni qaytaradi. Agar biz kodimizni modifikatsiya qilsak, modifikatorlarimizni ko'ramiz:
public static void main(String[] args) {
Method[] methods = Person.class.getDeclaredMethods();
System.out.println(getMethodsName(methods));
System.out.println(modifyModifiers(getModifiers(methods)));
}
[public, public, public, public, public, public, public, public, public, public, public]
getReturnedType()
Bu metod yordamida biz metodning qaytariladigan turini olishimiz mumkin:
static void getReturnedType(Method[] methods) {
Arrays.stream(methods)
.map(Method::getReturnType)
.forEach(System.out::println);
}
boolean
class java.lang.String
int
void
class java.lang.String
boolean
int
void
void
void
getGenericReturnType()
Person klassimizga jeneralizatsiyalangan turda qaytaradigan metod qo'shamiz va uning qaytariladigan qiymatini olishga harakat qilamiz:
public List<String> someMethod() {
//juda foydali va muhim metod
return null;
}
Va asosiy metodimizni modifikatsiya qilamiz:
static void getGenericReturnType(Method[] methods) {
Arrays.stream(methods)
.map(Method::getGenericReturnType)
.forEach(System.out::println);
}
Metod natijasi:
boolean
class java.lang.String
int
void
class java.lang.String
boolean
int
void
void
void
java.util.List<java.lang.String>
getParameterTypes() va getGenericParameterTypes() metodlari
Person klassimizdagi metodimizni modifikatsiya qilishda davom etamiz va yana ikki metod qo'shamiz:
public List<String> someMethod(List<String> list, String s) {
//juda foydali va muhim metod
return null;
}
Birinchisi metodlarimizning parametrlarini olishimizga, ikkinchisi esa jeneralizatsiyalangan parametrlarni ham chiqarishga imkon beradi.
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);
}
}
Faqatgina bitta metodimizga murojaat qilamiz. Ma'lum bir nom bo'yicha metodga murojaat qilish uchun, getMethod chaqiramiz va unga kerakli metod nomi va parametrlarini uzatamiz:
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);
}
Kodimiz natijalariga ko'ra, metodlar qanday farq qilishini va ular nima qaytarishini ko'ramiz:
class java.lang.String
java.util.List<java.lang.String>
class java.lang.String
getExceptionTypes() va getGenericExceptionTypes() metodlari
Bu metodlar yordamida biz metodimiz chiqarishi mumkin bo'lgan istisnolar massivini va agar mavjud bo'lsa, jeneralizatsiyalangan istisnolarni olishimiz mumkin. Sirli statik klass bilan yangi misolni ko'rib chiqamiz:
private static class Processor {
private void init() {}
private void process() throws IOException {}
}
Processor klassimizda metodlarni chaqiramiz:
public static void main(String... args) throws NoSuchMethodException {
Method method = Processor.class.getDeclaredMethod("process");
Type[] type = method.getExceptionTypes();
System.out.println(Arrays.toString(type));
}
Natijada bizning istisnomiz aniq ko'rinib turibdi:
Endi barchasini jeneralikka o'rab olamiz. Asosiy klassimizni modifikatsiya qilamiz:
private static class Processor<E extends IOException> {
private void process() throws E {
}
}
Va Main klassining kodi:
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);
}
}
}
}
Bu metod ichida biz TypeVariables oldik — bu tur o'zgaruvchilari uchun umumiy super interfeys. Ichida esa biz ichki parametrni, ya'ni ichki istisnomizni olishimiz mumkin:
class java.io.IOException
getAnnotations() va getDeclaredAnnotations() metodlari
Yangi klassimiz bilan ishlashni davom etamiz va unga bir nechta annotation qo'shamiz. Annotation nomli o'z annotationimizni yaratamiz:
@Retention(RetentionPolicy.RUNTIME)
@interface Annotation {
public String key();
public String value();
}
Uni metodimizga qo'shamiz:
@Annotation(key = "key", value = "value")
private void process() throws E{
}
Va barcha annotationlarimizni ko'rsatish uchun metod, albatta:
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();
}
}
Bizning Main klassimizning amalga oshirilishi:
public static void main(String... args) {
Class clazz = Processor.class;
getMethodAnnotations(clazz);
}
Ekranda quyidagi natijani olamiz:
[@com.company.Main&Annotation(key=”key”, value=”value”)]
Shu tariqa biz metodlarimizga tegishli annotationlarni olamiz, va getAnnotations metodi yordamida biz klassning ota-annotationlariga ham kirish imkoniga ega bo'lamiz.
Bugun sen bilan biz refleksiya yordamida metod va maydonlarning qanday ishlashini va u orqali qanday ma'lumotlar olishimiz mumkinligini bilib oldik!
GO TO FULL VERSION