Java的反射

Class类

在此之前,我们必须知道一句话,“java之中的一切都可以看作一个对象”。类是对象的抽象,而Class则是类的抽象,即任何一个类都是Class的实例对象。另外注意区别Class类和class关键字。Class类下面有很多方法,例如getConstructors() (包括其一些相似作用的方法这里以及后面不再列举,例如getDeclaredConstructor()等等),getFields(),getMethods();而它们会分别返回Constructor类型、Filed类型、Method类型的对象或者数组。Class类的构造方法是私有的,当一个类被加载时,JVM(java虚拟机)会自动通过Class的私有构造方法实例化一个Class对象,而我们没有办法通过Class的构造方法去实例化Class。而我们可以通过以下三种方法来获得Class的实例化对象;

  1. 类名.forName(“具体路径 包名.类名”);
  2. 类名.class;
  3. 对象.getClass();

获得了Class的实例化对象,我们就可以获得类的很多信息,例如权限修饰符,参数列表,类名,成员变量,成员方法等等。

Constructor类

每个Constructor对象都代表一个构造方法,利用Constructor对象可以操作相应的构造方法。下面时Constructor类常用的方法以及它的作用;

  1. isVarArgs(),查看该构造方法是否允许带有可变数量的参数,如果允许则返回true,否则返回false;方法原型:public boolean isVarArgs();
  2. getName(),以字符串的形式返回该构造方法的名字。方法原型:public String getName();
  3. getParameterTypes(),按照声明顺序以Class数组的形式获得该构造方法的各个参数类型。方法原型:public Class<?>[] getParameterTypes();
  4. getExceptionTypes(),以Class数组的形式获得该构造方法可能抛出的异常类型。方法原型:public Class<?>[] getExceptionTypes();
  5. newInstance(),通过该构造方法利用指定参数创建一个该类的对象,如果未设置参数则表示采用默认无参数的构造方法。函数原型:public T newInstance(Object… initargs),T表示返回的是一个Objec类的对象;

    注:Class.newInstance和Constructor.newInstance的有区别;Constructor的该方法能够使用有参数的构造方法,而Class下的该方法只能够使用无参默认构造方法。

  6. setAccessible(),如果该构造方法的权限为private,默认不允许通过反射利用newInstance()方法创建对象;如果先执行该方法并将入口参数设为true,则允许创建。方法原型:public void setAccessible(boolean flag);
    7.getModifiers(),获得可以解析出该构造方法所采用的修饰符的整数(利用Modifier类下的toString方法可以转换成字符串)。方法原型:public int getModifiers()。

下面介绍几个Modifier类常用的方法;

isPublic(int mod);

isProtected(int mod);

isPrivate(int mod);

isStatic(int mod);

isFinal(int mod);

toString(int mod);

这几种方法的作用都显而易见,不再赘述。

下面看代码示例:

//代码示例 Main类
import java.lang.reflect.*;

public class Main_01 {

	public static void main(String[] args) {

		Example_01 example = new Example_01("10", "20", "30");
		Class<? extends Example_01> exampleC = example.getClass();

		Constructor[] declaredConstructors = exampleC.getDeclaredConstructors();
		for (int i = 0; i < declaredConstructors.length; i++) {
			Constructor<?> constructor = declaredConstructors[i];
			System.out.println("查看是否允许带有可变数量的参数:" + constructor.isVarArgs());
			System.out.println("该构造方法的入口参数类型依次为:");
			Class[] parameterTypes = constructor.getParameterTypes();
			for (int j = 0; j < parameterTypes.length; j++) {
				System.out.println(" " + parameterTypes[j]);
			}
			System.out.println("该构造方法可能抛出的异常类型为:");
			Class[] exceptionTypes = constructor.getExceptionTypes();
			for (int j = 0; j < exceptionTypes.length; j++) {
				System.out.println(" " + exceptionTypes[j]);
			}
			Example_01 example2 = null;
			while (example2 == null) {
				try {
					if (i == 2)
						example2 = (Example_01) constructor.newInstance();
					else if (i == 1)
						example2 = (Example_01) constructor.newInstance("7", 5);
					else {
						Object[] parameters = new Object[] { new String[] {
								"100", "200", "300" } };
						example2 = (Example_01) constructor
								.newInstance(parameters);
					}
				} catch (Exception e) {
					System.out.println("在创建对象时抛出异常,下面执行setAccessible()方法");
					constructor.setAccessible(true);
				}
			}
			if(example2!=null){
			example2.print();
			System.out.println();
			
			}
		}

	}

}

