一、前言
java反射是一个很好的机制,本文会提供一些java反射例子帮助读者对其有所理解。
类其实也是一种对象,是java.lang.Class类的实例。编译阶段类信息会被编译成.class文件,在类加载阶段,类加载器把.class文件读入JVM内存,生成java.lang.Class对象(这时已经可以通过Class对象查看类信息了),再经过类的连接(验证、准备、解析)与类的初始化阶段后即可使用类对象。我们通常使用的new关键字与反射创建实例时都会触发类初始化。
二、Java反射的常规使用步骤
1、获取目标类的java.lang.Class对象
2、获取目标类的信息(字段、方法、构造器、注解等)
3、生成并操作对象
三、获取目标类的java.lang.Class对象
这个是搞Java必会的基础,面试也常问,主要有三种方法:
注:为方便测试,定义一个User类,类定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
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!"); } } |
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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异常
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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()——获取所有形参
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
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()方法
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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是调用该方法的实参。
测试
1 2 3 4 5 6 7 8 9 10 |
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为要设置的值
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
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); } } |

好了,相信大家应该理解了上面的应用java反射例子了。
有问题欢迎留言指正。