2009-08-15 23 views
3

ContentValuesに入れられる名前と値を渡すことができる関数を作成しようとしています。私が抱えている問題は、一度に複数のキー/値ペアを渡すことを許可しようとしているため、キーは文字列の配列になることができますが、値はオブジェクトでなければならず、ContentValues.put()オブジェクトを許可するには、String、Double、Floatなどにキャストする必要があります。オブジェクトの型を判別してキャストして正しいput()を呼び出す方法はありますか?以下は動作する1つのメソッドですが、可能なすべての型の値にifを追加する必要があります。オーバーロードされたメソッドのJava動的キャスト

public long create(String[] names, Object[] values) { 
     ContentValues initialValues = new ContentValues(); 

     for (int i = 0; i < names.length; i++) 
     { 
      String type = values[i].getClass().getName(); 
      if (type.equals("java.lang.Double")) 
      { 
       initialValues.put(names[i], (Double)values[i]); 
      } 
      else if (type.equals("java.lang.String")) { 
       initialValues.put(names[i], (String)values[i]); 
      } 
      else 
      { 
       throw new InvalidParameterException("Unable to convert type:"+type); 
      } 
     } 

     return mDb.insert(this.getTableName(), null, initialValues); 
    } 
+0

Java5を使用できますか? – dfa

+0

私はアンドロイドのために書いています。私が知っている限り、Java5を使っていますが、私はJavaを初めて使い慣れているので、その確認方法はわかりません。 –

答えて

3

あなたのアプローチは正しいですが、getClass().getName()の代わりにinstanceofを使用してください。すなわち:

if (values[i] == null) { 
    initialValues.putNull(names[i]); 
} else if (values[i] instanceof Boolean) { 
    initialValues.put(names[i], (Boolean)values[i]); 
} else if (values[i] instanceof Byte) { 
    initialValues.put(names[i], (Byte)values[i]); 
} else if (values[i] instanceof Double) { 
    initialValues.put(names[i], (Double)values[i]); 
} else if (values[i] instanceof Float) { 
    initialValues.put(names[i], (Float)values[i]); 
} else if (values[i] instanceof Integer) { 
    initialValues.put(names[i], (Integer)values[i]); 
} else if (values[i] instanceof Long) { 
    initialValues.put(names[i], (Long)values[i]); 
} else if (values[i] instanceof Short) { 
    initialValues.put(names[i], (Short)values[i]); 
} else if (values[i] instanceof String) { 
    initialValues.put(names[i], (String)values[i]); 
} else if (values[i] instanceof byte[]) { 
    initialValues.put(names[i], (byte[])values[i]); 
} else if (values[i] instanceof ContentValues) { 
    initialValues.putAll(names[i], (ContentValues)values[i]); 
} else { 
    throw new IllegalArgumentException(
     "can't put " + values[i].getClass().getName() + " in ContentValues."); 
} 

もう1つのオプションは反射を使用することですが、反射は最後の手段であると考えています。

ContentValuesfinalでない場合は、それを拡張してObjectのメソッドを追加することもできます。

+0

なぜあなたはリフレクションを最後の手段と考えていますか?それは私には良い方法のように見えます。 –

+0

@Asa:高すぎます。 –

+0

なぜinstanceofを使用していますか?プリミティブのラッパーは常に最終的です。サブクラスを確認する必要はありません – dfa

2

次の2つのオプションがあります。

  1. をあなたがやっているようであれば、他のブロックのリストを作成します。あなたがそうするなら、私はそのようにはしません。代わりに "ob instanceof String"を実行します。渡されたタイプのための正しい方法を見つけるか、
  2. 使用反射。

一つ考慮すべき事はNULL値です。 valueに渡された値がnullの場合、クラスは存在しません。したがって、型に関係する場合は型を判別できません。

+0

なぜinstanceofを使用していますか?プリミティブのラッパーは常に最終的です。サブクラスを確認する必要はありません – dfa

+0

この場合、instanceofはString.equals()呼び出しより速くなければなりません。一般的に、すべてのタイプが最終的であるとは想定できません。実際、クラスローダーが関与している場合、クラス名を比較するだけではクラスを区別することができません。 –

+0

instanceofの代わりにプリミティブに対して(object.getClass()== String.class)を実行することもできます。それは.equals()の代わりに暗黙のうちのものかもしれません。 – Robin

0

おそらくContentValuesは、あなたが書こうとしている行に沿ってputObject()メソッドを提供しているはずです。私はContentValueをそのメソッドを提供するクラスで拡張するか、そうでなければラップして、コードを再利用可能にする傾向があります。

あなたが使用しているif/elseアプローチでは、嫌な思いがするかもしれませんが、あなたが意味することを明示し、シンプルで保守可能なコードの作成が優先事項です。反射を使用することも可能ですが、実装するのがより複雑になります。私はあなたがしていることに固執します。

1

これはあなたが作ることができるように、きれいで効率的で正しいです。コンパイラが型キャストを最適化できる可能性はありますが、それほど重要ではありません。

public long create(String[] names, Object[] values) { 
    ContentValues initialValues = new ContentValues(); 
    for (int i = 0; i < names.length; i++) { 
     Object v = values[i]; 
     if (v instanceof Double) { 
      initialValues.put(names[i], (Double) v); 
     } else if (v instanceof String) { 
      initialValues.put(names[i], (String) v); 
     } else { 
      // You could test for v == null here ... otherwise you'll 
      // get an NPE 
      throw new InvalidParameterException(
        "Unable to convert type: " + v.getClass()); 
     } 
    } 
    return mDb.insert(this.getTableName(), null, initialValues); 
} 

いくつかの注意:

  1. EDIT:一般的には、おそらくより多くのあなたがC」のためにテストする可能性が高いまたはサブクラスの正確なクラスCのためにテストする必要はありませんC "となる。クラス名を使ってこれをテストすることはできません。これにはinstanceofを使用してください。
  2. クラス名をテストする場合は、正しいクラス名を使用するようにしてください。たとえば、Double.class.getName()は、実際には"java/lang/Double"ではなく、"java.lang.Double"です。
  3. instanceofよりも遅いだけでなく、クラス名を比較しても正しい答えが得られるとは限りません。何かがクラスローダーのトリックをしている場合、異なるクラスはgetName()getCanonicalName()によって報告されたものと同じ名前を持つことができます。
  4. このようなものに反射を使用しないようにしてください。必然的に遅くなり、コンパイラは多くの間違いを拾うことができなくなります。
関連する問題