一、前言
类其实也是一种对象,是java.lang.Class类的实例。编译阶段类信息会被编译成.class文件,在类加载阶段,类加载器把.class文件读入JVM内存,生成java.lang.Class对象(这时已经可以通过Class对象查看类信息了),再经过类的连接(验证、准备、解析)与类的初始化阶段后即可使用类对象。我们通常使用的new关键字与反射创建实例时都会触发类初始化。
(类的加载相关知识,可以参看博客http://blog.csdn.net/zhangliangzi/article/details/51319033?locationNum=1

二、Java反射的常规使用步骤
1、 获取目标类的java.lang.Class对象;
2、获取目标类的信息(字段、方法、构造器、注解等);
3、生成并操作对象

三、获取目标类的java.lang.Class对象 
这个是搞Java必会的基础,面试也常问,主要有三种方法:
注:为方便测试,定义一个User类,类定义如下:
public class User {
	private String user_id;
	public String user_name;
	
	//公用无参构造器
	public User(){
	}
	
	//公用有参构造器
	public User(String user_id, String user_name){
		this.user_id = user_id;
		this.user_name = user_name;
	}

	//getter
	public String getUser_id() {
		return user_id;
	}

	//setter
	public void setUser_id(String user_id) {
		this.user_id = user_id;
	}
	
	//test method
	public void say(){
		System.out.println(this.user_name + "Hello world!");
	}
}
测试如下:
public class TestReflect {
	public static void main(String[] args) throws ClassNotFoundException {
		// 获取java.lang.Class对象的三组方式
		// 第一种,使用Class的静态方法forName(类全称),可能抛出ClassNotFound异常
		Class c1 = Class.forName("com.javaReflect.User");
		// 第二种,使用类的class属性
		Class c2 = User.class;
		// 第三周,使用对象的getClass()方法
		Class c3 = new User().getClass();

		System.out.println(c1.getName());
		System.out.println(c2.getName());
		System.out.println(c3.getName());
	}
}
测试结果:


其中,第一种和第二种方法都是直接根据类名获取Class对象,第二种方法具有如下两种优势:
1、编译阶段检查目标类是否存在,更安全;
2、无需调用方法,效率更高;
所以,我们通常推荐使用第二种方式获取Class对象,但是如果在编写程序的时候我们不知道这里需要产生哪个Class对象,只知道有个类名会传入,这种情况我们就只能使用第一种方式去获取Class对象,但这也是反射的精髓,动态而灵活。


四、获取目标类信息
1、获取成员变量信息
getFields()——获取所有公有成员变量
getField(String name)——获取指定名称的公有成员变量,会抛出NoSuchFieldException异常
getDeclaredFields()——获取所有成员变量,不关乎权限
getDeclaredFields()——获取指定名称的成员变量,不关乎权限,会抛出NoSuchFieldException异常

测试如下:
public class TestReflect {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException {
		String className = "com.javaReflect.User";
		Class c = Class.forName(className);
		// 1、getFields()获取所有公有成员变量
		for (Field field : c.getFields()) {
			print(field);
		}
		System.out.println("-------------------------");
		// 2、getField(String name)获取指定名称的公有成员变量,会抛出异常
		print(c.getField("user_name"));
		System.out.println("-------------------------");
		// 3、getDeclaredFields()获取所有成员变量
		for (Field field : c.getDeclaredFields()) {
			print(field);
		}
		System.out.println("-------------------------");
		// 4、getDeclaredFields()获取指定名称的成员变量,会抛出异常
		print(c.getDeclaredField("user_id"));
	}

	public static void print(Field field) {
		// 输出变量类型
		System.out.println(field.getType().getName());
		// 输出变量名
		System.out.println(field.getName());
	}
}
测试结果:

2、获取方法以及参数信息
getMethods()——获取所有公有方法
getMethod(String methodName, Class<?> parameterTypes)——根据方法及形参列表获取公有方法,会抛出NoSuchMethodException异常
getDeclaredMethods()——获取所有方法
getDeclaredMethod(String methodName, Class<?> parameterTypes)——根据方法及形参列表获取方法,会抛出NoSuchMethodException异常
getParameters()——获取所有形参

测试如下:
public class TestReflect {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
		String className = "com.javaReflect.User";
		Class c = Class.forName(className);
		// 1、获取所有公有方法
		for (Method method : c.getMethods()) {
			print(method);
			System.out.println("--------------------------");
		}
		// 2、获取某一方法
		print(c.getMethod("setUser_id", String.class));
		System.out.println("--------------------------");
		// 3、getDeclaredMethods()获取所有方法
		// 4、getDeclaredMethod(String name, Class<?> parameterTypes);获取某一方法
		// 3、4与1、2使用方式类似,区别在于访问权限,3、4可以访问任意权限
	}

	public static void print(Method method) {
		// 输出方法名
		System.out.println(method.getName());
		// 输出方法返回值类型名
		System.out.println(method.getReturnType().getName());
		// 输出形参相关信息
		Parameter[] parameters = method.getParameters();
		int i = 0;
		for (Parameter parameter : parameters) {
			System.out.println("第" + ++i + "个形参信息:");
			// 输出形参名
			System.out.println(parameter.getName());
			// 输出形参类型名
			System.out.println(parameter.getType().getName());
		}
	}
}
测试结果:


