反射

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

posted @ 2021-03-13 09:47  橙汁one  阅读(64)  评论(0编辑  收藏  举报