คลาส java.lang.reflect.Field
คลาสฟิลด์ให้ข้อมูลเกี่ยวกับและการเข้าถึงแบบไดนามิกไปยังฟิลด์เดียวของคลาสหรืออินเทอร์เฟซ ฟิลด์ยังอนุญาตให้มีการแปลงประเภทที่กว้างขึ้นระหว่างการดำเนินการรับหรือตั้งค่าการเข้าถึง แต่จะโยนIllegalArgumentExceptionหากการจำกัดเกิดขึ้น
ในการรับ วัตถุ ฟิลด์ก่อนอื่นเราจะเขียนคลาส:
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 :
วิธี | คำอธิบาย |
---|---|
รับประเภท () | ส่งคืนวัตถุคลาสที่ระบุประเภทการประกาศของฟิลด์ที่แสดงโดยสิ่งนี้สนามวัตถุ. |
getAnnotatedType() | ส่งคืนคำอธิบายประกอบประเภทวัตถุที่แสดงถึงการใช้ประเภทเพื่อระบุประเภทการประกาศของฟิลด์ที่แสดงโดยฟิลด์นี้ |
getGenericType() | คืนพิมพ์วัตถุที่แสดงถึงประเภทของฟิลด์ที่ประกาศซึ่งแสดงโดยสิ่งนี้สนามวัตถุ. |
รับชื่อ () | ส่งกลับชื่อของฟิลด์ที่แสดงโดยสิ่งนี้สนามวัตถุ. |
getModifiers() | ส่งกลับ int เข้ารหัสตัวดัดแปลงภาษา Java สำหรับฟิลด์ที่แสดงโดยสิ่งนี้สนามวัตถุ. |
รับคำอธิบายประกอบ () | ส่งกลับคำอธิบายประกอบสำหรับฟิลด์นี้ หากไม่มีคำอธิบายประกอบ จะส่งคืนอาร์เรย์ว่าง |
เมธอด getType(), getName() และ getModifiers()
เราสามารถใช้ เมธอด getType()เพื่อรับประเภทของฟิลด์ของเรา ลองเขียนวิธีการ:
static void printTypes(List<Field> fields){
fields.forEach(e -> System.out.println(e.getType()));
}
และเราได้ผลลัพธ์นี้:
int
บูลีน
คลาส java.lang.String
int
int
ตอนนี้ให้เพิ่มวิธีการในชั้นเรียนของเราเพื่อรับชื่อฟิลด์ สิ่งนี้จะทำให้การนำทางในฟิลด์ของชั้นเรียนของเราง่ายขึ้น
static void printTypesAndNames(List<Field> fields){
fields.forEach(e -> System.out.printf("Field type - %s\nField name - %s\n\n", e.getType(), e.getName()));
}
ตอนนี้ผลลัพธ์เป็นที่เข้าใจมากขึ้น:
ชื่อฟิลด์ -
ชื่อ ประเภทฟิลด์ - int
ชื่อฟิลด์ - อายุ
ประเภท
ฟิลด์ - บูลีน ชื่อฟิลด์ - isMale
ประเภทฟิลด์ - คลาส java.lang.String
ชื่อฟิลด์ - ที่อยู่
ประเภทฟิลด์ - int
ชื่อฟิลด์ - MAX_AGE
ประเภทฟิลด์ - int
ชื่อฟิลด์ - MIN_AGE
ยอดเยี่ยม! มาปรับเปลี่ยนวิธีการของเรากันดีกว่า! เราจะเพิ่มตัวแก้ไขการเข้าถึงที่นี่
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())));
}
และมาดูกันว่าe.getModifiers()ส่งคืน อะไร เมธอดนี้ส่งคืนintที่ช่วยให้เรากำหนดสถานะของตัวแก้ไขการเข้าถึงฟิลด์ของเรา คลาส Modifier ประกอบด้วยตัวแปรสแตติกที่รับผิดชอบสำหรับตัวแก้ไขเฉพาะแต่ละ ตัวของฟิลด์
มารวมค่าส่งคืนของเราในModifier.toString()และรับค่าเป็นข้อความทันที:
ชื่อฟิลด์ - ชื่อ โม
ดิฟายเออร์ - ส่วนตัว
ประเภทฟิลด์ - int
ชื่อฟิลด์ - อายุ โม
ดิฟายเออร์ - ส่วนตัว
ประเภทฟิลด์ - ชื่อฟิลด์บูลีน
- isMale
โมดิฟายเออร์ - สาธารณะ
ประเภทฟิลด์ - คลาส java.lang.String
ชื่อฟิลด์ - ตัวแก้ไข ที่อยู่
- ป้องกัน
ประเภทฟิลด์ - int
ชื่อฟิลด์ - MAX_AGE
ตัวแก้ไข - สาธารณะแบบคงที่สุดท้าย
ประเภทฟิลด์ - int
ชื่อฟิลด์ - MIN_AGE
ตัวแก้ไข - สาธารณะแบบคงที่สุดท้าย
นี่คือลักษณะที่ไม่มีModifier.toString() :
ชื่อฟิลด์ - ชื่อ
ตัวดัดแปลง - 2
ประเภทฟิลด์ - int
ชื่อฟิลด์ - อายุ โม ดิฟาย
เออร์ - 2
ประเภทฟิลด์ - บูลีน
ชื่อฟิลด์ - isMale
ตัวดัดแปลง - 1
ประเภทฟิลด์ - class java.lang.String
ชื่อฟิลด์ - ตัวแก้ไข ที่อยู่
- 4
ประเภทฟิลด์ - int
ชื่อฟิลด์ - MAX_AGE
ตัวแก้ไข - 25
ประเภทฟิลด์ - int
ชื่อฟิลด์ - MIN_AGE
ตัวแก้ไข - 25
เมธอด getAnnotations(), getAnnotatedType() และ getGenericType()
มาแก้ไข คลาส Personเพื่อทำงานกับเมธอดเหล่านี้ เราจะเขียนคำอธิบายประกอบของเราเองและนำไปใช้กับฟิลด์ของเรา และเราจะเพิ่มฟิลด์อีกสองสามฟิลด์
มาสร้างคำอธิบายประกอบสองรายการ เราจะส่งชื่อตัวแปรในภาษา Pig Latin ไปที่หนึ่ง และเราจะใช้ชื่อที่สองสำหรับองค์ประกอบ:
@Target(value=ElementType.FIELD)
@Retention(value= RetentionPolicy.RUNTIME)
public @interface Name {
String name();
}
@Target({ ElementType.TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Number {
}
และเราจะเปลี่ยนคลาสหลักและ คลาส บุคคล :
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())));
}
ถึงเวลาดูผลลัพธ์ของวิธีการของเราและค้นหาว่าใช้ไปเพื่ออะไร:
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 > คลาส
java.lang.String \u006b\u006e\u0061\u006d\u0065\u0073")] [@Name(name="\u0041\u006d\u0065\u002d\u006e\u0061\u0079")] [ ]
-
getAnnotatedTypeส่งคืนคำอธิบายประกอบสำหรับฟิลด์ที่กำหนด ถ้ามี เราได้รับคำอธิบายประกอบสำหรับฟิลด์และเราสามารถมองเห็นได้อย่างสมบูรณ์
-
getGenericTypeช่วยให้คุณแสดงประเภทพารามิเตอร์ได้อย่างถูกต้อง
-
getAnnotationsส่งคืนคำอธิบายประกอบที่ใช้กับวัตถุของเรา
นี่คือวิธีที่เราสามารถรับข้อมูลทั้งหมดเกี่ยวกับแต่ละฟิลด์ในชั้นเรียนของเรา ตลอดจนตัวแก้ไขการเข้าถึง คำอธิบายประกอบ และประเภทข้อมูลได้อย่างง่ายดาย
java.lang.reflect.Method คลาส
สุดยอด! เราได้พูดคุยเกี่ยวกับสาขาของชั้นเรียนของเรา ตอนนี้ถึงเวลาที่จะพูดถึงวิธีการ
ในการรับ วัตถุ เมธอดเราเรียก เมธอด getMethodโดยส่งเป็นชื่อเมธอดของเรา นี่เป็นวิธีพื้นฐานในการรับ วัตถุ เมธอด :
Method getNameMethod = Person.class.getMethod("getName");
เราจะทำงานกับชั้นเรียนของเราต่อไป มาเพิ่ม getters และ setters และ hashCode วิธีเท่ากับและ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);
}
}
ตอนนี้เรามาเตรียมชุดของวิธีการที่เราจะตรวจสอบโดยใช้คลาสเมธอด นี่คือรายการของวิธีการที่สำคัญที่สุด:
วิธี | คำอธิบาย |
---|---|
รับชื่อ () | ส่งกลับชื่อของวิธีการ |
getModifiers() | ส่งคืนตัวแก้ไขการเข้าถึงของเมธอดนี้ |
getReturnType() | ส่งคืนประเภทการส่งคืนของเมธอด |
getGenericReturnType() | ส่งคืนประเภทการส่งคืนของเมธอด บัญชีสำหรับเมธอดทั่วไป |
getParameterTypes() | ส่งคืนอาร์เรย์ของพารามิเตอร์เมธอด |
getGenericParameterTypes() | ส่งคืนอาร์เรย์ของพารามิเตอร์เมธอด บัญชีสำหรับเมธอดทั่วไป |
getExceptionTypes() | ส่งกลับข้อยกเว้นที่เมธอดสามารถส่งกลับได้ |
getGenericExceptionTypes() | ส่งกลับข้อยกเว้นที่เมธอดโยนได้ บัญชีสำหรับประเภทพารามิเตอร์ |
รับคำอธิบายประกอบ () | ส่งกลับคำอธิบายประกอบสำหรับวิธีการ รวมถึงคำอธิบายประกอบพาเรนต์ |
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);
}
นี่คือ วิธีการ หลัก ของเรา :
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, 1]
ทุกเมธอดของเรามี ตัวดัดแปลง สาธารณะดังนั้นเมธอดสุดท้ายจึงคืนอาร์เรย์ของเมธอด หากเราแก้ไขรหัสของเรา เราจะเห็นตัวแก้ไขของเราเอง:
public static void main(String[] args) {
Method[] methods = Person.class.getDeclaredMethods();
System.out.println(getMethodsName(methods));
System.out.println(modifyModifiers(getModifiers(methods)));
}
สาธารณะ]
getReturnedType()
วิธีนี้ช่วยให้เราได้รับประเภทผลตอบแทนของวิธีการ:
static void getReturnedType(Method[] methods) {
Arrays.stream(methods)
.map(Method::getReturnType)
.forEach(System.out::println);
}
บูลีน
คลาส java.lang.String
int
เป็นโมฆะ
คลาส java.lang.String
บูลีน
int
เป็น
โมฆะ
เป็นโมฆะ
getGenericReturnType()
ให้ เมธอดคลาส Person ของเรา คืนค่าประเภทที่ห่อด้วยพารามิเตอร์ที่กำหนด และลองรับค่าส่งคืน:
public List<String> someMethod() {
// Very useful and important method
return null;
}
และเราจะอัปเดตวิธีการหลักของเรา:
static void getGenericReturnType(Method[] methods) {
Arrays.stream(methods)
.map(Method::getGenericReturnType)
.forEach(System.out::println);
}
ผลลัพธ์ของวิธีการของเรา:
บูลีน
คลาส java.lang.String
int
เป็นโมฆะ
คลาส java.lang.String
บูลี
น int
เป็น
โมฆะ
เป็นโมฆะ
java.util.List<java.lang.String>
เมธอด getParameterTypes() และ getGenericParameterTypes()
เรายังคงแก้ไข คลาส บุคคล ของเรา โดยเพิ่มเมธอดอีกสองเมธอด:
public List<String> someMethod(List<String> list, String s) {
// Very useful and important method
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);
}
รันโค้ดของเรา เราจะดูว่าเมธอดต่างกันอย่างไรและได้อะไรกลับมา:
คลาส java.lang.String
java.util.List<java.lang.String>
คลาส java.lang.String
เมธอด getExceptionTypes() และ getGenericExceptionTypes()
เราสามารถใช้เมธอดเหล่านี้เพื่อรับอาร์เรย์ของข้อยกเว้นที่เมธอดของเราสามารถส่งได้ เช่นเดียวกับข้อยกเว้นที่มีประเภทพารามิเตอร์ (ถ้ามี) ลองใช้ตัวอย่างใหม่ที่มีคลาสสแตติกซ่อนอยู่:
private static class Processor {
private void init() {}
private void process() throws IOException {}
}
และเราจะเรียกเมธอดใน คลาส ตัวประมวลผล ของเรา :
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 {
}
}
และรหัสของ วิธีการ หลัก :
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ซึ่งเป็นอินเทอร์เฟซหลักทั่วไปสำหรับตัวแปรประเภท และภายในนั้น ตอนนี้เราสามารถรับพารามิเตอร์ภายในได้ ซึ่งก็คือข้อยกเว้นแบบซ้อนของเรา:
คลาส java.io.IOException
เมธอด getAnnotations() และ getDeclaredAnnotations()
ลองใช้คลาสใหม่นี้ต่อไปและเพิ่มคำอธิบายประกอบสองสามข้อ เราจะสร้าง คำอธิบาย ประกอบคำอธิบายประกอบ ของเราเอง :
@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();
}
}
การดำเนินการตาม วิธีการ หลัก ของเรา :
public static void main(String... args) {
Class clazz = Processor.class;
getMethodAnnotations(clazz);
}
เอาต์พุตหน้าจอที่ได้คือ:
[@com.company.Main&Annotation(key="key", value="value")]
นี่คือวิธีที่เราจะได้รับคำอธิบายประกอบที่ใช้กับเมธอดของเรา และ เมธอด getAnnotationsช่วยให้เราเข้าถึงคำอธิบายประกอบหลักของคลาสได้เช่นกัน
วันนี้เราได้ทำความคุ้นเคยกับวิธีการสะท้อนกลับที่ทำงานร่วมกับเมธอดและฟิลด์ต่างๆ และข้อมูลใดบ้างที่เราจะได้รับจากมัน!
GO TO FULL VERSION