JAVA-反射篇

/**
 *介绍:什么是反射机制
 *      在程序运行中 对于任意一个类或对象, 都可以获取到这个类的方法和属性(包含私有属性与方法)
 *      这种动态的获取信息以及动态的调用对象方法的功能,我们称为反射机制
 *      简单来说: 通过反射 类在我们面前是完全透明的。想要获取任何东西都可以
 * 优点:
 *      在程序的运行中,可以动态的获取类的属性与方法.操作这些对象
 *      可以解耦,提高程序的可扩展性
 * JAVA代码在计算机中所经历的三个阶段
 *      1: Source 阶段: 通过 javac 命令 .java 文件 编译成 .class 文件
 *      2: Class 类对象阶段 .class 字节码文件被类加载器 加载至内存 并将其封装成Class对象
 *      (用于在内存中描述字节码文件) Class 对象将原字节码中的成员变量抽取出来封装成数组Field[]
 *      将字节码文件中的构造函数抽取出来封装成Construction[] ,将成员方法 封装成数组 Method[]
 *      Class 类内不止这个,我们常用的就这三个
 *      3: RunTime运行时阶段: 使用 new 创建对象的过程
 */

public class ReflexTemplate {

    /**
     * 介绍:什么是反射机制
     *      在程序运行中 对于任意一个类或对象, 都可以获取到这个类的方法和属性(包含私有属性与方法)
     *      这种动态的获取信息以及动态的调用对象方法的功能,我们称为反射机制
     *      简单来说: 通过反射 类在我们面前是完全透明的。想要获取任何东西都可以
     */

    /**
     * 优点:
     *      在程序的运行中,可以动态的获取类的属性与方法.操作这些对象
     *      可以解耦,提高程序的可扩展性
     */
    /**
     * JAVA代码在计算机中所经历的三个阶段
     *      1: Source 阶段: 通过 javac 命令 .java 文件 编译成 .class 文件
     *      2: Class 类对象阶段 .class 字节码文件被类加载器 加载至内存 并将其封装成Class对象
     *      (用于在内存中描述字节码文件) Class 对象将原字节码中的成员变量抽取出来封装成数组Field[]
     *      将字节码文件中的构造函数抽取出来封装成Construction[] ,将成员方法 封装成数组 Method[]
     *      Class 类内不止这个,我们常用的就这三个
     *      3: RunTime运行时阶段: 使用 new 创建对象的过程
     */


    public static void test01() throws ClassNotFoundException {
        /*
        获取对象的三种方式
         */
        // 方式1: [Source阶段] Class.forName("全类名") 将字节码文件加载至内存。返回 Class 对象
        // 多用于配置文件 将类名定义于配置文件中 通过读取配置文件加载类
        Class<?> class1 = Class.forName("com.shangqing.api.reflex.ReflexTemplate");

        // 方式2: [Class] 类对象阶段 通过类名的属性 class 获取 多用于参数的传递
        Class<ReflexTemplate> class2 = ReflexTemplate.class;

        // 方式3: [Runtime运行时阶段] 对象.getClass(); 此方法定义于 Object 类中的方法 因此所有类都会继承这个方法 多用于对象获取字节码文件
        ReflexTemplate template = new ReflexTemplate();
        Class<? extends ReflexTemplate> class3 = template.getClass();

        System.out.println(class1 == class2);  // true
        System.out.println(class1 == class3);  // true

        // 同一个字节码文件 .class 在一次程序运行中 只会被加载一次 无论通过哪种方式获取Class对象 都是同一个
    }
    public String name;

    private Integer age;

    Integer height;

    protected String sex;

    public static void test02() throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        /*
            获取成员变量
         */
        Class<ReflexTemplate> reflexTemplateClass = ReflexTemplate.class;

        // 获取所有 public 修饰的成员变量
        Field[] fields = reflexTemplateClass.getFields();
        // 获取指定名称的 成员变量
        Field field = reflexTemplateClass.getField("name");
        Arrays.stream(fields).forEach(o->System.out.println(o.getName()));       // name
        System.err.println(field.getName());                                     // name