//代码示例 Example类
public class Example_01 {
	String s;
	int i, i2, i3;
	private Example_01() {
	}
	protected Example_01(String s, int i) {
		this.s = s;
		this.i = i;
	}
	public Example_01(String... strings) throws NumberFormatException {
		if (0 < strings.length)
			i = Integer.valueOf(strings[0]);
		if (1 < strings.length)
			i2 = Integer.valueOf(strings[1]);
		if (2 < strings.length)
			i3 = Integer.valueOf(strings[2]);
	}
	public void print() {
		System.out.println("s=" + s);
		System.out.println("i=" + i);
		System.out.println("i2=" + i2);
		System.out.println("i3=" + i3);
	}
}

这是运行结果截图:

Filed类

每个Field对象都代表一个成员变量,利用Field对象可以操控相应的成员变量。下面是Field类的一些常用的方法以及作用;

  1. getName(),获得该成员变量的名称。方法原型:public String getName();
  2. getType(),获得表示该成员变量类型的Class对象。方法原型:public Class<?> getType();
  3. getModifiers(),获得可以解析出该成员变量所采用修饰符的整数。方法原型:public int getModifiers();
  4. get(Object obj),获得指定对象obj中成员变量的值,返回类型为Object型。方法原型:public Object get(Object obj);
  5. set(Object obj,Object value),将指定对象obj中成员变量的值设定为value;
    还有具体到各种类型的get set方法,不再一一介绍。另外说明:Object对象指的是已经实例化的反射对象。
    下面是代码示例:
//代码示例 Main类
import java.lang.reflect.*;
public class Main_02 {
	public static void main(String[] args) {
		Example_02 example = new Example_02();
		Class exampleC = example.getClass();
		// 获得所有成员变量
		Field[] declaredFields = exampleC.getDeclaredFields();
		for (int i = 0; i < declaredFields.length; i++) {
			Field field = declaredFields[i]; // 遍历成员变量
			// 获得成员变量名称
			System.out.println("名称为:" + field.getName());
			Class fieldType = field.getType(); // 获得成员变量类型
			System.out.println("类型为:" + fieldType);
			boolean isTurn = true;
			while (isTurn) {
				// 如果该成员变量的访问权限为private,则抛出异常,即不允许访问
				try {
					isTurn = false;
					// 获得成员变量值
					System.out.println("修改前的值为:" + field.get(example));
					// 判断成员变量的类型是否为int型
					if (fieldType.equals(int.class)) {
						System.out.println("利用方法setInt()修改成员变量的值");
						field.setInt(example, 168); // 为int型成员变量赋值
						// 判断成员变量的类型是否为float型
					} else if (fieldType.equals(float.class)) {
						System.out.println("利用方法setFloat()修改成员变量的值");
						// 为float型成员变量赋值
						field.setFloat(example, 99.9F);
						// 判断成员变量的类型是否为boolean型
					} else if (fieldType.equals(boolean.class)) {
						System.out.println("利用方法setBoolean()修改成员变量的值");
						// 为boolean型成员变量赋值
						field.setBoolean(example, true);
					} else {
						System.out.println("利用方法set()修改成员变量的值");
						// 可以为各种类型的成员变量赋值
						field.set(example, "MWQ");
					}
					// 获得成员变量值
					System.out.println("修改后的值为:" + field.get(example));
				} catch (Exception e) {
					System.out.println("在设置成员变量值时抛出异常,"
							+ "下面执行setAccessible()方法!");
					field.setAccessible(true); // 设置为允许访问
					isTurn = true;
				}
			}
			System.out.println();
		}
	}
}
//代码示例 Example类
public class Example_02 {
	int i;
	public float f;
	protected boolean b;
	private String s;
}

