第二篇 java中的反射

java中的反射

一、反射的概述

     JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;

这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。要想解剖一个类,必须先要获取到该类的字节码文件对象。

而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

1、创建实体类

 1 public class User {
 2     private int id;
 3     private int age;
 4     private String uname;
 5     
 6     public User(int id, int age, String uname) {
 7         super();
 8         this.id = id;
 9         this.age = age;
10         this.uname = uname;
11     }
12     public User() {
13         super();
14         // TODO Auto-generated constructor stub
15     }
16     public int getId() {
17         return id;
18     }
19     public void setId(int id) {
20         this.id = id;
21     }
22     public int getAge() {
23         return age;
24     }
25     public void setAge(int age) {
26         this.age = age;
27     }
28     public String getUname() {
29         return uname;
30     }
31     public void setUname(String uname) {
32         this.uname = uname;
33     }
34     
35     @Override
36     public String toString() {
37         return "User [id=" + id + ", age=" + age + ", uname=" + uname + "]";
38     }
39     
40 }

2、测试java.lang.Class对象的获取方式

 1 /**
 2  * 各种不同的类型的class对象的获取
 3  * 测试java.lang.Class对象的获取方式
 4  * @author Zhang XiaoDao
 5  *
 6  */
 7 public class Demo01 {
 8     public static void main(String[] args) {
 9         String path = "com.zzp.bean.User";    
10         try {
11             //加载javaBean
12             Class clazz = Class.forName(path);
13             
14             //对象是表示或封装一些数据,一个类被加载后(只能加载一次),jvm会创建一个对应该类的class对象,
15             //类的整个结构信息会放到对应的class对象中,这个class对象就像是一面镜子
16             //通过这面镜子,我们能看见对应类的全部信息
17             System.out.println(clazz);
18             //一个类只对应一个class对象,只被加载一次
19             Class clazz2 = Class.forName(path);
20             
21             //通过.class和getClass()获取对象
22             Class clazz3 =User.class;
23             Class clazz4 = path.getClass();
24             
25             //通过.class也能获取基本数据类型
26             Class int1 = int.class;
27             
28             //也能获取数组对象,一维数组arr01和arr02都是一样的,二维数组arr03与前面两个不同,
29             //数组的类型不一样,获取到的对象也不一样d与前面三个都不相同
30             int[] arr01 = new int[10];
31             int[] arr02 = new int[30];
32             int[][] arr03 = new int[10][20];
33             double[] d = new double[10];
34                     
35         } catch (ClassNotFoundException e) {
36             // TODO Auto-generated catch block
37             e.printStackTrace();
38         }
39     }
40 }

 3、应用反射的API,获取类的信息(类的名字,属性,方法,构造器等)

 

 1 /**
 2  * 
 3  * 应用反射的API,获取类的信息(类的名字,属性,方法,构造器等)
 4  * @author Zhang XiaoDao
 5  *
 6  */
 7 public class Demo02 {
 8     public static void main(String[] args) {
 9         String path = "com.zzp.bean.User";    
10         try {
11             //加载javaBean
12             Class clazz = Class.forName(path);
13             
14             //获取类的全路径
15             System.out.println(clazz.getName());
16             
17             //只获取类名
18             System.out.println(clazz.getSimpleName());
19             
20             //获取属性信息
21             //Field[] fields = clazz.getFields();//只能获取public修饰的属性
22             Field[] fields = clazz.getDeclaredFields();//获取所有的属性
23             System.out.println(fields.length);
24             
25             Field field = clazz.getDeclaredField("uname");//获取单个的属性
26             System.out.println(field);
27             
28             //获取方法信息
29             Method[] method = clazz.getDeclaredMethods();//获得所有的方法
30             Method m01 = clazz.getDeclaredMethod("getUname", null);//根据指定的方法名获取,无参传null
31             Method m02 = clazz.getDeclaredMethod("setUname", String.class);//有参的传参数
32             
33             //获取构造器
34             Constructor[] constructor = clazz.getDeclaredConstructors();//获取所有的构造器
35             //获取无参构造
36             Constructor a = clazz.getDeclaredConstructor(null);
37             //获取有参构造
38             Constructor c = clazz.getDeclaredConstructor(int.class,int.class,String.class);
39             
40         } catch (Exception e) {
41             // TODO Auto-generated catch block
42             e.printStackTrace();
43         }
44     }    
45 }

 4、通过反射API动态的操作:构造器、方法、属性

 1 /**
 2  * 
 3  * 通过反射API动态的操作:构造器、方法、属性
 4  * @author Zhang XiaoDao
 5  *
 6  */
 7 public class Demo03 {
 8     public static void main(String[] args) {
 9         String path = "com.zzp.bean.User";
10         //加载javaBean
11         try {
12             Class<User> clazz = (Class<User>) Class.forName(path);
13             
14             //通过反射API动态调用构造方法,构造对象
15             //其实是调用无参的构造器,javabean必须要有无参构造方法
16             User user = clazz.newInstance();
17             System.out.println(user);
18             
19             //调用指定的构造器
20              Constructor<User> c = clazz.getDeclaredConstructor(int.class,int.class,String.class);
21              User user2 = c.newInstance(1024,18,"张小刀1");
22              System.out.println(user2.getUname());
23              
24              //通过反射API调用普通的方法
25              User user3 = clazz.newInstance();
26              Method m = clazz.getDeclaredMethod("setUname", String.class);
27              m.invoke(user3, "张小刀2");//以上的两步相当于u3.setUname("张小刀")
28              System.out.println(user3.getUname());
29              
30              //通过反射API操作属性
31              User user4 = clazz.newInstance();
32              Field f = clazz.getDeclaredField("uname");
33              f.setAccessible(true);//这个属性不需要做安全检查了,可以直接访问
34              f.set(user4, "张小刀3");//通过反射直接写属性
35              System.out.println(user4.getUname());//通过反射直接读属性
36              System.out.println(f.get(user4));
37              
38         } catch (Exception e) {
39             // TODO Auto-generated catch block
40             e.printStackTrace();
41         }
42     }
43 }

 