        ReflexTemplate template = reflexTemplateClass.newInstance();
        field.set(template,"张三");
        System.out.println(field.get(template));                                 // 张三

        // 获取所有成员变量 不考虑修饰符
        Field[] declaredFields = reflexTemplateClass.getDeclaredFields();
        // 获取指定成员变量 不考虑修饰符
        Field declaredField = reflexTemplateClass.getDeclaredField("age");
        Arrays.stream(declaredFields).forEach(o-> System.out.println(o.getName()));       // name age height sex
        System.err.println(declaredField.getName());                                      // age
        // 设置属性
        declaredField.set(template,11);
        System.out.println(declaredField.get(template));                                  // 11

    }

    public ReflexTemplate() {
    }

    private ReflexTemplate(String name) {
        this.name = name;
    }

    public ReflexTemplate(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public static void test03() throws NoSuchMethodException {
        /*
        获取构造方法
         */
        Class<ReflexTemplate> templateClass = ReflexTemplate.class;
        // 获取所有 public 修饰的 构造方法
        Constructor<?>[] constructors = templateClass.getConstructors();
        // com.shangqing.api.reflex.ReflexTemplate-------2  com.shangqing.api.reflex.ReflexTemplate-------0
        Arrays.stream(constructors).forEach(o-> System.out.println(o.getName()+ "-------"+o.getParameterCount()));   
        // 获取指定的 public 修饰的 构造方法
        Constructor<ReflexTemplate> constructor = templateClass.getConstructor(String.class,Integer.class);
        System.err.println(constructor.getName()+ "-------"+constructor.getParameterCount());   // com.shangqing.api.reflex.ReflexTemplate-------2
        // 获取所有 构造方法 忽略修饰符
        Constructor<?>[] declaredConstructors = templateClass.getDeclaredConstructors();
        //com.shangqing.api.reflex.ReflexTemplate-------1  com.shangqing.api.reflex.ReflexTemplate-------0  com.shangqing.api.reflex.ReflexTemplate-------2
        Arrays.stream(declaredConstructors).forEach(o->System.out.println(o.getName()+ "-------"+o.getParameterCount() )); 
        // 获取指定 构造方法 忽略修饰符
        Constructor<ReflexTemplate> declaredConstructor = templateClass.getDeclaredConstructor(String.class);
        System.err.println(declaredConstructor.getName()+ "-------"+constructor.getParameterCount()); // com.shangqing.api.reflex.ReflexTemplate-------2

    }

    public String method01(Integer i){
        return "method01";
    }

    private String method02(String i){
        return "method02";
    }

    public static void test04() throws NoSuchMethodException {
        /*
        获取成员方法
         */
        Class<ReflexTemplate> templateClass = ReflexTemplate.class;
        // 获取所有 Public 方法
        Method[] methods = templateClass.getMethods();
        Arrays.stream(methods).forEach(o->System.out.println(o.getName()));   // Public 包含 父类方法
        // 获取指定 Public 方法
        Method method = templateClass.getMethod("method01",Integer.class);
         System.err.println(method.getName());                                    // method01
        // 获取所有方法  忽略修饰符
        Method[] declaredMethods = templateClass.getDeclaredMethods();
        /*
        main
        test02
        test01
        lambda$test02$0
        test04
        lambda$test04$4
        lambda$test03$3
        method01
        test05
        lambda$test02$1
        lambda$test03$2
        method02
        test03
         */
        Arrays.stream(declaredMethods).forEach(o->System.out.println(o.getName()));

        // 获取指定方法  忽略修饰符
        Method declaredMethod = templateClass.getDeclaredMethod("method02", String.class);
        System.err.println(declaredMethod.getName());                       // method02

    }
    public static void test05(){
        Class<ReflexTemplate> templateClass = ReflexTemplate.class;
        System.out.println(templateClass.getName());
    }

    public static void main(String[] args) throws Exception {
        test01();
        test02();
        test03();
        test04();
        test05();
    }

newInstance()和new()区别:

1、两者创建对象的方式不同,前者是实用类的加载机制,后者则是直接创建一个类:

2、newInstance创建类是这个类必须已经加载过且已经连接,new创建类是则不需要这个类加载过

3、newInstance: 弱类型(GC是回收对象的限制条件很低,容易被回收)、低效率、只能调用无参构造,new 强类型(GC不会自动回收,只有所有的指向对象的引用被移除是才会被回收,若对象生命周期已经结束,但引用没有被移除,经常会出现内存溢出
  (注:newInstance实例化对象是只能调用无参构造方法,在A、B类中并没有构造方法,是因为每个创建的类都有一个默认的无参构造方法,如果你重写了一个带参构造方法,想要使用newInstance,则必须指定一个无参构造方法,否则会报初始化错误)

: 通过反射 ResultSet 遍历取值
 public static <T> List<T> paresList(Class<T> c , ResultSet resultSet) {
        List<T> result = new ArrayList<>();
        try {
            // 获取当前返回数据字段名
            ResultSetMetaData metaData = resultSet.getMetaData();
            // 得到当前共有多少列
            int count = metaData.getColumnCount();
            // 得到列名 装到数组中 根据返回获取get,set方法
            String[] clumnNames = new String[count];

            for (int i = 0; i < clumnNames.length; i++) {
                clumnNames[i] = metaData.getCatalogName(i+1);
            }
            Method[] methods = c.getDeclaredMethods();
            while (resultSet.next()){
                // 调取 class 无参构造方法
                T instance = c.newInstance();
                for (String name : clumnNames) {
                    name = "set" + name;
                    // 获取到返回数据 字段名
                    for (Method method : methods) {
                        // 遍历方法.
                        if (method.getName().equalsIgnoreCase(name)){
                            // 进行反射 调取方法赋值
                            method.invoke(instance,resultSet.getObject(name));
                            break;
                        }
                    }
                }
                result.add(instance);
            }
        } catch (SQLException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return result;
    }: 自定义注解 + 反射 获取执行sql 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target(value=ElementType.TYPE)
// 用于指定数据库表名称
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    String value();
}


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value=ElementType.FIELD)
//用于指定数据库的主键
@Retention(RetentionPolicy.RUNTIME)
public @interface PromaryKey {
    String value();
}

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value=ElementType.METHOD)
// 用于指定数据表的列名称
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String value();
}


