一种Java通用的FeatureMap存取设计

本文介绍了一种在Java中使用Map存储任意类型对象的方法,并通过泛型改进代码以提高类型安全性。同时,提出了一种键值封装方案及类型校验机制,确保数据一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、map存取任意对象

  首先,定义map对象,将map的value类型指定为Object,它可以存储任意基础类型或自定义类型的值对象。由于值类型为Object,在读取map元素时,往往需要将值强制转换为需要的类型。其实,可以返回值类型为范型优化代码,将类型转换前置到get方法中,如下:

/**
 * Created by Jerry on 17/7/22.
 */
public class CoMap {

    private Map<String, Object> coMap = new HashMap<String, Object>();

    public void putObj(String key, Object value){
        coMap.put(key, value);
    }

    public <T> T getObj(String key) {
        try {
            return (T) coMap.get(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

CoMap存取任意对象的测试代码如下:

/**
 * Created by Jerry on 17/7/19.
 */
public class Test {

    private String field1;

    private Integer field2;

    Test(String field1, Integer field2) {
        this.field1 = field1;
        this.field2 = field2;
    }

    public String getField1() {
        return field1;
    }

    public void setField1(String field1) {
        this.field1 = field1;
    }

    public Integer getField2() {
        return field2;
    }

    public void setField2(Integer field2) {
        this.field2 = field2;
    }

    public static void main(String [] args) {
        CoMap coMap = new CoMap();

        coMap.putObj("a", 123);
        coMap.putObj("b", 123.456);
        coMap.putObj("c", "aaa");
        coMap.putObj("d", Lists.newArrayList(1, 2, 3));
        coMap.putObj("e", new String [] {"mmm", "nnn", "kkk"});
        coMap.putObj("f", Sets.newHashSet("yyyy", "mm", "dd"));
        coMap.putObj("g", new Test("test", 123));

        Integer a = coMap.getObj("a");
        System.out.println(a);
        Double b = coMap.getObj("b");
        System.out.println(b);
        String c = coMap.getObj("c");
        System.out.println(c);
        List d = coMap.getObj("d");
        System.out.println(JSON.toJSONString(d));
        String [] e = coMap.getObj("e");
        System.out.println(JSON.toJSONString(e));
        Set f = coMap.getObj("f");
        System.out.println(JSON.toJSONString(f));
        Test g = coMap.getObj("g");
        System.out.println(JSON.toJSONString(g));
    }
}

结果:
123
123.456
aaa
[1,2,3]
["mmm","nnn","kkk"]
["yyyy","mm","dd"]
{"field1":"test","field2":123}
  • 说明
    • 1.CoMap对键值(key)没有进行良好封装,增加了数据读取的困难度
    • 2.CoMap没有对返回值(value)进行类型判断,这可能在数据强制类型转换时出现“java.lang.ClassCastException”异常
    • 3.getObj(String key)方法虽然有try-catch块,但却无法捕获数据强制转换导致的“java.lang.ClassCastException”异常

二、通用FeatureMap存取设计

  基于以上CoMap存在的问题,对该CoMap类进行优化,主要在两方面:1.对map键值进行封装;2.对返回值进行类型校验。该设计可用于通用FeatureMap的存取。

  • 2.1 key封装

      定义Field类,用于封装key,该处主要针对数据库Feature存储,所以将key定义为整形,valueClass用于在输入时做数据类型校验,保证存储的数据为Field指定类型。

//**
 * Created by Jerry on 17/7/19.
 */
public class Field implements Serializable {
    private static final long serialVersionUID = 2025270001756934102L;
    private int key;
    private Class valueClass;

    Field(int key, Class valueClass) {
        this.key = key;
        this.valueClass = valueClass;
    }

    public String getKeyStr() {
        return String.valueOf(this.key);
    }

    public int getKey() {
        return this.key;
    }

    public Class getValueClass() {
        return valueClass;
    }
}

  属性Field定义后,可进行Schema定义,Schema中约定最终用于数据存取的key,Schema的定义采用单例实现。

/**
 * Created by Jerry on 17/7/23.
 */
public class TestSchema {

    private Field feature1;

    private Field feature2;

    private Field feature3;

    private Field feature4;

    private static final TestSchema INSTANCE = new TestSchema();

    private TestSchema() {
        feature1 = new Field(1, Date.class);
        feature2 = new Field(2, Long.class);
        feature3 = new Field(3, String.class);
        feature4 = new Field(4, Test.class);
    }

    public static TestSchema getInstance() {
        return INSTANCE;
    }

    public Field getFeature1() {
        return feature1;
    }

    public Field getFeature2() {
        return feature2;
    }

    public Field getFeature3() {
        return feature3;
    }

    public Field getFeature4() {
        return feature4;
    }
}
  • 2.2 存取数据校验

      第一部分在getObj方法中有捕获数据转换错误的代码块,但代码实际执行过程中,try-catch块无法捕获该处的“java.lang.ClassCastException”异常,这是因为在getObj方法中,范型的类型已经被擦除,该处的强制转换可以避免编译错误,但数据类型的真正转换却不发生在该处,而是在给调用方返回赋值的时候,因此第一部分测试代码如果返回值类型指定错误仍然会抛出异常。
      对getObj和getField方法进行优化,将返回值类型的类信息作为参数,在数据返回前对返回值类型进行校验。
      此外,对setField方法也进行优化,校验存储数据是否为Field指定数据类型。

/**
 * Created by Jerry on 17/7/22.
 */
public class CoMap {

    private Map<String, Object> coMap = new HashMap<String, Object>();

    public void putObj(String key, Object value){
        coMap.put(key, value);
    }

    public <T> T getObj(String key, Class<T> clazz) {
        if (clazz.isInstance(coMap.get(key)) == false) {
            System.out.println("return type is wrong");
            return null;
        }
        return (T) coMap.get(key);
    }

    public <T> void setField(Field field, T value) {
        // 校验输入数据类型是否为field指定数据类型
        if(field.getValueClass().isInstance(value) == false) {
            System.out.println("value type is wrong");
            return ;
        }

        coMap.put(field.getKeyStr(), value);
    }

    /**
     * 获取数据,如果数据类型与返回值类型不匹配,则:ClassCastException,该异常在会在调用方赋值时抛出,无法在方法内捕获
     * @param field
     * @param <T>
     * @return
     */
    public <T> T getField(Field field) {
        // try catch 无法捕获类型转换异常,因为类型已擦除
        return (T) coMap.get(field.getKeyStr());
    }

    /**
     * 获取数据,校验数据类型与返回值类型是否匹配
     * @param field
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T getField(Field field, Class<T> clazz) {
        if (clazz.isInstance(coMap.get(field.getKeyStr())) == false) {
            System.out.println("return type is wrong");
            return null;
        }
        return (T) coMap.get(field.getKeyStr());
    }
}

测试代码如下:

/**
 * Created by Jerry on 17/7/19.
 */
public class Test {

    private String field1;

    private Integer field2;

    Test(String field1, Integer field2) {
        this.field1 = field1;
        this.field2 = field2;
    }

    public String getField1() {
        return field1;
    }

    public void setField1(String field1) {
        this.field1 = field1;
    }

    public Integer getField2() {
        return field2;
    }

    public void setField2(Integer field2) {
        this.field2 = field2;
    }

    public static void main(String [] args) {
        CoMap coMap = new CoMap();

        coMap.setField(TestSchema.getInstance().getFeature1(), 123);
        coMap.setField(TestSchema.getInstance().getFeature1(), new Date());
        coMap.setField(TestSchema.getInstance().getFeature2(), 123L);
        coMap.setField(TestSchema.getInstance().getFeature3(), "abc");
        coMap.setField(TestSchema.getInstance().getFeature4(), new Test("test", 123));

        Date f1 = coMap.getField(TestSchema.getInstance().getFeature1(), Date.class);
        System.out.println(f1);
        Long f2 = coMap.getField(TestSchema.getInstance().getFeature2(), Long.class);
        System.out.println(f2);
        String f3 = coMap.getField(TestSchema.getInstance().getFeature3(), String.class);
        System.out.println(f3);
        Test f4 = coMap.getField(TestSchema.getInstance().getFeature4(), Test.class);
        System.out.println(JSON.toJSONString(f4));
        String f4_1 = coMap.getField(TestSchema.getInstance().getFeature4(), String.class);
    }
}


结果:
value type is wrong
Sun Jul 23 16:39:59 CST 2017
123
abc
{"field1":"test","field2":123}
return type is wrong
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值