反射机制的性能问题

setAccessible 
启用和禁止访问安全检查的开关,值为true,则表示反射的对象在使用时,应该取消安全检查;为false,则表示反射的对象应该实施java语言的安全检查。
并不是为true就能访问,为false就不能进行访问。
禁止安全检查,可以提高反射的运行速度。
可以考虑使用cglib/javaassist字节码操作
 1 /**
 2  * 测试反射调用对象方法时,跳过安全检查与不跳过安全检查之间的性能差别
 3  * @author Zhang XiaoDao
 4  *
 5  */
 6 public class Demo06 {
 7     public static void test01(){
 8         User u = new User();
 9         long startTime = System.currentTimeMillis();
10         
11         for(int i=0;i<1000000000L;i++){
12             u.getUname();
13         }
14         
15         long endTime = System.currentTimeMillis();
16         System.out.println("普通方法调用执行10亿次耗时:"+(endTime-startTime)+"ms");
17     }
18     
19     public static void test02(){
20         User u = new User();
21         Class clazz = u.getClass();
22         try {
23             Method m = clazz.getDeclaredMethod("getUname", null);
24             long startTime = System.currentTimeMillis();
25             
26             for(int i=0;i<1000000000L;i++){
27                 m.invoke(u, null);
28             }
29             
30             long endTime = System.currentTimeMillis();
31             System.out.println("反射动态方法调用,不跳过安全检查,执行10亿次耗时:"+(endTime-startTime)+"ms");
32         } catch (Exception e) {
33             // TODO Auto-generated catch block
34             e.printStackTrace();
35         } 
36     }
37     
38     public static void test03(){
39         User u = new User();
40         Class clazz = u.getClass();
41         try {
42             Method m = clazz.getDeclaredMethod("getUname", null);
43             m.setAccessible(true);//跳过安全检查
44             long startTime = System.currentTimeMillis();
45             
46             for(int i=0;i<1000000000L;i++){
47                 m.invoke(u, null);
48             }
49             
50             long endTime = System.currentTimeMillis();
51             System.out.println("反射动态方法调用,跳过安全检查,执行10亿次耗时:"+(endTime-startTime)+"ms");
52         } catch (Exception e) {
53             // TODO Auto-generated catch block
54             e.printStackTrace();
55         } 
56     }
57     
58     public static void main(String[] args) {
59         test01();
60         test02();
61         test03();
62     }
63 }

 1 普通方法调用执行10亿次耗时:745ms 2 反射动态方法调用,不跳过安全检查,执行10亿次耗时:4527ms 3 反射动态方法调用,跳过安全检查,执行10亿次耗时:3469ms 

 