//定义一个泛型类
public class BaseDao<T> {
        public <V> String add(T t) {
            /*
             * 通过userBean自动生成insert语句
             *insert into product(price,name,id) values('5000.0','iphone','1')
             */
            Class clazz =  t.getClass();//返回此 t的运行时类。
            /*通过运行实类,可以调用反射中的
            getDeclaredAnnotation(返回对象全部注解),
            getDeclaredFields(返回对象的全部属性)
            getDeclaredMethods(返回对象的全部方法)*/
            Table table = (Table) clazz.getDeclaredAnnotation(Table.class);
            String tableName = table.value();

            Map<Object, Object> columnAndValue = getColumnAndValue(clazz, t);

            //获取指定行视图和指定列中的单元格的值
            Set<Entry<Object, Object>> set = columnAndValue.entrySet();

            StringBuilder keys = new StringBuilder();
            StringBuilder values = new StringBuilder();
            for (Entry<Object, Object> entry : set) {
                if(keys.length()>0) {
                    keys.append(",");
                }
                if(values.length()>0) {
                    values.append(",");
                }
                keys.append(entry.getKey());
                values.append("'").append(entry.getValue()).append("'");

            }
            return "insert into "+tableName+"("+keys+") values("+values+")";
        }

        public String delete(T t) {
            /*
             * 通过userBean自动生成delete语句
             *
             * delete from product where id = 1
             */
            Class clazz = t.getClass();
            //获得Bean
            //获取表名称
            Table table = (Table) clazz.getDeclaredAnnotation(Table.class);
            //getDeclaredAnnotation()返回直接存在于此元素上的所有注释
            String tableName = table.value();

            Map<Object, Object> columnAndValue = getColumnAndValue(clazz, t);
            //获取指定行视图和制定列中的单元格的值
            Set<Entry<Object, Object>> set = columnAndValue.entrySet();

            List<Object> primaryKey = getPrimaryKey(clazz);

            StringBuilder keysAndvalues = new StringBuilder();
            for (Entry<Object, Object> entry : set) {

                //上面这个是我没有用PrimaryKey注解时的写法,这个写过于鸡肋,因为如果主键的name不是id就不行了
                if(primaryKey.contains(entry.getKey())){
                    keysAndvalues.append(entry.getKey()).append(" = ").append(entry.getValue());
                }
            }
            return "delete from "+tableName+" where "+keysAndvalues;
        }
        public String update(T t) {
            /*
             * 通过ProductBean自动生成update语句
             *
             * update product set price = 5000.0 and name = iphone where id = 1
             */
            Class clazz = t.getClass();
            Table table = (Table) clazz.getDeclaredAnnotation(Table.class);
            //getDeclaredAnnotation()返回直接存在于此元素上的所有注释
            String tableName = table.value();

            Map<Object, Object> columnAndValue = getColumnAndValue(clazz, t);
            //获取指定行视图和制定列中的单元格的值
            Set<Entry<Object, Object>> set = columnAndValue.entrySet();

            List<Object> primaryKey = getPrimaryKey(clazz);
            StringBuilder keysAndvalues = new StringBuilder();
            StringBuilder FkeysAndvalues = new StringBuilder();
            int i = 1;
            for(Entry<Object, Object> entry : set){
                if(primaryKey.contains(entry.getKey())){
                    FkeysAndvalues.append(" ").append(entry.getKey()).append(" = ").append(entry.getValue());

                }
                else{
                    if(1 <i && i < set.size()){
                        keysAndvalues.append(" and ");
                        keysAndvalues.append(entry.getKey()).append(" = ").append(entry.getValue());
                    }
                    else{
                        keysAndvalues.append("  ");
                        keysAndvalues.append(entry.getKey()).append(" = ").append(entry.getValue());
                        i++;
                    }
                }
            }

            return "update "+tableName + keysAndvalues + " where "+FkeysAndvalues;
        }