3、获取构造方法信息(与上面一个套路……)
getConstructors()——获取所有公有构造器
getConstructor(Class<?> parameterTypes)——根据形参列表获取某一公有构造器
getDeclaredConstructors()——获取所有构造器
getDeclaredConstructor(Class<?> parameterTypes)——根据形参列表获取某一构造器

4、获取注解,关键字为annotation,一样一样的~~~~(>_<)~~~~

五、使用反射生成并操作对象
1、创建对象,两种方式:
Class对象的newInstance()方法——调用默认构造创建实例
Class对象获取指定Constructor对象,再调用该对象的newInstance()方法

测试如下:
public class TestReflect {
	public static void main(String[] args) throws Exception {
		String className = "com.javaReflect.User";
		Class c = Class.forName(className);
		// 第一种方式
		User user1 = (User) c.newInstance();
		user1.user_name = "第一种方式";
		user1.say();
		// 第二种方式
		User user2 = (User) c.getConstructor(String.class, String.class).newInstance("2", "第二种方式");
		user2.say();
	}
}
测试结果:

2、调用方法
Method对象的invoke(Object obj, Object args)——其中,第一个参数obj是执行该方法的主调(也就是一个拥有这个方法的对象),后面的arg是调用该方法的实参。

测试如下:
public class TestReflect {
	public static void main(String[] args) throws Exception {
		String className = "com.javaReflect.User";
		Class c = Class.forName(className);

		User user = (User) c.getConstructor(String.class, String.class).newInstance("1", "调用方法");
		Method sayMethod = c.getMethod("say", null);
		sayMethod.invoke(user, null);
	}
}
测试结果:


3、修改成员变量值
Field对象的getXXX(Object obj)——obj为拥有该属性的对象,XXX为8种基本类型,代表着成员变量类型,如果成员变量为引用类型,则去掉XXX。
Field对象的setXXX(Object obj, XXX val)——obj同上,val为要设置的值

测试如下:
public class TestReflect {
	public static void main(String[] args) throws Exception {
		String className = "com.javaReflect.User";
		Class c = Class.forName(className);

		User user = (User) c.getConstructor(String.class, String.class).newInstance("1", "调用方法");
		Method sayMethod = c.getMethod("say", null);
		sayMethod.invoke(user, null);

		Field user_name = c.getField("user_name");
		user_name.set(user, "修改后的用户名");
		sayMethod.invoke(user, null);
	}
}
测试结果:



本文转载:CSDN博客