Java - 泛型与投射对象

时间:2012-07-09 19:25:31

标签: java generics casting gson type-inference

我有一个班级Data<T>

具有通用属性

private T value;

有更好的方法可以做到以下几点吗? 即以不同的形式返回泛型类型?

public List<String> getValues() {
    if (value.getClass() != ArrayList.class)
        throw new Exception("Wrong Enum value '%s'", value);
    return (ArrayList<String>) value;
    //ugly
}


public String getStringValue() {
    if (value.getClass() != String.class)
        throw new Exception("Wrong value type '%s'", value);
    return (String) value;
    //ugly
}

public Float getFloatValue() {
    if (value.getClass() != Double.class)
        throw new Exception("Wrong value type '%s'", value);
    return (Float) value;
    //ugly
}

public Long getLongValue() {
    if (value.getClass() != Double.class)
        throw new Exception("Wrong value type '%s'", value);
    return (Long) value;
    //ugly
}
public T getValue() {
    return value;
}

精确,我使用Gson作为反序列化器来获取List,每个Data对象都可以是异类的 也可以注册适配器进行浮动和长时间检测,但它不会更快或更好

编辑:gson无法检索多头:

 ((Long) d.getValue())

java.lang.Double无法强制转换为java.lang.Long

Long.parseLong( d.getValue().toString())

java.lang.NumberFormatException:对于输入字符串:“212231.0”

我尝试注册LongAdpater

gsonBuilder.registerTypeAdapter(Long.class, new LongAdapter());

private static class LongAdapter implements 
    JsonSerializer<Long>, JsonDeserializer<Long> 
{

    @Override public Long deserialize(
            JsonElement json, 
            Type type,
            JsonDeserializationContext arg2) throws JsonParseException 
    {
        return json.getAsLong();
    }

    @Override
    public JsonElement serialize(Long l, Type arg1,
            JsonSerializationContext arg2) {
        return new JsonPrimitive(new Double(l));
    }
}

java.lang.IllegalArgumentException:无法为类java.lang.Long注册类型适配器

tsOverflow的

edit2

Data<Float> d1 = new Data<Float>( new Float(6.32));
List<String> l = new ArrayList<String>();
    l.add("fr");
    l.add("it");
    l.add("en");
Data<List<String>> d2 = new Data<List<String>>( l);
Data<Long> d3 = new Data<Long>(new Long(212231));

List<Data> data = new ArrayList<Data>();
    data.add(d1);
    data.add(d2);
    data.add(d3)

new Gson().toJson(data);

4 个答案:

答案 0 :(得分:11)

泛型的要点是 NOT ,以允许类同时使用不同的类型。

泛型允许您定义/限制对象的实例所使用的类型。

泛型背后的想法是消除投射的必要性。

在类中使用泛型应该会产生如下内容:

Data<String> stringData = new Data<String>();
String someString = stringData.getValue();

Data<Long> longData = new Data<Long>();
Long someLong = longData.getValue();

Data<List<String>> listData = new Data<List<String>>();
List<String> someList = listData.getValue();

你应该使用 Objects 并强制转换 - OR - 使用泛型来避免强制转换。

您似乎相信泛型允许在同一实例中进行异构键入。

这是不正确的。

如果您希望列表包含混合类型的包,则泛型不合适。


也...

要从双人创建长片,请使用Double.longValue()

要从double创建一个浮点数,请使用Double.floatValue()

我建议阅读the documentation

答案 1 :(得分:1)

这个设计看起来很可疑,但要回答你的实际问题:

Long-values的情况看起来不对。您的代码段包含c&amp; p错误

public Long getLongValue() {
    if (value.getClass() != Double.class) // <<- should be Long.class
        throw new Exception("Wrong value type '%s'", value);
    return (Long) value;
    //ugly
}

因此它应该是:

public Long getLongValue() {
    if (value.getClass() != Long.class)
        throw new Exception("Wrong value type '%s'", value);
    return (Long) value;
    //ugly
}

但是,为了减少代码重复,您可以引入一个通用的帮助方法

private T getValue() {
    return value;
}

private <V> V castValue(Class<V> type) {
  if (!type.isInstance(value)) {
    // exception handling
  }
  return type.cast(value);
}

public List<String> getValues() {
    return castValue(ArrayList.class);
}

public String getStringValue() {
    return castValue(String.class);
}

如果您决定采用这种方法,我建议对数据类进行反生成,因为如果对实例本身实际上没有约束,那么有一个类型参数是令人恼火的。我会使用Object代替字段类型:

private Object getValue() {
    return value;
}

private <V> V castValue(Class<V> type) {
  if (!type.isInstance(value)) {
    // exception handling
  }
  return type.cast(value);
}

public List<String> getValues() {
    return castValue(ArrayList.class);
}

public String getStringValue() {
    return castValue(String.class);
}
// .. more cases ..

答案 2 :(得分:0)

您可以直接将类型T用于简单的getter,并将Class.cast - 方法用于其他类型:

public class GenericDataTest
{
    private static class DataTest<T>
    {
        private T value;

        public DataTest(T value)
        {
            this.value = value;
        }

        public T getValue()
        {
            return value;
        }

        public Object getValueAsType(Class<?> type)
        {
            return type.cast(value);
        }
    }

    @Test
    public void testGeneric()
    {
        DataTest<String> stringTest = new DataTest<String>("Test");
        Assert.assertEquals("Test", stringTest.getValue());
        Assert.assertEquals("Test", stringTest.getValueAsType(String.class));

        DataTest<Double> doubleTest = new DataTest<Double>(1.0);
        Assert.assertEquals(1.0, doubleTest.getValue());
        Assert.assertEquals(1.0, doubleTest.getValueAsType(Double.class));
    }

    @Test(expected = ClassCastException.class)
    public void testClassCastFailure()
    {
        DataTest<String> stringTest = new DataTest<String>("Test");
        Assert.assertEquals("Test", stringTest.getValueAsType(Float.class));
    }
}

答案 3 :(得分:0)

您可以询问是否可以将“值”分配给预期的类。

private T value;
.
.
.
public Object getValueAsObjectOfClass(Class<?> expectedClass) {
    if(!expectedClass.isAssignableFrom(value.getClass())) {
        // abort gracefully
    }
    return expectedClass.cast(value);
}