        public String selete(T t) {
            /*
             * 通过userBean自动生成selete语句
             *
             * selete* from product where price = 5000.0 and name = iphone and id = 1
             */
            Class clazz = t.getClass();
            //获得Bean
            //获取表名称
            Table table = (Table) clazz.getDeclaredAnnotation(Table.class);
            //getDeclaredAnnotation()返回直接存在于此元素上的所有注释
            String tableName = table.value();

            Map<Object, Object> columnAndValue = getColumnAndValue(clazz, t);
            //获取指定行视图和制定列中的单元格的值
            Set<Entry<Object, Object>> set = columnAndValue.entrySet();

            StringBuilder keysAndvalues = new StringBuilder();
            for (Entry<Object, Object> entry : set) {
                if(keysAndvalues.length()>0) {
                    keysAndvalues.append(" and ");
                }
                keysAndvalues.append(entry.getKey()).append(" = ").append(entry.getValue());
            }

            return "selete* from "+tableName+" where "+keysAndvalues;
        }

        //按照<列明,属性>的格式输出所有的单元格
        private Map<Object, Object> getColumnAndValue(Class<? extends T> clazz, T t) {
            //首先声明了一个map键值对
            Map<Object, Object> map = new HashMap<>();
            //获取clazz类的所有方法
            Method[] methods = clazz.getDeclaredMethods();
            //获取的是类自身声明的所有方法,包含public、protected和private方法
            for (Method method : methods) {
                String methodName = method.getName();
                if(methodName.startsWith("get")) {
                    //获得所有的get方法
                    Column column = method.getDeclaredAnnotation(Column.class);
                    // getDeclaredAnnotation(); //返回直接存在于此元素上的所有注释
                    //这个方法里放有参数时,返回指定类型的注解。如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
                    try {
                        map.put(column.value(), method.invoke(t));
                        //invoke执行方法
                    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                        e.printStackTrace();
                    } // TODO Auto-generated catch block

                }
            }

            return map;
        }

