Java 反射-访问成员

反射定义了一个接口java.lang.reflect.Member 其实现有java.lang.reflect.Field,java.lang.reflect.Method,以及 java.lang.reflect.Constructor。分别定义了如何来访问字段,方法以及构造器的实现。

一、访问字段

获取字段的类型:字段类型可以是8种基本数据类型,引用类型和枚举类型。

/**
	 * 访问字段的类型
	 */
	@Test
	public void testType() throws Exception {
		c = Class.forName("cn.com.xiaofen.field.FieldT");
		/* 根据字段名臣获取Field对象 */
		Field field = c.getField("val");
		/* 打印字段的类型 */
		out.format("%s%n", field.getType());
		/* 字段的标准类型 */
		out.format("%s%n", field.getGenericType());
	}



检索和访问方法的修饰符:字段可能出现的修饰符。

· Access modifiers: public, protected, and private
· Field-specific modifiers governing runtime behavior: transient and volatile
· Modifier restricting to one instance: static
· Modifier prohibiting value modification: final
· Annotations
/**
	 * 检索和访问方法的修饰符
	 */
	@Test
	public void testModifiers() throws ClassNotFoundException, NoSuchFieldException, SecurityException {
		c = Class.forName("cn.com.xiaofen.field.FieldT");
		/* 根据字段名臣获取Field对象 */
		Field field = c.getField("NAME");
		/* 获取字段的访问修饰符 */
		int mod = field.getModifiers();
		out.println(Modifier.toString(mod));
		/*字段查找参考官方API*/
	}




获取和设置字段的值:给定一个Class对象的实例可以通过反射获取字段的值,只有在特殊情况下使用,其违反了类的设计原则。

/**
	 * 获取和设置字段的值
	 * */
	@Test
	public void testValue() throws Exception{
		FieldT<Object> fieldT=new FieldT<>();
		c = fieldT.getClass();
		/*获取字段对象*/
		Field field=c.getDeclaredField("age");
		/*为字段设置值*/
		field.setInt(fieldT, 100);
		/*获取字段的值*/
		out.println(field.getInt(fieldT));
	}




二、访问方法

获取方法信息:方法的类型信息包括名字,修饰符,参数,返回类型及异常列表等。

/**
	 * 访问方法信息
	 */
	@Test
	public void testInfo() throws Exception {
		FieldT<Object> fieldT = new FieldT<>();
		c = fieldT.getClass();
		/* 获取所有方法并遍历 */
		Method[] allMethods = c.getDeclaredMethods();
		for (Method m : allMethods) {
			out.format("%s%n", m.toGenericString());
			/* 打印方法类型 */
			out.format(fmt, "ReturnType", m.getReturnType());
			out.format(fmt, "GenericReturnType", m.getGenericReturnType());
			/* 获取参数类型 */
			Class<?>[] pType = m.getParameterTypes();
			Type[] gpType = m.getGenericParameterTypes();
			/* 打印参数类型 */
			for (int i = 0; i < pType.length; i++) {
				out.format(fmt, "ParameterType", pType[i]);
				out.format(fmt, "GenericParameterType", gpType[i]);
				out.format(fmt, "GenericParameterName", gpType[i]);
			}
			/* 获取异常类型 */
			Class<?>[] xType = m.getExceptionTypes();
			Type[] gxType = m.getGenericExceptionTypes();
			for (int i = 0; i < xType.length; i++) {
				out.format(fmt, "ExceptionType", xType[i]);
				out.format(fmt, "GenericExceptionType", gxType[i]);
			}
			/* 打印方法参数数量 */
			out.format(fmt, "ParamCount", m.getParameterCount());
			/* 打印方法参数名称 */
			Parameter[] param = m.getParameters();
			for (Parameter p : param) {
				out.format(fmt, "ParameterName", p.getName());
			}
			/* 解析方法修饰符 */
			out.format("  Modifiers:  %s%n", Modifier.toString(m.getModifiers()));
		}
	}




 

调用方法:反射提供了一种方法用来调用Class对象的方法。java.lang.reflect.Method.invoke()

/**
	 * 调用方法
	 * */
	@Test
	public void testInvoke() throws Exception{
		FieldT<Object> fieldT = new FieldT<>();
		c = fieldT.getClass();
		/*获取指定方法*/
		Method method =c.getMethod("setSex", String.class);
		/*调用方法*/
		method.invoke(fieldT, "hello");
		out.format("  result:  %s%n", fieldT.getSex());
	}




三、构造器

构造器信息:构造器信息包括名称、修饰符、参数、异常列表等。

/**
	 * 访问构造器的基本信息
	 */
	@Test
	public void testFind() throws Exception {
		c = Class.forName("cn.com.xiaofen.modifier.Hello");
		/* 获取所有可用构造器 */
		Constructor[] allConstructors = c.getDeclaredConstructors();
		for (Constructor ctor : allConstructors) {
			/* 获取并打印参数类型 */
			Type[] pType = ctor.getGenericParameterTypes();
			for (int i = 0; i < pType.length; i++) {
				out.format("GenericParameterType %s%n", pType[i]);
			}

			/* 打印构造器访问修饰符 */
			out.format("modifier: %s%n", Modifier.toString(ctor.getModifiers()));
			out.println("-------------");
		}
	}



创建一个新的实例:反射提供了两个方法用来创建新的Class实例,java.lang.reflect.Constructor.newInstance() andClass.newInstance()前者为首选,原因如下。

Class.newInstance(),只能调用无参构造器。

Class.newInstance()在构造器中抛出任何异常,无论检查与否。Constructor.newInstance()总是抛出InvocationTargetException包装的异常。

Class.newInstance()构造器必须是可见的,Constructor.newInstance()某些情况下可以调用私有的构造器。

/**
	 * 实例化对象
	 * */
	@Test
	public void testNewInstance() throws Exception {
		c = Class.forName("cn.com.xiaofen.modifier.Hello");
		/*获取一个String类型的构造器*/
		Constructor<?> constructor=c.getConstructor(String.class);
		/*使用有参数构造器实例化对象*/
		Hello<?, ?> hello=(Hello<?, ?>) constructor.newInstance("hello");
		out.println(hello.getMessage());
		/*使用无参数构造器实例化对象*/
		hello=(Hello<?, ?>) c.newInstance();
		out.println(hello.getMessage());
	}




 项目地址:https://github.com/poai/Reflect.git