3

我有一堂课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 作为反序列化器来获取一个列表,然后每个数据对象可以是异构
的也可以注册适配器以进行浮点和长检测,但它不会更快或更好

编辑: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

4 回答 4

12

泛型的重点是不允许一个类同时使用不同的类型。

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

泛型背后的想法是消除强制转换的需要。

在你的类中使用泛型应该会产生如下结果:

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();

您应该使用对象和强制转换——或者——使用泛型来避免强制转换。

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

这是不正确的。

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


还...

要从 double 创建 long,请使用Double.longValue()

要从双精度数创建浮点数,请使用Double.floatValue()

我建议阅读文档

于 2012-07-09T20:11:39.027 回答
1

The design looks suspicious to me, but to answer your actual question:

The case for Long-values looks wrong. Your snippet contains a c&p error

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

thus it should read:

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

However, in order to reduce code duplication, you could introduce a generic helper method

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);
}

If you decide to go for that approach, I'd recommend to de-generify the data class since it's irritating to have a type parameter if there is actually no constraint on the instance itself. I'd use Object instead for the field type:

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 ..
于 2012-07-09T20:39:50.927 回答
0

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

private T value;
.
.
.
public Object getValueAsObjectOfClass(Class<?> expectedClass) {
    if(!expectedClass.isAssignableFrom(value.getClass())) {
        // abort gracefully
    }
    return expectedClass.cast(value);
}
于 2012-07-09T19:47:59.017 回答
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));
    }
}
于 2012-07-09T19:44:29.830 回答