        private List<Object> getPrimaryKey(Class<? extends T> clazz){
            List<Object> list = new ArrayList<>();
            Field[] fields = clazz.getDeclaredFields();
            //获得某个类的所有声明字段(id,name,price)
            for (Field field : fields) {
                if(field.isAnnotationPresent(PromaryKey.class)) {
                    //Package.isAnnotationPresent()如果指定类型的注释存在于此元素上,则返回true;否则flase
                    PromaryKey primaryKey = field.getDeclaredAnnotation(PromaryKey.class);
                    try {
                        list.add(primaryKey.value());
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    }
                }
            }
            return list;
        }
}

附 集合工具类

public class CollectionUtil {

    public static <T> List<T> castList(Object obj, Class<T> clazz)
    {
        List<T> result = new ArrayList<T>();
        if(obj instanceof List<?>)
        {
            for (Object o : (List<?>) obj)
            {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }

    /**
     * 将源bean中的指定字段拷贝到目标map中
     */
    public static void copyToMap(Object srcBean, Map<String, Object> destMap, List<String> fieldNameList, List<String> keyNameList) {
        if (fieldNameList.size() != keyNameList.size()) {
            throw new RuntimeException("字段集合和key集合的个数不一致,请检查后重新传入");
        }
        if (fieldNameList.size() == 0) {
            return;
        }

        try {
            int count = fieldNameList.size();
            for (int i = 0; i < count; i++) {
                String fieldName = fieldNameList.get(i);
                String keyName = keyNameList.get(i);
                // 转换为getter方法名
                String methodName = getGetterMethodName(fieldName);

                Method method = srcBean.getClass().getMethod(methodName);
                Object value = method.invoke(srcBean);
                if (value == null) {
                    // 给value一个默认值
                    value = getDefaultValue(method.getReturnType());
                }
                destMap.put(keyName, value);
            }
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * field名称 -> getter方法名
     */
    public static String getGetterMethodName(String fieldName) {
        StringBuilder sb = new StringBuilder();
        sb.append(fieldName);
        if (Character.isLowerCase(sb.charAt(0))) {
            if (sb.length() == 1 || !Character.isUpperCase(sb.charAt(1))) {
                sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
            }
        }
        sb.insert(0, "get");
        return sb.toString();
        // return "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    }

    private static Object getDefaultValue(Class<?> objectType) {
        if (objectType.equals(String.class)) {
            return "";
        }
        return null;
    }

    //Object转Map
    public static Map<String, Object> getObjectToMap(Object obj) throws IllegalAccessException {
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        Class<?> clazz = obj.getClass();
    
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            String fieldName = field.getName();
            Object value = field.get(obj);
            if (value == null){
                value = "";
            }
            map.put(fieldName, value);
        }
        return map;
    }

    public static String getMapToString(Map<String,Object> map){
        Set<String> keySet = map.keySet();
        //将set集合转换为数组
        String[] keyArray = keySet.toArray(new String[0]);
        //给数组排序(升序)
        Arrays.sort(keyArray);
        //因为String拼接效率会很低的,所以转用StringBuilder
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keyArray.length; i++) {
            // 参数值为空,则不参与签名 这个方法trim()是去空格
            if ((String.valueOf(map.get(keyArray[i]))).trim().length() > 0) {
                sb.append(keyArray[i]).append(":").append(String.valueOf(map.get(keyArray[i])).trim());
            }
            if(i != keyArray.length-1){
                sb.append(",");
            }
        }
        return sb.toString();
    }


}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值