反射操作泛型

 java使用泛型擦除的机制来引入泛型,java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换的麻烦,但是,一旦编译完成,所有的和泛型有关的类型全部擦除。为了通过反射操作这些类型以迎合实际开发的需要,java中新增了以下几种类型来代表不能被归一到class类中的类型,但是又和原始类型齐名的类型。

① ParameterizedType:表示一种参数化的类型,比如:Collection<String>

②GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型

③TypeVariable:是各种类型变量的公共父接口

④WildcardType:代表一种通配符类型表达式,比如:?,?extends Number,? super Integer

wildcard是一个单词:通配符的意思

 1 /**
 2  * 
 3  * 通过反射获取泛型信息
 4  * 参数信息
 5  * 返回信息
 6  * @author Zhang XiaoDao
 7  *
 8  */
 9 public class Demo04 {
10     public void test01(Map<String,User> map,List<User> list){
11         System.out.println("Demo04.test01()");
12     }
13     
14     public Map<Integer,User> test02(){
15         System.out.println("Demo04.test02()");
16         return null;
17     }
18     
19     public static void main(String[] args) throws Exception{
20         Method m = Demo04.class.getMethod("test01", Map.class,List.class);
21         Type[] T = m.getGenericParameterTypes();
22         for (Type t : T) {
23             System.out.println("t:"+t);
24             if(t instanceof ParameterizedType){
25                 Type[] genericTypes = ((ParameterizedType) t).getActualTypeArguments();
26                 for (Type type : genericTypes) {
27                     System.out.println("泛型类型:"+ type);
28                 }
29             }
30         }
31         
32         Method m2 = Demo04.class.getMethod("test02", null);
33         Type genericReturnType = m2.getGenericReturnType();
34         if(genericReturnType instanceof ParameterizedType){
35             Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
36             for (Type type : actualTypeArguments) {
37                 System.out.println("返回值泛型类型:"+type);
38             }
39         }
40     }
41 }

 

反射操作注解

 1 /**
 2  * 
 3  *使用反射读取注解的信息,模拟处理注解的流程
 4  *@author Zhang XiaoDao 
 5  */
 6 public class Demo03 {
 7 
 8     public static void main(String[] args) throws NoSuchFieldException, SecurityException{        
 9         try {
10             //通过反射加载需要处理的类
11             Class clazz = Class.forName("com.zzp.annotation.ZzpStudent");
12             
13             //获得类的所有有效的注解
14             Annotation[] Annotations = clazz.getAnnotations();
15             for (Annotation at : Annotations) {
16                 System.out.println(at);
17             }
18             
19             //获取类的指定的注解
20             Table t = (Table) clazz.getAnnotation(Table.class);
21             //输出t的值
22             System.out.println(t.value());
23             
24             //获取类的属性的注解
25             Field f = clazz.getDeclaredField("sname");
26             ZzpFiled t1 = f.getAnnotation(ZzpFiled.class);
27             System.out.println(t1.columnName()+"---"+t1.type()+"---"+t1.length());
28             
29             //可以根据获得的表名,属性等,拼出DDL语句,使用JDBC执行这个sql,在数据库中生成相关的表
30             
31         } catch (ClassNotFoundException e) {
32             e.printStackTrace();
33         }
34 
35     }
36 
37 }

 

posted on 2018-05-31 23:40  奋斗的小刀001  阅读(211)  评论(0编辑  收藏  举报

导航