Կլասը java.lang.reflect.Field
Կլասը Field տրամադրում է տեղեկատվություն և դինամիկ մուտք դեպի դասի կամ ինտերֆեյսի մեկ դաշտ: Field նույնպես թույլ է տալիս ընդլայնում փոխակերպումների ժամանակ get կամ set մուտքի աշխատանքում, բայց տեղադրում է IllegalArgumentException բացառություն, եթե տեղի է ունենում նեղացում փոխակերպման ժամանակ:
Որպեսզի ստանաք Filed կլասը, մենք կգրենք կլասը, որի հետ կաշխատենք, ինչպես նաև դրա համար ցուցիչ:
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 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);
}
}
Այսպիսով մենք ստանում ենք մեր դասի դաշտերի ցանկը, որոնց հետ կշարունակենք աշխատել: Արդյունքը տեսք կունենա այսպես:
Հիմա եկեք տեսնենք, թե ինչ կարող ենք անել այս տվյալների շրջանակի հետ: Խոսենք Field կլասի մեթոդների մասին:
Մեթոդ | Նկարագրություն |
---|---|
getType() | Վերադարձնում է դասի օբյեկտ, որը որոշում է հայտարարված դաշտի տեսակն այս Field օբյեկտում: |
getAnnotatedType() | Վերադարձնում է AnnotatedType օբյեկտ, որը ներկայացնում է դաշտի հայտարարված տիպը այս դաշտում: |
getGenericType() | Վերադարձնում է Type օբյեկտ, որը ներկայացնում է դաշտի հայտարարված տիպը այս Field օբյեկտում: |
getName() | Վերադարձնում է դաշտի անունը, որը ներկայացված է այս Field օբյեկտում: |
getModifiers() | Վերադարձնում է Java լեզվի մոդիֆիկատորները դաշտի համար, որը ներկայացված է այս Field օբյեկտում, որպես ամբողջական թիվ: |
getAnnotations() | Վերադարձնում է այս դաշտի անոտացիաները: Եթե անոտացիաներ չկան — դատարկ զանգված: |
Մեթոդներ getType(), getName(), getModifiers()
Օգտագործելով getType() մեթոդը, մենք կարող ենք ստանալ մեր դաշտի տեսակն: Եկեք գրենք մեթոդ:
static void printTypes(List<Field> fields){
fields.forEach(e -> System.out.println(e.getType()));
}
Եվ կստանանք այսպիսի արդյունք:
int
boolean
class java.lang.String
int
int
Եկեք անմիջապես մեր դասում ավելացնենք մեթոդ, որը կստացնի դաշտի անունը: Այսպես ավելի հեշտ կլինի կողմնորոշվել մեր դասի դաշտերի միջոցով:
static void printTypesAndNames(List<Field> fields){
fields.forEach(e -> System.out.printf("Դաշտի տեսակ - %s\nԴաշտի անուն - %s\n\n", e.getType(), e.getName()));
}
Արդյունքը կդառնա ավելի հասկանալի օգտագործողի համար:
Դաշտի անուն - name
Դաշտի տեսակ - int
Դաշտի անուն - age
Դաշտի տեսակ - boolean
Դաշտի անուն - isMale
Դաշտի տեսակ - class java.lang.String
Դաշտի անուն - address
Դաշտի տեսակ - int
Դաշտի անուն - MAX_AGE
Դաշտի տեսակ - int
Դաշտի անուն - MIN_AGE
Հիանալի, եկեք նաև մեր մեթոդը ավելի մոդիֆիկացնենք: Ավելացնենք այստեղ մուտքի մոդիֆիկատորները:
static void printFieldInfo(List<Field> fields){
fields.forEach(e -> System.out.printf("Դաշտի տեսակ - %s\nԴաշտի անուն - %s\nՄոդիֆիկատորներ - %s\n\n", e.getType(), e.getName(), Modifier.toString(e.getModifiers())));
}
Եվ եկեք քննարկենք, թե ինչ է վերադարձնում e.getModifiers(): Այս մեթոդը վերադարձնում է int թիվ, որի մեջ կարող ենք որոշել դաշտի մուտքի մոդիֆիկատորը: Modifier կլասում կան ստատիկ փոփոխականներ, որոնք պատասխանատու են կոնկրետ մոդիֆիկատորի համար:

