17

文字列型のデータを含むリストがあります->["classField1", "classField2", "classField3"]

myMethod(List list, String className)Listをパラメータとして受け入れるメソッド()があります。したがって、このリストをパラメーターを介してmyMethod(List list、String className)に渡すことができます。

myMethod、2番目のパラメータであるclassNameのインスタンスとなる1つのオブジェクトを作成します。その後、リストのデータを使用してクラスのフィールドを設定したいと思います。クラスのフィールドを動的に取得したいという事実のために、上記の結果は、リストの各文字列値をクラスの各フィールドのタイプにキャストする必要があるということです。

リスト内の文字列の順序は正しい順序であり、同じ順序でクラスのフィールドに対応していると確信しています。

誰かが上記を実行する方法を知っていますか?

例:

["StringtempValue", "StringUnitOfMeasurement"]=>

インスタンスオブジェクトを作成します。

public class TempStruct {

   private double tempValue;
   private String unitOfMeasurement;

   public TempStruct(double tempValue, String unitOfMeasurement) {
     this.tempValue = tempValue;
     this.unitOfMeasurement = unitOfMeasurement;
   }

}

私は次の方法で解決策を提供しようとします:

実は既存のクラスのオブジェクトを作りたいのですが、それをリフレクションでやってみました。私は次のコードを使用します:

Class<?> cls = Class.forName(name);
Object clsInstance = (Object) cls.newInstance();
Field[] objectFields = clsInstance.getClass().getDeclaredFields();

しかし、新しいオブジェクトを作成しようとすると、2行目に例外が発生します。@JB Nijetが言ったように、getDeclaredFields()メソッドがソートされたフィールドを返さないことを知りませんでした。

実際、私は文字列のリストのみを受け入れるメソッドを持っているので、リフレクションを使用してオブジェクトを文字列のリストに変換し、その後、逆のことをしたいと思います。私はそれをする他の方法を考えませんでした。

4

3 に答える 3

53

オブジェクトの動的インスタンス化はかなり複雑になる可能性があり、シナリオはいくつかの側面に触れます。

  • Stringオブジェクト値をから適切なタイプに変換する
  • クラス名から適切なクラスをロードし、インスタンスを作成する
  • それらの値をオブジェクトに割り当てる

これらの各ポイントを徹底的に議論することは、動的言語としてのJavaの疑いの余地のないリベットでの扱いの章全体を占めるでしょう。しかし、これらの複雑さを学ぶ時間がない、または巨大なサードパーティのライブラリに依存していると仮定して、あなたを道に連れて行く何かを作りましょう。乗り心地がでこぼこになるので、常に車内に手を入れてください。

まず、型変換の問題に取り組みましょう。値はとして提供されますが、オブジェクトはそれらを、、、などStringsとして格納します。したがって、を適切なターゲットタイプに解析する関数が必要です。doublelongintString

static Object convert(Class<?> target, String s) {
    if (target == Object.class || target == String.class || s == null) {
        return s;
    }
    if (target == Character.class || target == char.class) {
        return s.charAt(0);
    }
    if (target == Byte.class || target == byte.class) {
        return Byte.parseByte(s);
    }
    if (target == Short.class || target == short.class) {
        return Short.parseShort(s);
    }
    if (target == Integer.class || target == int.class) {
        return Integer.parseInt(s);
    }
    if (target == Long.class || target == long.class) {
        return Long.parseLong(s);
    }
    if (target == Float.class || target == float.class) {
        return Float.parseFloat(s);
    }
    if (target == Double.class || target == double.class) {
        return Double.parseDouble(s);
    }
    if (target == Boolean.class || target == boolean.class) {
        return Boolean.parseBoolean(s);
    }
    throw new IllegalArgumentException("Don't know how to convert to " + target);
}

うーん。これは醜く、組み込み型のみを処理します。しかし、私たちはここで完璧を求めているのではありませんよね?したがって、必要に応じて強化してください。Stringから他のタイプへの変換は事実上逆シリアル化の形式であるためStrings、特定の形式で値を提供するようにクライアント(を提供している人)に制約を課していることに注意してください。この場合、フォーマットはparseメソッドの動作によって定義されます。演習1:将来のある時点で、逆方向に互換性のない方法で形式を変更して、誰かの怒りを招きます。

次に、実際のインスタンス化を行いましょう。

static Object instantiate(List<String> args, String className) throws Exception {
    // Load the class.
    Class<?> clazz = Class.forName(className);

    // Search for an "appropriate" constructor.
    for (Constructor<?> ctor : clazz.getConstructors()) {
        Class<?>[] paramTypes = ctor.getParameterTypes();

        // If the arity matches, let's use it.
        if (args.size() == paramTypes.length) {

            // Convert the String arguments into the parameters' types.
            Object[] convertedArgs = new Object[args.size()];
            for (int i = 0; i < convertedArgs.length; i++) {
                convertedArgs[i] = convert(paramTypes[i], args.get(i));
            }

            // Instantiate the object with the converted arguments.
            return ctor.newInstance(convertedArgs);
        }
    }

    throw new IllegalArgumentException("Don't know how to instantiate " + className);
}

ここでは多くのショートカットを使用していますが、これは私たちが作成しているシスティーナ礼拝堂ではありません。クラスをロードし、パラメーターの数が引数の数(つまり、アリティ)と一致するコンストラクターを検索するだけです。同じアリティのコンストラクターをオーバーロードしましたか?いいえ、動作しません。Varargs?いいえ、動作しません。非公開コンストラクター?いいえ、動作しません。そして、あなたのクラスがあなたの例のようにすべてのフィールドを設定するコンストラクターを提供することを保証できない場合TempStruct、このアプローチはDOAであるため、私はそれを1日と呼び、ビールを飲みます。

コンストラクターが見つかったら、String引数をループして、コンストラクターが期待するタイプに変換します。それが機能すると仮定して、次に、反射を介してコンストラクターを呼び出し、魔法の杖を振って、abracadabraと言います。Voilà:新しいオブジェクトがあります。

非常に工夫された例で試してみましょう。

public static void main(String[] args) throws Exception {
    TempStruct ts =
        (TempStruct)instantiate(
            Arrays.asList("373.15", "Kelvin"),
            TempStruct.class.getName());

    System.out.println(
        ts.getClass().getSimpleName() + " " +
        ts.tempValue + " " +
        ts.unitOfMeasurement);
}

出力:

TempStruct 373.15 Kelvin

栄光

于 2012-12-14T03:20:48.067 に答える
3

私は以前同じ種類の問題を抱えていましたが、hashMapが解決策であることがわかりました。

チェックしてください:http: //docs.oracle.com/javase/6/docs/api/java/util/HashMap.html

于 2012-12-13T21:47:57.563 に答える
0

http://commons.apache.org/beanutils/パッケージを見てください。名前でフィールドにアクセスできます。

于 2012-12-13T22:59:44.613 に答える