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を使用しており、リストを取得するために、各データオブジェクトは異種になります。float
およびlong検出用のアダプターを登録することもできますが、高速または優れたものではありません。

編集:gsonはlongの取得に失敗します:

また:

 ((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からfloatを作成するには、Double.floatValue()を使用します。

ドキュメントを読むことをお勧めします。

于 2012-07-09T20:11:39.027 に答える
1

デザインは私には疑わしいように見えますが、あなたの実際の質問に答えるために:

Long-valuesの場合は間違っているように見えます。スニペットにc&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);
}

そのアプローチを採用する場合は、インスタンス自体に実際に制約がない場合に型パラメーターを設定するのは面倒なので、データクラスを非生成化することをお勧めします。フィールドタイプの代わりにオブジェクトを使用します。

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

単純なゲッターにはタイプTを直接使用し、他のタイプには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 に答える
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 に答える