下面是运行结果:

Method类

每个Method对象代表一个方法,利用Method对象可以操纵相应的方法。下面是Method类的一些常用的方法以及作用;

  1. getName(),获得该方法的名称。方法原型:public String getName();
  2. getParameterTypes(),按照声明的顺序以Class数组的形式获得该方法的各个参数的类型。方法原型:public Class<?>[] getParameterTypes();
  3. getReturnType(),以Class对象的形式返回该方法的返回类型。方法原型:public Class<?> getReturnType();
  4. getExceptionTypes(),以Class数组的形式获得该方法可能抛出的异常。方法原型:public Class<?> getExceptionTypes();
  5. invoke(Object obj,Object···args),利用指定参数args执行指定对象obj中的该方法,返回值类型为Object型。方法原型:public Object invoke(Object obj, Object… args);
  6. isVarArgs(),同Constructor;
  7. getModifiers(),同上。
    下面是代码示例:
//代码示例 Main类
import java.lang.reflect.*;

public class Main_03 {
	public static void main(String[] args) {
		Example_03 example = new Example_03();
		Class exampleC = example.getClass();
		// 获得所有方法
		Method[] declaredMethods = exampleC.getDeclaredMethods();
		for (int i = 0; i < declaredMethods.length; i++) {
			Method method = declaredMethods[i]; // 遍历方法
			System.out.println("名称为:" + method.getName()); // 获得方法名称
			System.out.println("是否允许带有可变数量的参数:" + method.isVarArgs());
			System.out.println("入口参数类型依次为:");
			// 获得所有参数类型
			Class[] parameterTypes = method.getParameterTypes();
			for (int j = 0; j < parameterTypes.length; j++) {
				System.out.println(" " + parameterTypes[j]);
			}
			// 获得方法返回值类型
			System.out.println("返回值类型为:" + method.getReturnType());
			System.out.println("可能抛出的异常类型有:");
			// 获得方法可能抛出的所有异常类型
			Class[] exceptionTypes = method.getExceptionTypes();
			for (int j = 0; j < exceptionTypes.length; j++) {
				System.out.println(" " + exceptionTypes[j]);
			}
			boolean isTurn = true;
			while (isTurn) {
				// 如果该方法的访问权限为private,则抛出异常,即不允许访问
				try {
					isTurn = false;
					if("staticMethod".equals(method.getName()))
						method.invoke(example); // 执行没有入口参数的方法
					else if("publicMethod".equals(method.getName()))
						System.out.println("返回值为:"
								+ method.invoke(example, 168)); // 执行方法
					else if("protectedMethod".equals(method.getName()))
						System.out.println("返回值为:"
								+ method.invoke(example, "7", 5)); // 执行方法
					else if("privateMethod".equals(method.getName())) {
						Object[] parameters = new Object[] { new String[] {
								"M", "W", "Q" } }; // 定义二维数组
						System.out.println("返回值为:"
								+ method.invoke(example, parameters));
					}
				} catch (Exception e) {
					System.out.println("在执行方法时抛出异常,"
							+ "下面执行setAccessible()方法!");
					method.setAccessible(true); // 设置为允许访问
					isTurn = true;
				}
			}
			System.out.println();
		}
	}
}

//代码示例 Example
public class Example_03 {
	static void staticMethod() {
		System.out.println("执行staticMethod()方法");
	}
	
	public int publicMethod(int i) {
		System.out.println("执行publicMethod()方法");
		return i * 100;
	}
	
	protected int protectedMethod(String s, int i)
			throws NumberFormatException {
		System.out.println("执行protectedMethod()方法");
		return Integer.valueOf(s) + i;
	}
	
	private String privateMethod(String... strings) {
		System.out.println("执行privateMethod()方法");
		StringBuffer stringBuffer = new StringBuffer();
		for (int i = 0; i < strings.length; i++) {
			stringBuffer.append(strings[i]);
		}
		return stringBuffer.toString();
	}
}

下面是运行结果图:

未完待更……2020-4-2

版权声明:本文为hackerstd原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/hackerstd/p/12617030.html