在Class 类中定义有如下两个取得类中普通方法的定义
public Method[] getMethods()
throws SecurityException
(核心)
public Method getMethod(String name,
Class<?>... parameterTypes)
throws NoSuchMethodException,
SecurityException
最重要的方法:
public Object invoke(Object obj, Object... args)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
package com.beyond.dhl.exercise;
import java.lang.reflect.Method;
class Person{
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class Test01 {
public static void main(String[] args) throws Exception {
Class<?> cls = Person.class;
Method met[] = cls.getMethods(); // 取得全部方法
for (int x = 0; x < met.length; x++) {
System.out.println(met[x]);
}
}
}
那么在之前所编写的程序对于类中的 setter, getter 方法 采用的都是明确的对象调用. 而现在有了反射处理机制之后, 这个时候的程序即使你没有明确的Person类型的对象(依然需要实例化对象, Object描述, 所有的普通方法必须在有实例化对象之后才可以进行调用), 就需要通过反射完成.
package com.beyond.dhl.exercise;
import java.lang.reflect.Method;
class Person{
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class Test01 {
public static void main(String[] args) throws Exception {
String attribute = "name"; // 明确的告诉你属性名称
String value = "DHL"; // 明确告诉你要设置的内容
Class<?> cls = Class.forName("com.beyond.dhl.exercise.Person"); // Class.forName("com.beyond.dhl.exercise.Person") 相当于 Person.class
Object obj = cls.newInstance(); // 任何情况下调用类中的普通方法, 都必须有实例化对象
// 取得setName这个方法是实例化对象, 设置方法名称和参数的类型
// setName() 是方法名称, 但是这个方法名称是根据给定的属性的信息拼凑得来的, 同时该方法需要接收一个String 类型的参数
Method setMethod = cls.getMethod("set"+initcap(attribute), String.class);
// 随后需要通过Method类对象调用指定的方法, 调用方法必须有实例化对象, 同时要传入一个参数
setMethod.invoke(obj, value); // 相当于: Person对象.setName(value)
Method getMethod = cls.getMethod("get"+initcap(attribute));
Object ret = getMethod.invoke(obj); // 相当于 Person对象.getName()
System.out.println(ret);
}
public static String initcap(String str) {
return str.substring(0,1).toUpperCase() + str.substring(1);
}
}
在之前已经成功的实现了类的构造调用, 方法调用, 那么除了这两种模式之外还需要有成员调用.
前提: 类中的所有属性一定要在类对象实例化之后才会进行空间的分配, 所有此时如果要想调用类的属性, 必须要有实例化对象, 而通过反射的 newInstence() 方法可以直接取得实例化对象(Object 类型).
1.1 取得类中的全部属性
public Field[] getFields()
throws SecurityException
1.2 取得类中指定名称的属性
public Field getField(String name)
throws NoSuchFieldException,SecurityException
2.1 取得本类中的全部属性
public Field[] getDeclaredFields()
throws SecurityException
2.2 取得本类中指定名称的属性
public Field getDeclaredField(String name)
throws NoSuchFieldException, SecurityException
package com.beyond.dhl.exercise;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
class Person{
private String name; // 此时的类中只是明确提供了一个属性
protected String nickName; // 此时的类中只是明确提供了一个属性
}
class Student extends Person{
// 做一个继承关系
private String school;
public String nameString;
}
public class Test01 {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.beyond.dhl.exercise.Student");
{
// 普通代码块
Field fields[] = cls.getFields(); // 取得全部属性
for (int x = 0; x < fields.length; x++) {
System.out.println(fields[x]);
}
}
System.out.println("====================");
{
// 普通代码块
Field fields[] = cls.getDeclaredFields(); // 取得全部属性
for (int x = 0; x < fields.length; x++) {
System.out.println(fields[x]);
}
}
}
}
现在就需要关注属性的核心描述类: java.lang.reflect.Field, 在这个类有两个重要的方法:
public void set(Object obj, Object value)
throws IllegalArgumentException, IllegalAccessException
public Object get(Object obj)
throws IllegalArgumentException, IllegalAccessException
在 AccessibleObject 中提供有一个方法 : 动态设置封装, 也称为 暴力反射
public void setAccessible(boolean flag)
throws SecurityException
nameField.setAccessible(true); // 取消封装
package com.beyond.dhl.exercise;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
class Person{
private String name; // 此时的类中只是明确提供了一个属性
}
public class Test01 {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.beyond.dhl.exercise.Person");
Object obj = cls.newInstance(); // 实例化本类对象
Field nameField = cls.getDeclaredField("name");
nameField.setAccessible(true); // 取消封装
nameField.set(obj, "张三"); // 等价于 对象.name = "张三";
System.out.println(nameField.get(obj)); // 取得属性
}
}
在 Field 类中有一个特别有用的方法: 取得属性类型
public Class<?> getType()
package com.beyond.dhl.exercise;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
class Person{
private String name; // 此时的类中只是明确提供了一个属性
}
public class Test01 {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.beyond.dhl.exercise.Person");
Object obj = cls.newInstance(); // 实例化本类对象
Field nameField = cls.getDeclaredField("name");
System.out.println(nameField.getType().getName()); // 包.类
System.out.println(nameField.getType().getSimpleName()); // 类名
}
}