Մեր վերադարձվելիք արժեքը կտեղավորենք Мodifier.toString() — և անմիջապես կստանանք արժեքը տեքստային տեսքով:
Դաշտի անուն - name
Մոդիֆիկատորներ - private
Դաշտի տեսակ - int
Դաշտի անուն - age
Մոդիֆիկատորներ - private
Դաշտի տեսակ - boolean
Դաշտի անուն - isMale
Մոդիֆիկատորներ - public
Դաշտի տեսակ - class java.lang.String
Դաշտի անուն - address
Մոդիֆիկատորներ - protected
Դաշտի տեսակ - int
Դաշտի անուն - MAX_AGE
Մոդիֆիկատորներ - public static final
Դաշտի տեսակ - int
Դաշտի անուն - MIN_AGE
Մոդիֆիկատորներ - public static final
Եվ այսպես է դա երևում առանց Мodifier.toString():
Դաշտի անուն - name
Մոդիֆիկատորներ - 2
Դաշտի տեսակ - int
Դաշտի անուն - age
Մոդիֆիկատորներ - 2
Դաշտի տեսակ - boolean
Դաշտի անուն - isMale
Մոդիֆիկատորներ - 1
Դաշտի տեսակ - class java.lang.String
Դաշտի անուն - address
Մոդիֆիկատորներ - 4
Դաշտի տեսակ - int
Դաշտի անուն - MAX_AGE
Մոդիֆիկատորներ - 25
Դաշտի տեսակ - int
Դաշտի անուն - MIN_AGE
Մոդիֆիկատորներ - 25
Մեթոդներ getAnnotations(), getAnnotatedType(), getGenericType()
Եկեք մոդիֆիկացնենք Person կլասը, որպեսզի աշխատենք ընթացիկ մեթոդների հետ: Մենք կգրենք մեր սեփական անոտացիան, որը կավելացնենք մեր դաշտերին, ինչպես նաև կավելացնենք մի քանի դաշտ:
Ստեղծենք երկու անոտացիաներ: Մեկին կփոխանցենք փոփոխականի անունը ռուսերենով, իսկ երկրորդը կօգտագործենք տարրերի համար:
@Target(value=ElementType.FIELD)
@Retention(value= RetentionPolicy.RUNTIME)
public @interface Name {
String name();
}
@Target({ ElementType.TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Number {
}
Եվ փոփոխենք մեր հիմնական կլասը և Person: կլասը:
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())));
}
Ամեն ինչ պատճաշ է ՝ հստակ տեսնենք մեր մեթոդների արդյունքը և խոսենք նրանց նշանակության մասին:
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 վերադարձնում է դաշտի անոտացիան, եթե կա: Մենք ունենք դաշտի անոտացիա և մենք դա լավ տեսնում ենք:
getGenericType թույլ է տալիս ճիշտ ցույց տալ գեներացված պարամետրերը.
getAnnotations վերադարձնում է անոտացիաները, որոնք դրված են մեր օբյեկտի վրա:
Այսպիսով մենք հեշտությամբ կարող ենք ստանալ բոլոր տվյալները մեր դասի յուրաքանչյուր դաշտի մասին, նրա մուտքի մոդիֆիկատորների մասին, անոտացիաների և տվյալների տեսակների մասին:
Կլասը java.lang.reflect.Method
Սուպեր, մենք խոսեցինք մեր դասի դաշտերի մասին, հիմա ժամանակն է խոսել մեթոդների մասին:
Որպեսզի ստանաք Method կլասի օբյեկտ, մենք կանչում ենք getMethod և դրան փոխանցում մեր մեթոդի անունը: Սա հիմնարար մեթոդն է Method կլասի ստացման համար:
Method getNameMethod = Person.class.getMethod("getName");
Մենք կշարունակենք աշխատել մեր դասի հետ: Ավելացնենք անդամներից և set-երները, hashCode-երը, equals և 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);
}
}
Եվ եկեք պատրաստենք մեթոդների հավաքածուն, որոնք մենք կքննարկենք Method կլասի մեջ: Ահա հիմնական մեթոդների ցուցակը:
Մեթոդ | Նկարագրություն |
---|---|
getName() | Վերադարձնում է մեթոդի անունը: |
getModifiers() | Վերադարձնում է մեթոդի մուտքի մոդիֆիկատորը: |
getReturnType() | Վերադարձնում է մեթոդի վերադարձվող տեսակն: |
getGenericReturnType() | Վերադարձնում է մեթոդի վերադարձվող տեսակն հաշվի առնելով գեներացված մեթոդները: |
getParameterTypes() | Վերադարձնում է մեթոդի պարամետրերի զանգվածը: |
getGenericParameterTypes() | Վերադարձնում է մեթոդի պարամետրերի զանգվածը հաշվի առնելով գեներացված մեթոդները: |
getExceptionTypes() | Վերադարձնում է բացառությունները, որոնք կարող է դուրս գալ մոտոդը: |
getGenericExceptionTypes() | Վերադարձնում է բացառությունները, որոնք կարող է դուրս գալ մոտոդը, հաշվի առնելով գեներացված պարամետրերը: |
getAnnotations() | Վերադարձնում է մեթոդի անոտացիաները, ներառյալ ծնողական անոտացիաները: |
getDeclaredAnnotations() | Վերադարձնում է մեթոդի անոտացիաները, անտեսելով ծնողական անոտացիաները: |
Մեր դասի վերադարձվելիք մեթոդների զանգվածը ստանալու համար կարող ենք կանչել այսպիսի մեթոդ:
Method[] methods = Person.class.getDeclaredMethods();
Օգտագործելով այս, մենք կստանանք մեր դասից բոլոր մեթոդները:
Մեթոդներ getName() և getModifiers()
Մեր բոլոր մեթոդների անունները ստանալու համար կարող ենք օգտագործել getName:
static List<String> getMethodsName(Method[] methods) {
return Arrays.asList(methods)
.stream()
.map(Method::getName)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}
Եվ որպեսզի ստանանք մոդիֆիկատորները, կգրենք մեթոդ getModifiers կիրառությամբ:
static List<String> getModifiers(Method[] methods) {
return Arrays
.stream(methods)
.map(Method::getModifiers)
.map(String::valueOf)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}
Մեր main մեթոդը:
public static void main(String[] args) {
Method[] methods = Person.class.getDeclaredMethods();
System.out.println(getMethodsName(methods));
System.out.println(getModifiers(methods));
}
Մեր արդյունքը:
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Մեր բոլոր մոդիֆիկատորներն ունեն public մուտք, ուստի վերջին մեթոդը մեզ վերադարձնում է միավորներ: Եթե մենք մեր կոդը փոփոխենք, ապա կտեսնենք մեր մոդիֆիկատորները:
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()
Օգտագործելով այս մեթոդը, մենք կարող ենք ստանալ մեթոդի վերադարձվող տիպը:
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 կլասի մեջ մեթոդ, որը վերադարձնում է գեներացված տիպ, և փորձենք ստանալ նրա վերադարձվող արժեքը:
public List<String> someMethod() {
//շատ օգտակար և կարևոր մեթոդ
return null;
}
Եվ փոփոխենք մեր հիմնական մեթոդը:
static void getGenericReturnType(Method[] methods) {
Arrays.stream(methods)
.map(Method::getGenericReturnType)
.forEach(System.out::println);
}
Մեր մեթոդի արդյունքը:
boolean
class java.lang.String
int
void
class java.lang.String
boolean
int
void
void
void
java.util.List<java.lang.String>
Մեթոդներ getParameterTypes() և getGenericParameterTypes()
Շարունակենք փոփոխել մեր Person կլասի մեթոդը և ավելացնենք ևս երկու մեթոդներ:
public List<String> someMethod(List<String> list, String s) {
//շատ օգտակար և կարևոր մեթոդ
return null;
}
Գեներացված պարամետրերը նույնպես ցույց կտան։
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);
}
}
Աշխատանք կատարելու համար կդիմենք միայն մեկ մեր մեթոդներից մեկին: Որպեսզի դիմենք մեթոդին անունով, մենք կանչում ենք getMethod և դրան փոխանցում ենք անունը և մեր պահանջվող մեթոդի պարամետրերը:
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);
}
Եվ մեր կոդի արդյունքներում մենք կտեսնենք տարբերությունները և արդյունքները, որոնք հենց նրանք վերադարձնում են:
class java.lang.String
java.util.List<java.lang.String>
class java.lang.String
Մեթոդներ getExceptionTypes() և getGenericExceptionTypes()
Օգտագործելով այս մեթոդները մենք կարող ենք ստանալ բացառությունների զանգված, որոնք կարող է արտանետել մեր մեթոդը, ինչպես նաև գեներացված պարամետրերով (եթե այդպիսիք կան) բացառություններ: Մենք վերցնենք մի նոր օրինակ՝ թաքնված ստատիկ դասով:
private static class Processor {
private void init() {}
private void process() throws IOException {}
}
Կմտնենք այն մեթոդներից մեկի մեջ, ահա այսպես՝ Process:
public static void main(String... args) throws NoSuchMethodException {
Method method = Processor.class.getDeclaredMethod("process");
Type[] type = method.getExceptionTypes();
System.out.println(Arrays.toString(type));
}
Հիանալի, այսպես տեսնում ենք մեր բացառությունը:
Հիմա մեր բոլորի մոտ դնում է նորով `կակա կոնակը. Մենք այն տեղադրում ենք մեր հիմնական դասում:
private static class Processor<E extends IOException> {
private void process() throws E {
}
}
Եվ Main: միջաշինքի կոդզ՝ այստեղ արդեն առկա է փոփոխություն:
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);
}
}
}
}
Մեր մեթոդի ներսում մենք ստացանք TypeVariables — դա ընդհանուր սուպեր ինտերֆեյս է տիպի փոփոխականների համար: Եվ դրա ներսում կարող ենք ստանալ ներքին պարամետրը, հենց մեր ներքին արտադրական բացառումից:
class java.io.IOException
Մեթոդներ getAnnotations() և getDeclaredAnnotations()
Շարունակե՛նք աշխատել մեր նոր դասի հետ և ավելացնենք երկու անոտացիաներ: Ստեղծենք մեր սեփական Annotation անոտացիան:
@Retention(RetentionPolicy.RUNTIME)
@interface Annotation {
public String key();
public String value();
}
Եվ ավելացնենք այն մեր մեթոդի մեջ.
@Annotation(key = "key", value = "value")
private void process() throws E{
}
Եվ իհարկե, ստեղծեք մեթոդ, որը ցուցադրում է մեր բոլոր անոտացիաները:
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();
}
}
Մեր դասի՝ Main:
public static void main(String... args) {
Class clazz = Processor.class;
getMethodAnnotations(clazz);
}
Արդյունքում կստանանք այսպիսի արդյունք պատուհանի վրա:
[@com.company.Main&Annotation(key=”key”, value=”value”)]
Այսպիսով մենք կարող ենք ստանալ մեր մեթոդների անոտացիաները, իսկ getAnnotations մեթոդի միջոցով մենք ստանում ենք հասանելիություն նաև ծնողական դասի անոտացիաներին:
Այսօր մենք ծանոթացանք մեթոդների և դաշտերի հետ ռեֆլեքսիայի միջոցով և տեսանք, թե ինչ տվյալներ կարող ենք ստանալ նրանց միջոցով:
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