zoukankan      html  css  js  c++  java
  • 反射

    1、什么是反射?

      ***框架的灵魂就是反射***

      在程序运行时,对于任何一个类,都能获取类中的属性和方法,对于任何一个对象,都能调用它的任意属性和方法。简单来说,就是能动态获取任何类的信息和能够操作任何对象的属性和方法,这就是java的反射机制

    2、如何使用反射?

      2.1、先明白java程序的开发过程

        先编写源码,后缀名为java,然后编译,编译的结果是字节码文件,字节码文件中包含类中的全部信息,后缀为class,然后jvm运行字节码文件

      2.2、反射的操作过程

        (1)、获取类的字节码文件

        (2)、获取字节码文件中的属性、方法

        (3)、使用获取的属性和方法

      2.3、三个步骤中需要的方法

        2.3.1、获取基本信息的方法

    getName():获取类的完整路径名
    newInstance():创建对象
    getPackage():获取包名
    getSimpleName():获取类名
    getSupperClass():获取当前类继承的父类的名字
    getInterfaces():获取当前类继承的类或者接口的名字
    

        2.3.2、获取类的字节码文件

          三种方法:

    ①Class.forname("目标类的全类名");
    ②类名.class
    ③对象名.getClass()
    

         注:三种方式获取的类的字节码文件是同一个

        2.3.3、获取字节码文件中的属性、方法的方法

          Ⅰ、获取构造函数

    getConstructor(Class...<?> parameterType):根据参数类型获取公共的构造方法
    getConstructors():获取所有的公共的构造方法
    getDeclaredConstructor(Class...<?> parameterType):根据参数类型获取构造方法
    getDeclaredConstructors():获取所有的构造方法
    

          Ⅱ、获取属性

    getField(String name):根据属性名获取公共属性对象
    getFields():获取所有的公共属性对象
    getDeclaredField(String name):根据属性名获取属性对象
    getDeclaredFields():获取所有的属性对象
    

          Ⅲ、获取类中成员方法的方法

    getMethod(String name,Class...<?> parametorTypes):根据方法名和方法参数类型获取共有方法对象
    getMethods():获取所有的公共的方法对象
    getDeclaredMethod(String name,Class...<?> parametorTypes):根据方法名和方法参数类型获取方法对象
    getDeclaredMethods():获取所有的方法对象
    

           Ⅳ、获取类中注解的方法

    getAnnotation(Class...<?> AnnotationTypes):根据注解类型获取共有注解对象
    getAnnotations():获取所有的公有注解对象
    getDeclaredAnnotation(Class...<?> AnnotationTypes):根据注解类型获取注解对象
    getDeclaredAnnotations():获取所有的注解对象
    

         2.3.4、反射创建对象的两种方式

          Ⅰ、根据获取的构造函数对象创建类对象(constructor.newInstance())

          Ⅱ、直接 字节码对象.newInstance(),默认调用空构造创建对象

        2.3.5、操作属性值

          属性对象.get(Object o)

          属性对象.set(Object o,value)

          属性对象.setAccessible(Boolean b):忽略属性的权限修饰符

        2.3.6、调用方法

          方法对象.invoke(Object b,param... p):调用目标方法

          

    代码:

    获取字节码对象:

    public static void main(String[] args) throws Exception {
            //三种方式
            //1.Class.forName("全类名");  获取  类的字节码对象  通过类路径
            Class pClass1 = Class.forName("com.cz.reflex.demo1.People");
            System.out.println(pClass1);
    
            //2.类名.class
            Class pClass2 = People.class;
            System.out.println(pClass2);
    
            //3.通过  对象.getClass();
            People people = new People();
            Class pClass3 = people.getClass();
            System.out.println(pClass3);
    
            System.out.println(pClass1 == pClass2);
            System.out.println(pClass1 == pClass3);
        }
    View Code

    获取并调用类构造方法:

    public void test1() throws Exception {
            //1.获取类的字节码对象
            Class pClass = People.class;
            //2.获取字节码对象中的构造信息
            Constructor constructor = pClass.getConstructor(int.class);
            System.out.println(constructor);
            //通过从类的字节码对象中获取到的构造器 调用newInstance方法  并且传入需要的参数   创建实例对象
            People o = (People) constructor.newInstance(5);
            System.out.println(o);
    
            Constructor constructor1 = pClass.getConstructor(int.class, String.class);
            System.out.println(constructor1);
    
            Constructor constructor2 = pClass.getConstructor(int.class, String.class, String.class);
            System.out.println(constructor2);
            //通过从类的字节码对象中获取到的构造器 调用newInstance方法  并且传入需要的参数   创建实例对象
            Object o1 = constructor2.newInstance(18, "张三", "男");
            System.out.println(o1);
    
            //获取所有的公有(public)构造
            Constructor[] constructors = pClass.getConstructors();
            System.out.println(Arrays.toString(constructors));
    
            //不考虑构造的修饰符  获取构造器
            //单个的
            Constructor declaredConstructor = pClass.getDeclaredConstructor(String.class, String.class);
            System.out.println(declaredConstructor);
    
            //获取所有的构造器
            Constructor[] declaredConstructors = pClass.getDeclaredConstructors();
            System.out.println(Arrays.toString(declaredConstructors));
        
            //pClass.newInstance(); 默认调用无参空构造方法
            Object o2 = pClass.newInstance();
            System.out.println(o2);
        }
    View Code

    获取并调用普通成员方法:

    public void test3()throws Exception{
            //1.获取类的字节码对象
            Class pClass = People.class;
            //2.获取类中的方法信息
            //获取不带参数的方法
            Method aaa = pClass.getMethod("aaa");
            System.out.println(aaa);
    
            //invoke(Object obj, Object... args)  通过invoKe方法去调用这个方法
            aaa.invoke(pClass.newInstance());//调用aaa()方法
    
            //获取有参数的方法
            Method aaa1 = pClass.getMethod("aaa", int.class);
            System.out.println(aaa1);
            aaa1.invoke(pClass.newInstance(),6);
            /*
            不考虑权限修饰符获取方法
             */
            //获取单个,根据方法名字和参数类型
            Method bbb = pClass.getDeclaredMethod("bbb", int.class);
            System.out.println(bbb);
    
            //获取所有
            Method[] methods = pClass.getDeclaredMethods();
            System.out.println(Arrays.toString(methods));
        }
    View Code

    获取并操作属性:

    public void test2() throws Exception{
            //1.获取类的字节码对象
            Class pClass = People.class;
            //2.获取类中的属性信息
            // Field类  中提供一些操作属性的信息
            //获取pulic 修饰的变量/属性
            Field age = pClass.getField("age");
            System.out.println(age);
            Object o = pClass.newInstance();
            /*
            给属性赋值  set(Object obj,value)方法中需要传入 对象参数obj
            obj : 这个属性是哪个类的属性  对象参数就传入哪个类的实例对象
             */
            age.set(o,18);
            System.out.println(o);
    
            //获取所有的Public修饰的属性
            Field[] fields = pClass.getFields();
            System.out.println(Arrays.toString(fields));
    
            /**
             * 不考虑修饰符获取属性
             */
            //单个
            Field name = pClass.getDeclaredField("name");
            Object o1 = pClass.newInstance();
            //忽略权限修饰符   本来name属性是私有的,不能直接赋值,必须要开启 setAccessible(true),才可以进行赋值
            name.setAccessible(true);
            name.set(o1,"张三");
            System.out.println(o1);
    
            //所有
            Field[] declaredFields = pClass.getDeclaredFields();
            System.out.println(Arrays.toString(declaredFields));
        }
    View Code

    综合案例使用:

      使用反射和自定义注解,模拟框架,根据传入的实体类,自动生成sql语句

      自定义注解:

        @classname:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ClassName {
        String value();
    }
    View Code

        @Fieldname:

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface FieldName {
        String value();
    }
    View Code

       实体类:

    @ClassName("book")
    public class Book {
    
        @FieldName("bookid")
        private Integer bookid;
        @FieldName("bookname")
        private String bookname;
        @FieldName("author")
        private String author;
    }
    View Code

       测试类:

    //目的:利用反射和注解,完成模拟Mybatis的sql生成
    public class ReflectInfo {
        public static void main(String[] args) {
            String selectsql = selectSql(Book.class);
            System.out.println(selectsql);
    
            String delectSql = delectSql(Book.class);
            System.out.println(delectSql);
        }
    
    //    数据库查询语句
        public static String selectSql(Class c){
    //  1、获得实体类的字节码对象
            Class bclass=c;
    //  2、获取类中的 属性 和 类名,用于sql拼接
            ClassName classname = (ClassName) bclass.getAnnotation(ClassName.class);//通过注解获取注解中的信息
            String entityName=classname.value();
    
    //  3、先获取实体类中的字段,然后再通过字段对象获取注解,然后再得到注解中的信息
            Field[] declaredFields = bclass.getDeclaredFields();
            ArrayList<String> fieldlist = new ArrayList<>();//用来存放得到的注解信息
    //        循环遍历得到的属性数组,然后通过属性对象获取注解信息
            for (int i = 0; i < declaredFields.length; i++) {
                FieldName fieldName = declaredFields[i].getAnnotation(FieldName.class);
                fieldlist.add(fieldName.value());
            }
    
            StringBuffer sql = new StringBuffer();
            sql.append("select ");
    
            for (int i = 0; i < fieldlist.size(); i++) {
                if(i<fieldlist.size()-1){
                    sql.append(fieldlist.get(i)+",");
                }else {
                    sql.append(fieldlist.get(i));
                }
            }
    
            sql.append(" from "+entityName);
    
    //        System.out.println(sql.toString());
            return sql.toString();
        }
    
    
    //    数据库删除语句,根据id删除
        public static String delectSql(Class c){
    //        delect from xxx where x=?
            Class entityclas=c;
            ClassName className =(ClassName) entityclas.getAnnotation(ClassName.class);//get the annotation of the classname
            String entityCN=className.value();//the name of entity
    
            Field[] declaredFields = entityclas.getDeclaredFields();//get all Field
    //        ArrayList<String> fieldlist = new ArrayList<>();//set the annotation info ,it's found by field
    
            String targetField=null;
            for (int i = 0; i < declaredFields.length; i++) {
                FieldName f = declaredFields[i].getAnnotation(FieldName.class);//first,get the annotation by field
                if(f.value().contains("id")){
                    targetField=f.value();// look for field like %id%
                    break;
                }
            }
    
            String sql="delect from "+entityCN+" where "+targetField+" =?";
            return sql;
        }
    }
    View Code

      

  • 相关阅读:
    Python将字符串转换成字典
    MySQL索引、视图
    MySQL高级查询
    MySQL函数应用
    MySQL约束
    MySQL基础查询
    MySQL数据库基本语法
    MySQL数据库存储引擎
    MySQL数据库简介与命令行操作
    MySQL 安装和配置环境变量
  • 原文地址:https://www.cnblogs.com/fbbg/p/14526619.html
Copyright © 2011-2022 走看看