反射
1.反射
1.1.反射概述
一种计算机处理方式。是程序可以访问、检测和修改它本身状态或行为的一种能力。 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意方法和属性; 这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
1.2.优缺点
1.2.1优点
a.反射提高了程序的灵活性和扩展性。
b.降低耦合性,提高自适应能力。
c.它允许程序创建和控制任何类的对象,无需提前硬编码目标类。
1.2.2缺点
a.性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
b.使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术因而会带来维护的问题,反射代码比相应的直接代码更复杂。
2.Class介绍
2.1.获取Class的方式
(1)如果持有一个对象,可以直接通过Object类中继承的getClass方法获取。
Student s = new Student(); Class clazz = s.getClass();
(2)可以直接通过类包(接口)直接调用其属性.class获取
Class clazz = Student.class
(3)可以通过Class类中提供的forName方法获取
Class clazz = Class.forName("全类名");
2.2.通过Class对象获取Constructor、Field、Method
2.2.1通过Class对象获取Constructor
getConstructor(Class<?>...parameterType) //它获取的是类的public构造 getConstructors //它获取的是类的所有的public构造 getDeclaredConstructor(Class<?>...parameterType) //获取的一个类的任意构造方法(私有和非私有的都可以) getDeclaredConstructors //获取的是类的所有的构造(包括私有的)例如:
(1)获取非私有的实例化对象的代码
//获取Student的Class对象 Class clazz = Class.forName("com.ccsoft.Student"); //获取构造方法对象 Constructor ct = clazz.getConstructor(); //获取Student的实例化对象 Object obj = ct.newInstance(); //也可以强转 Student stu = (Student)ct.newInstance();
(2)获取包括私有的实例化对象的代码
/获取Student的Class对象 Class clazz = Class.forName("com.ccsoft.Student"); //获取构造方法对象 Constructor ct = clazz.getDeclaredConstructor(); //取消检查 ct.setAccessible(true); //获取Student的实例化对象 Object obj = ct.newInstance(); //也可以强转 Student stu = (Student)ct.newInstance();
2.3 Field介绍
getField(String name) //获取一个Field对象(非私有的), getFields() //获取包含所有的Field对象的数组(非私有的), getDeclaredField(String name) //获取任意一个Field对象(包含私有的和非私有的), getDeclaredFields() //获取包含所有的Field对象的数组(包含私有的和非私有的),
举例:给Student类的私有age赋值
//获取Student的Class对象 Class clazz = Class.forName("com.itheima01.Student"); //获取属性对象 Field field_age = clazz.getDeclaredField("age"); //取消检查 field_age.setAccessible(true); //赋值操作 field_age.set(Student,18);
2.4 Method介绍
getMethod(String name,Class<?>...parameterType) //获取本类中非私有方法的对象 getMethods() //获取本类和父类以及超类的非私有方法的对象的数组 getDeclaredMethod(String name,Class<?>...parameterType) //获取本类中任意方法的对象 getDeclaredMethods() //获取本类包含私有的方法对象的数组
invoke方法:Method对象.invoke(类的实例化对象,方法参数)
User user = new User(); // 1.获取sayHello方法 // 1.获取sayHello方法的Method对象 Class clazz = user.getClass(); // 2.获取Method对象 |->此处传递的class是方法中的参数.class Method method = clazz.getMethod("sayHello", String.class); // 3.让方法执行 Object invoke = method.invoke(user, "fox"); System.out.println(invoke);
2.5.Method的invoke使用时注意事项
2.5.1如果方法是static,我们怎样调用?
如果方法是静态的,在通过invoke调用时不需要传递对象
Method method = clazz.getMethod("sum"); method.invoke(null);
2.5.1 如果方法的参数是一个数组类型,怎样处理?
(1)将args直接强制转换成Object再传递。
Integer[] args = {1,2,3,4}; method.invoke(user,(object)args);
(2)在数组参数的外面再包装一层数组
Object[] obj={args}; mothod.invoke(user,obj);
3.反射案例
将Map集合中的数据匹配javaben 中的属性,并将值赋给javabean中的属性。
1 @Test 2 public void test() { 3 4 Map<String, Object> map = new HashMap<String, Object>(); 5 map.put("username", "tom"); 6 map.put("age", 20); 7 map.put("sex", "男"); 8 map.put("address", "北京"); 9 10 } 11 12 // 通过属性对应setXxx方法来完成操作 13 @Test 14 public void test2() throws Exception{ 15 Map<String, Object> map = new HashMap<String, Object>(); 16 map.put("username", "tom"); 17 map.put("age", 20); 18 map.put("sex", "男"); 19 map.put("address", "北京"); 20 // 1.得到Person类的Class 21 Class clazz = Class.forName("com.itheima.reflect.Person"); 22 Object obj = clazz.newInstance(); 23 //2.得到Person类中的方法 24 Method[] methods = clazz.getDeclaredMethods(); 25 //3.遍历map 26 for(String key:map.keySet()){ 27 //将所有的key前面添加上set,与方法的名称不区分大小写来对比。 28 String methodName="set"+key; //操作的方法 29 for(Method method:methods){ 30 String mname=method.getName(); 31 if(methodName.equalsIgnoreCase(mname)){ 32 method.invoke(obj, map.get(key)); 33 } 34 } 35 } 36 System.out.println(obj); 37 } 38 // 通过属性来完成操作 39 @Test 40 public void test1() throws Exception { 41 Map<String, Object> map = new HashMap<String, Object>(); 42 map.put("username", "tom"); 43 map.put("age", 20); 44 map.put("sex", "男"); 45 map.put("address", "北京"); 46 // 1.得到Person类的Class 47 Class clazz = Class.forName("com.itheima.reflect.Person"); 48 Object obj = clazz.newInstance(); 49 // 2.得到Person类的所有属性 50 Field[] fds = clazz.getDeclaredFields(); 51 // 3.得到map中所有的key 52 Set<String> keys = map.keySet(); 53 for (Field f : fds) { 54 String field_name = (f.getName()); // 得到属性名称 55 56 if (keys.contains(field_name)) { // map的key中包含了Person类的属性 57 // 4.将key对应的value赋值给属性 58 f.setAccessible(true); 59 f.set(obj, map.get(field_name)); 60 } 61 } 62 System.out.println(obj); 63 }