一、前言
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!" ) ;
}
}
测试
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()方法
测试
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 ) ;
}
}
好了,相信大家应该理解了上面的应用java反射例子了。
有问题欢迎留言指正。