反射与java简单类

1. 单级属性

针对反射和简单Java类在实际项目中的设计意义

简单Java类最大的特点是只进行数据的存储 , 不对数据做复杂的操作

a. 实现思路

1563931206121.png

b. 代码结构

1563932264296.png

c. 数据类型

1563934325923.png

d. 代码

1563935859137.png
  1. 主方法

    import com.Dept;
    import com.Emp;
    import util.InputData;
    import util.reflect.ObjectInstanceFactory;
    
    public class Main {
    
        public static void main(String[] args) throws Exception {
            Emp emp = ObjectInstanceFactory.create(Emp.class, InputData.input());
            Dept dept = ObjectInstanceFactory.create(Dept.class, InputData.inputDept());
            System.out.println(emp);
            System.out.println(dept);
        }
    }
    
    
  1. ObjectInstanceFactory

    package util.reflect;
    
    import java.util.Map;
    
    public class ObjectInstanceFactory {
    
        private ObjectInstanceFactory() {
        }
    
        /**
         * 根据传入的Class类型获取实例化对象,同时可以将传入的属性进行赋值(错误的属性不复制)
         *
         * @param clazz  要进行实例化的简单java类型
         * @param values 包含输入的数据 , key必须和属性名相同
         * @param <T>    带有属性内容的简答java类对象
         * @return
         */
        public static <T> T create(Class<T> clazz, Map<String, String> values) {
            T object = null;
            try {
                // 1. 调用无参构造方法对类实例化
                object = clazz.getDeclaredConstructor().newInstance();
                // 2. 用发射处理内容
                BeanUtil.setValue(object, values);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return object;
        }
    }
    
    
  1. BeanUtil

    package util.reflect;
    
    import util.StringUtil;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Iterator;
    import java.util.Map;
    
    public class BeanUtil {
    
        private BeanUtil() {
        }
    
        public static void setValue(Object object, Map<String, String> values) {
            Iterator<Map.Entry<String, String>> iterator = values.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, String> entry = iterator.next();//获取每组数据
                try { // 防止某些成员输入错误
                    Field field = object.getClass().getDeclaredField(entry.getKey());
                    Method method = object.
                            getClass().
                            getDeclaredMethod("set" +
                                    StringUtil.initcap(entry.getKey()), field.getType());
                    method.invoke(object, converValue(entry.getValue(), field));
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
            }
        }
    
        /**
         * 实现字符串向指定数据类型转换
         *
         * @param value 接受字符串的数据内容
         * @param field 目标类型
         * @return 结果
         */
        private static Object converValue(String value, Field field) {
            String fieldName = field.getType().getName();
            if (String.class.getName().equalsIgnoreCase(fieldName)) {
                return value;
            }
            if (int.class.getName().equalsIgnoreCase(fieldName) || Integer.class.getName().equalsIgnoreCase(fieldName)) {
                try {
                    return Integer.parseInt(value);
                } catch (Exception e) {
                    return 0;
                }
            }
            if (long.class.getName().equalsIgnoreCase(fieldName) || Long.class.getName().equalsIgnoreCase(fieldName)) {
                try {
                    return Long.parseLong(value);
                } catch (Exception e) {
                    return 0;
                }
            }
    
            if (double.class.getName().equalsIgnoreCase(fieldName) || Double.class.getName().equalsIgnoreCase(fieldName)) {
                try {
                    return Double.parseDouble(value);
                } catch (Exception e) {
                    return 0;
                }
            }
    
            if (Date.class.getName().equalsIgnoreCase(fieldName)) {
                if (value == null || "".equalsIgnoreCase(value)) {
                    return null;
                } else {
                    SimpleDateFormat simpleDateFormat = null;
                    if (value.matches("\\d{4}-\\d{2}-\\d{2}")) {
                        simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                    } else if (value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) {
                        simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    }
                    try {
                        return simpleDateFormat.parse(value);
                    } catch (Exception e) {
                        return null;
                    }
                }
            }
    
            return null;
        }
    }
    
    
  1. StringUtil

    package util;
    
    public class StringUtil {
        private StringUtil() {
        }
    
        public static String initcap(String name) {
            return name.substring(0, 1).toUpperCase() + name.substring(1);
        }
    }
    
    
  1. Bean

    package com;
    
    import java.util.Date;
    
    public class Emp {
        private String name;
        private int age;
        private Integer code;
        private Double sal;
        private Date birthday;
    
        //setter/gettter/toString方法...
    }
    
    
  1. InputData

    package util;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class InputData {
        private InputData() {
        }
    
        public static Map input() {
            Map<String, String> map = new HashMap<>();
            map.put("name", "luke");
            map.put("age", "28");
            map.put("code", "193829");
            map.put("sal", "3900.88");
            map.put("birthday", "1992-05-07 08:30:01");
            return map;
        }
    
        public static Map inputDept() {
            Map<String, String> map = new HashMap<>();
            map.put("name", "luke");
            map.put("office", "28");
            return map;
        }
    }
    
    

2. 多级属性

a. 关系图

在一些时候也可能类中的属性引用的其他引用类型 , 假设下列关系如下

  • Emp : 雇员
    • Dept : 部门
      • Company : 公司


        1563936616641.png
1563936993946.png

b. 代码

所以要想完成后续的所有设计 , 那么就必须考虑当前类对象实例化问题 , 级联的对象必须实例化 , 在一个简单Java类复制的过程中只能实例化一次 , 并且要有无参构造方法

修改 : BeanUtil 的 setValue 方法

public static void setValue(Object object, Map<String, String> values) {
    Iterator<Map.Entry<String, String>> iterator = values.entrySet().iterator();
    while (iterator.hasNext()) {

        Map.Entry<String, String> entry = iterator.next();//获取每组数据
        String fieldKey;
        Object currentObject = object;// 设置一个当前的操作对象(后面还会不停的修改其引用)
        try {

            if (entry.getKey().contains(".")) { // 如果有点则表示会出现级联关系

                // 依据"."进行拆分处理, 而后以此判断, 如果发现getter方法调用返回的是null, 则利用setter实例化级联对象
                String[] fieldSplit = entry.getKey().split("\\."); // 特别注意这个转义符
                for (int i = 0; i < fieldSplit.length - 1; i++) { // 循环每一个属性 不看最后一个 因为最后一个不需要实例化
                    // 获取get方法
                    Method getMethod = currentObject.getClass().getDeclaredMethod("get" + StringUtil.initcap(fieldSplit[i]));
                    // 使用get犯法
                    Object tempReturn = getMethod.invoke(currentObject);// 获取返回值
                    // 获取到null对象
                    if (tempReturn == null) {//如果当前的对象没有被实例化,应该调用setter设置内容
                        Class<?> currentType = currentObject.getClass().getDeclaredField(fieldSplit[i]).getType();
                        // 获取set方法
                        Method setMethod = currentObject.getClass().getDeclaredMethod("set" + StringUtil.initcap(fieldSplit[i]), currentType);
                        // 实例化该对象
                        tempReturn = currentType.getDeclaredConstructor().newInstance();
                        // 使用set方法
                        setMethod.invoke(currentObject, tempReturn);
                    }
                    // 切换实例化对象为当前对象
                    currentObject = tempReturn;
                }
                // 获取属性名
                fieldKey = entry.getKey().substring(entry.getKey().lastIndexOf(".") + 1); // 截取属性名 ( 例如 emp.conpany.cname 最后一个cname一定是一个普通数据类型)

            } else { // 如果没有级联属性
                // 获取属性名
                fieldKey = entry.getKey();
            }
            // 获取当前对象需要写入的属性
            Field field = currentObject.getClass().getDeclaredField(fieldKey);
            // 获取当前对象需要写入属性的set方法
            Method setethod = currentObject.getClass().getDeclaredMethod("set" + StringUtil.initcap(fieldKey), field.getType());
            // 使用set方法
            setethod.invoke(currentObject, converValue(entry.getValue(), field));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

增加 : 实体类

  1. Emp

    package com;
    
    import java.util.Date;
    
    public class Emp {
        private String name;
        private int age;
        private Integer code;
        private Double sal;
        private Date birthday;
        private Dept dept;
    
     //setter/gettter/toString方法...
    }
    
  1. Dept

    package com;
    
    public class Dept {
        private String name;
        private String office;
        private Company company;
    
     //setter/gettter/toString方法...
    }
    
  1. Company

    package com;
    
    public class Company {
        private String name ;
        private String loc;
    
        //setter/gettter/toString方法...
    }
    

修改输入结构 : InputData

package util;

import java.util.HashMap;
import java.util.Map;

public class InputData {
    private InputData() {
    }

    public static Map input() {
        Map<String, String> map = new HashMap<>();
        map.put("name", "luke");
        map.put("age", "28");
        map.put("code", "193829");
        map.put("sal", "3900.88");
        map.put("dept.office", "7楼办公室");
        map.put("dept.name", "软件部门");
        map.put("dept.company.loc", "火星98号坑");
        map.put("dept.company.name", "火星研究所");
        return map;
    }
}

主方法运行 :

import com.Emp;
import util.InputData;
import util.reflect.ObjectInstanceFactory;

public class Main {

    public static void main(String[] args) throws Exception {
        Emp emp = ObjectInstanceFactory.create(Emp.class, InputData.input());
        System.out.println(emp);
        System.out.println(emp.getDept());
        System.out.println(emp.getDept().getCompany());
    }
}

运行结构 :

Emp{name='luke', age=28, code=193829, sal=3900.88, birthday=null, dept=Dept{name='软件部门', office='7楼办公室', company=Company{name='火星研究所', loc='火星98号坑'}}}
Dept{name='软件部门', office='7楼办公室', company=Company{name='火星研究所', loc='火星98号坑'}}
Company{name='火星研究所', loc='火星98号坑'}
1563931206121.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 本文包括:1、Listener简介2、Servlet监听器3、监听三个域对象创建和销毁的事件监听器4、监听三个域对...
    廖少少阅读 5,892评论 6 28
  • 50道经典Java编程练习题,将数学思维运用到编程中来。抱歉哈找不到文章的原贴了,有冒犯的麻烦知会声哈~ 1.指数...
    OSET我要编程阅读 6,693评论 0 9
  • org.springframework.beans: org.springframework.beans.fact...
    过河卒sc阅读 557评论 1 1
  • 主要积累一些开发中比较 常用的工具类,部分借鉴于网络,主要来源于平时开发因需求而生的小工具类 13、ArithUt...
    大鸭梨leepear阅读 651评论 0 1
  • Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和...
    Java小辰阅读 920评论 0 5