zoukankan      html  css  js  c++  java
  • 19.java反射入门

    一、反射机制是什么
    反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
    对于任意一个对象,都能够调用它的任意一个方法和属性;
    这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

    二、反射机制能做什么
    1.在运行时判断任意一个对象所属的类;
    2.在运行时构造任意一个类的对象;
    3.在运行时判断任意一个类所具有的成员变量和方法;
    4.在运行时调用任意一个对象的方法;
    5.生成动态代理。

    三、反射机制的相关API

    图片来源于 http://c.biancheng.net/view/1103.html

    1.通过一个对象获得完整的包名和类名:
      对象名.getClass().getName();
    2.实例化Class类对象:
      ①clazz1 = Class.forName("完整的包名和类名");
      ②clazz2 = new 构造方法.getClass();
        = 对象名.getClass();
      ③clazz3 = 类名.class;
    3.获取一个对象的父类与实现的接口:
      获得父类:clazz.getSuperclass();
      获得所有的接口:clazz.getInterfaces();
    4.获取某个类中的全部构造函数,实例化一个类的对象
      ①第一种方法,实例化默认构造方法:clazz.newInstance();
      ②第二种方法,取得全部的构造函数,可先查看每个构造函数的参数类型,再使用构造函数赋值:
          clazz.getConstructors()[i].getParameterTypes()[j].getName();
          clazz.getConstructors()[i].newInstance(参数);
    5.获取某个类的全部属性:
      本类的所有属性:
        clazz.getDeclaredFields();
      父类或实现的接口的所有属性:
        clazz.getFields();
      属性名:
        fields[i].getName();
      属性权限修饰符:
        int mo = field[i].getModifiers();
        String priv = Modifier.toString(mo);
      属性类型:
        field[i].getType();
      属性类型名:
        field[i].getType().getName();
    6.获取某个类的全部方法
      全部方法:
        clazz.getMethods();
      方法的返回类型:
        methods[i].getReturnType();
      某个方法的所有参数类型:
        methods[i].getParameterTypes();
    7.调用某个类的方法
      Method method = clazz.getMethod("方法名",new Class[]{参数类型1,参数类型2,...});
      method.invoke(对象名,new Object[]{参数1,参数2,...});
    8.操作某个类的属性
      可以直接对 private 的属性赋值:
      Field field = clazz.getDeclaredField("属性名");
      field.setAccessible(true);
      field.set(对象名,"属性值");

    四、反射机制的应用实例
    1.在泛型为Integer的ArrayList中存放一个String类型的对象。
    2.通过反射取得并修改数组的信息
    3.通过反射机制修改数组的大小
    4.将反射机制应用于工厂模式

    实例1:利用反射来审查一个对象的内部

    Main.java
    package reflecttest;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    public class Main {
    
        public static void main(String[] args) {
            // 打开连接
            // 准备语句,设置参数
            // 发送语句,执行并处理结果集(ResultSet)
            // 遍历结果集,把每一行封装成对象
            /*
            List<Student> students = new ArrayList<>();
            for (row : resultSet) {
                Student student = new Student(); // 要素1:要new的是哪个类
                student.setId(row.getInt(1)); // 要素2:这个类中有哪些属性,并且要能调用其setter
                student.setName(row.getString(2));
                student.setAge(row.getInt(3));
                students.add(student);
            }
            */
            // Java中类似镜子的机制叫做反射,可以用来审查某个对象或者某个类的内部(哪些字段,哪些方法,调用之)
            // 这面镜子叫做元对象(meta object),元数据
            Student student = new Student(1, "zhangan", 20);
            inspect(student);
            inspect(new Teacher(1, "lisi", "软件工程"));
        }
        
        /**
         * 审查一个对象(打印类名,打印声明的字段列表,打印定义的方法列表)
         * @param o
         */
        private static void inspect(Object o) {
            Class clazz = o.getClass(); // 获取描述对象的元数据
            System.out.println("限定类名:" + clazz.getName());
            System.out.println("简单类名:" + clazz.getSimpleName());
            
            Field[] fields = clazz.getDeclaredFields(); // 包括public、private等,但排除集成的字段
    //        System.out.println(Arrays.toString(fields));
            // 打印字段列表
            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i]; // field等元信息是跟类走的
                Object value;
                try {
    //                value = field.get(o); // 实际取值或者调用时得传入目标对象(与对象挂钩的)
                    // 默认是不能访问私有字段的,改为调用其getter
                    String getterName = "get" + StringUtils.cap(field.getName()); // getName, getAge
                    Method getter = clazz.getDeclaredMethod(getterName);
                    value = getter.invoke(o);
                } catch (Exception e) {
                    e.printStackTrace();
                    value = "--- 取值错误 ---";
                }  
                System.out.println("字段:" + field.getName() + ", " + 
                    field.getType().getSimpleName() + " = " + value);
            }
            
            // 打印方法列表
            Method[] methods = clazz.getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                Method method = methods[i];
                System.out.println("方法:" + method.getName() + ", " +
                    method.getReturnType().getSimpleName()); 
            }
        }
    }

      StringUtils.java

    package reflecttest;
    
    public class StringUtils {
    
        /**
         * 将首字母大写
         * @param name
         * @return
         */
        public static String cap(String name) {
            return name.substring(0, 1).toUpperCase() + name.substring(1);
        }
    }

      Student.java

    package reflecttest;
    
    public class Student {
    
        private Integer id;
        private String name;
        private int age;
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public Student(Integer id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
        public Student() {
        }
        
        @Override
        public String toString() {
            return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
        }
        
    }

      Teacher.java

    package reflecttest;
    
    public class Teacher {
    
        private Integer id;
        private String name;
        private String major;
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getMajor() {
            return major;
        }
        public void setMajor(String major) {
            this.major = major;
        }
        public Teacher(Integer id, String name, String major) {
            this.id = id;
            this.name = name;
            this.major = major;
        }
        public Teacher() {
        }
    }

    实例2:利用反射给对象属性赋值

      Mapper.java

    package reflecttest;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 作为MyBatis的一个最原始的原型
     * @author Administrator
     *
     */
    public class Mapper { 
    
        /**
         * 将row中的每一列set到目标类的对象上
         * @param clazz
         * @param row
         * @return
         */
        public static Object map(Class clazz, Map<String, Object> row) {
            // new一个目标对象
    //        new Student()
            try {
                // 获取无参构造器
                Constructor constructor = clazz.getDeclaredConstructor();
                Object obj = constructor.newInstance();
                
                // 将各列set到obj的属性上,如id列就setId(?)
                for (String columnName : row.keySet()) {
    //                System.out.println(columnName + " -> " + row.get(columnName));
                    Object value = row.get(columnName);
                    String setterName = "set" + StringUtils.cap(columnName);
                    // 此处忽略一个细节:如果列名对应的setter不存在应该忽略该列
                    Field field = clazz.getDeclaredField(columnName);
                    Method setter = clazz.getDeclaredMethod(setterName, field.getType());
                    setter.invoke(obj, value);
                }
                return obj;
            } catch (Exception e) {
                throw new RuntimeException(e);
            } 
        }
        
        public static void main(String[] args) {
            Map<String, Object> row = new HashMap<String, Object>();
            row.put("id", 3);
            row.put("name", "王五");
            row.put("age", 25);
            
            Object obj = map(Student.class, row);
            System.out.println(obj);
        }
    }

    实例3:利用Apache Commons工具来复制对象(属性)

    BeanUtilsTest.java
    package reflecttest;
    
    import java.lang.reflect.InvocationTargetException;
    
    import org.apache.commons.beanutils.PropertyUtils;
    
    public class BeanUtilsTest {
    
        public static void main(String[] args) throws Exception {
            // 如何获取bean属性
            // id, name, age
            Student o = new Student(5, "xyz", 30);
            String name = (String) PropertyUtils.getProperty(o, "name");
            System.out.println("name: " + name);
            
            // 如何设置bean属性
            PropertyUtils.setProperty(o, "name", "张三");
            System.out.println(o.getName()); // 应该是张三
            
            // 如何复制所有属性
            Student o2 = new Student();
            PropertyUtils.copyProperties(o2, o);
            System.out.println(o2);
        }
    }

     案例4:利用反射完成javabean之间的复制

    package com.myreflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    import com.pojo.User;
    
    public class ReflectDemo {
        //写一个类,写一个方法完成两个数求幂值  x的n次方值
        //用反射来调用此方法
        
        //写一个工具类,完成功能是javabean之间的复制 方法的原型:copyObject(Object obj1,Object obj2);
        //从obj1到obj2的复制功能
        //思路:Student对象 有属性:id,name,age,sex,birthday  有方法:Set和get方法
        //1.创建一个学员类给其属性赋值,然后再创建一个新的学员类,将原来的学员对象的值复制到新的学员对象中
        public  void  copy(Object obj1,Object obj2) throws Exception{
            //1.拿到obj1和obj2的类型
            Class c1 = obj1.getClass();
            Class c2 = obj2.getClass();
            //2.通过类型中的获取obj1的get方法取值。obj2的set方法来完成复制功能
            
            Field[] fs1 = c1.getDeclaredFields();
            //获取c1中以get开头属性名结尾的所有方法
            for (int i = 0; i < fs1.length; i++) {
                String getmethodName = "get"+cap(fs1[i].getName());
                Method getMethod = c1.getDeclaredMethod(getmethodName,null);
                
                String setmethodName = "set"+cap(fs1[i].getName());
                Method setMethod = c2.getDeclaredMethod(setmethodName, new Class[]{fs1[i].getType()});
                
                Object result = getMethod.invoke(obj1, null);
                setMethod.invoke(obj2, new Object[]{result});
            }
        }
        public String cap(String name) {
            return name.substring(0, 1).toUpperCase() + name.substring(1);
        }
        
        public static void main(String[] args) throws Exception {
            User user1 = new User();
            user1.setUsername("张三");
            user1.setPwd("q2w");
            
            User user2 = new User();
            ReflectDemo rd = new ReflectDemo();
            rd.copy(user1, user2);
            
            System.out.println(user2.getUsername()+"   "+user2.getPwd());
            
        }
    }
  • 相关阅读:
    允许 使用接口传递对象,为什么?
    一道猫和老鼠吵醒主人的笔试题(C#)
    随心所欲操作Enum枚举类型
    SmartPhone 2003 手机编程实战之一:简单上手 2005年01月08日
    SmartPhone 2003 手机编程实战之二:自己开发一个天气预报服务 2005116
    QQ是危险的、MSN是危险的,所有即时通讯都是危险的
    PWN通用技巧
    Jarvis Oj Pwn 学习笔记level2
    Jarvis Oj Pwn 学习笔记Tell Me Something
    Jarvis Oj Pwn 学习笔记level1
  • 原文地址:https://www.cnblogs.com/wlxslsb/p/10782905.html
Copyright © 2011-2022 走看看