Java的反射机制是在编译时并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用的是在编译期并不知道的类。这样的编译特点就是java反射。反射可以在运行时获取任意 Class 或 Object 内部所有的成员变量、成员方法、构造函数和 Annotation。
本文中用到的类:
StaticMethod
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface StaticMethod {
}
UserInfo
public class UserInfo {
private String userName;
private int userId;
public UserInfo(String userName, int userId) {
this.userName = userName;
this.userId = userId;
}
@StaticMethod
public String getUserName() {
System.out.println("getUserName");
return this.userName;
}
@StaticMethod
public static void staticMethod(String userName, int id) {
System.out.println("static method invoked:" + userName);
}
}
public class Reflect {
public static void main(String[] strings) {
// getFields(UserInfo.class);
// getMethod(UserInfo.class);
// getConstruction(UserInfo.class);
// getFieldValue(new UserInfo("owen", 1));
// invokeMethod();
}
private static void getFields(Class userInfoClass) {
Field[] fields = userInfoClass.getDeclaredFields();
for(Field field : fields) {
String fieldString = "";
fieldString += Modifier.toString(field.getModifiers()) + " ";
fieldString += field.getType().getSimpleName() + " ";
fieldString += field.getName();
fieldString += ";";
System.out.println(fieldString);
}
}
private static void getMethod(Class userInfoClass) {
Method[] methods = userInfoClass.getDeclaredMethods();
for (Method method : methods) {
String methodString = Modifier.toString(method.getModifiers()) + " " ; // private static
methodString += method.getReturnType().getSimpleName() + " "; // void
methodString += method.getName() + "("; // staticMethod
Class[] parameters = method.getParameterTypes();
for (Class parameter : parameters) {
methodString += parameter.getSimpleName() + " "; // String
}
methodString += ")";
System.out.println(methodString);
}
}
private static void getConstruction(Class userInfoClass) {
Constructor[] constructors = userInfoClass.getDeclaredConstructors();
for (Constructor constructor : constructors) {
String s = Modifier.toString(constructor.getModifiers()) + " ";
s += constructor.getName() + "(";
Class[] parameters = constructor.getParameterTypes();
for (Class parameter : parameters) {
s += parameter.getSimpleName() + ", ";
}
s += ")";
System.out.println(s);
}
}
private static void getFieldValue(UserInfo userInfo) {
try {
Field field = UserInfo.class.getDeclaredField("userName");
field.setAccessible(true);
String str = (String) field.get(userInfo);
System.out.print(str);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void invokeMethod() {
try {
Method[] methods = UserInfo.class.getDeclaredMethods(); // 获取所有成员方法
for (Method method : methods) {
if (method.isAnnotationPresent(StaticMethod.class)) { // 判断是否被 @Invoke 修饰
if (Modifier.isStatic(method.getModifiers())) { // 如果是 static 方法
method.invoke(null, "owen", 12); // 直接调用,并传入需要的参数 devName
} else {
Class[] params = {String.class, int.class};
Constructor constructor = UserInfo.class.getDeclaredConstructor(params); // 获取参数格式为 String,long 的构造函数
Object userBean = constructor.newInstance("owen", 11); // 利用构造函数进行实例化,得到 Object
if (Modifier.isPrivate(method.getModifiers())) {
method.setAccessible(true); // 如果是 private 的方法,需要获取其调用权限
}
method.invoke(userBean); // 调用 method,无须参数
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
1、打印成员变量
Java 里提供了 Field 这个类来表示成员变量,提供了 clazz.getDeclaredFields() 来获取一个类内部声明的所有变量。因此,可以利用下面的代码获取 UserInfo 内部所有的成员变量。
代码如下:
private static void getFields(Class userInfoClass) {
Field[] fields = userInfoClass.getDeclaredFields();
for(Field field : fields) {
String fieldString = "";
fieldString += Modifier.toString(field.getModifiers()) + " ";
fieldString += field.getType().getSimpleName() + " ";
fieldString += field.getName();
fieldString += ";";
System.out.println(fieldString);
}
}
2、打印成员方法
可以通过 Method[] methods = UserInfo.class.getDeclaredMethods(); 获得所有的成员方法
代码如下:
private static void getMethod(Class userInfoClass) {
Method[] methods = userInfoClass.getDeclaredMethods();
for (Method method : methods) {
String methodString = Modifier.toString(method.getModifiers()) + " " ; // private static
methodString += method.getReturnType().getSimpleName() + " "; // void
methodString += method.getName() + "("; // staticMethod
Class[] parameters = method.getParameterTypes();
for (Class parameter : parameters) {
methodString += parameter.getSimpleName() + " "; // String
}
methodString += ")";
System.out.println(methodString);
}
}
3、打印构造函数:
Java 里提供了 Constructor 来表示构造函数
代码如下:
private static void getConstruction(Class userInfoClass) {
Constructor[] constructors = userInfoClass.getDeclaredConstructors();
for (Constructor constructor : constructors) {
String s = Modifier.toString(constructor.getModifiers()) + " ";
s += constructor.getName() + "(";
Class[] parameters = constructor.getParameterTypes();
for (Class parameter : parameters) {
s += parameter.getSimpleName() + ", ";
}
s += ")";
System.out.println(s);
}
}
4、获取对象中某个变量的值
private static void getFieldValue(UserInfo userInfo) {
try {
Field field = UserInfo.class.getDeclaredField("userName");
field.setAccessible(true);
String str = (String) field.get(userInfo);
System.out.print(str);
} catch (Exception e) {
e.printStackTrace();
}
}
5、调用 Class 内部的用 @Invoke 修饰的方法
可以利用 class.getDeclaredMethods() 获取一个类内部所有成员方法,然后:
判断这个方法是否被 @Invoke 修饰
如果修饰,判断这个方法是不是 static 的
如果是 static,则可以直接用 class 调用
如果不是 static,那就需要实例化一个对象来调用
如果这个方法是 private 的,要记得 setAccessible(true)。
代码如下:
private static void invokeMethod() {
try {
Method[] methods = UserInfo.class.getDeclaredMethods(); // 获取所有成员方法
for (Method method : methods) {
if (method.isAnnotationPresent(StaticMethod.class)) { // 判断是否被 @Invoke 修饰
if (Modifier.isStatic(method.getModifiers())) { // 如果是 static 方法
method.invoke(null, "owen", 12); // 直接调用,并传入需要的参数 devName
} else {
Class[] params = {String.class, int.class};
Constructor constructor = UserInfo.class.getDeclaredConstructor(params); // 获取参数格式为 String,long 的构造函数
Object userBean = constructor.newInstance("owen", 11); // 利用构造函数进行实例化,得到 Object
if (Modifier.isPrivate(method.getModifiers())) {
method.setAccessible(true); // 如果是 private 的方法,需要获取其调用权限
}
method.invoke(userBean); // 调用 method,无须参数
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}