替代在地图中使用Object和强制转换

时间:2016-08-17 16:10:24

标签: java generics casting

我有以下类代表一组属性。

public class Properties
{
    /** String type properties. */
    private final List<String> m_stringProperties = Arrays.asList("str1", "str2", "str3");

    /** Float type properties. */
    private final List<String> m_floatProperties = Arrays.asList("float1", "float2", "float3");

    /** Integer type properties. */
    private final List<String> m_intProperties = Arrays.asList("int1", "int2");

    public class PropertyType
    {
        private final String m_name;
        private final Object m_value;

        public PropertyType(String name, Object value)
        {
            m_name = name;
            m_value = value;
        }

        public String getName()
        {
            return m_name;
        }

        public Object getValue()
        {
            return m_value;
        }
    }

    /** The container for the properties. */
    private final Map<String, PropertyType> m_properties = new HashMap<>();

    public PropertyType getProperty(String name)
    {
        return m_properties.get(name);
    }

    public void setProperty(String name, Object value)
    {
        if ((m_stringProperties.contains(name) && value instanceof String)
                || (m_floatProperties.contains(name) && value instanceof Float)
                || (m_intProperties.contains(name) && value instanceof Integer))
        {
            m_properties.put(name, new PropertyType(name, value));
        }

        else
        {
            assert false : "Invalid property name";
        }
    }
}

备注

  1. 每个属性都有一个名称和一个值。
  2. 属性值可以是String,Float或Integer类型。
  3. 属性的名称仅限于类顶部列表中定义的值。
  4. 如果给定的属性是该属性名称的正确类型,则只能将其添加到地图中。
  5. 该课程可按如下方式使用:

    Properties properties = new Properties();
    
    // set properties
    properties.setProperty("str1", "testId");
    properties.setProperty("float1", 1.0f);
    
    // get properties
    Properties.PropertyType str1 = properties.getProperty("str1");
    Properties.PropertyType float1 = properties.getProperty("float1");
    Properties.PropertyType invalid = properties.getProperty("unknown");    // return null
    
    System.out.println("str1: " + str1.getValue());
    System.out.println("float1: " + float1.getValue());
    
    float f1 = (float) properties.getProperty("float1").getValue();
    Object o1 = properties.getProperty("float1").getValue();
    
    System.out.println("f1: " + f1);
    System.out.println("o1: " + o1);
    
    properties.setProperty("str1", 1.0f);       // assertion - str1 property should be String, not Float
    

    我想知道是否有更好的方法来实现这一点。具体来说,我希望避免使用Object以及随之而来的演员表。我已经尝试了参数化类和泛型类型,甚至是有效Java第20项中描述的类型安全的异类容器。

    我想尽可能使其成为类型安全 - 即通过编译器强制执行类型检查 - 这样如果调用getProperty,则返回值将自动为正确类型。

    我意识到我可以为每种类型重载setPropertygetProperty只能返回Object而不是嵌套类型PropertyType,但这仍然会让我失望容器<String, Object>

    我是来自C ++的Java新手。在C ++中,地图值为boost::variant

1 个答案:

答案 0 :(得分:0)

为了确保该类将接收3种类型中的一种,并且编译器将使用它,您可以使用一些多态性。

示例:

public PropertyType(String name, String value)
        {
            m_name = name;
            m_value = value;
        }

 public PropertyType(String name, Integer value)
        {
            m_name = name;
            m_value = value;
        }

 public PropertyType(String name, Float value)
        {
            m_name = name;
            m_value = value;
        }

String,Integer和Float扩展了Object,因此您不需要将它们转换为变量private final Object m_value;

但是如果你需要在执行类型中检查变量的类型(例如,创建和变量,并且不知道它是否是三种类型中的一些),这可能不起作用。