オブジェクトの動的インスタンス化はかなり複雑になる可能性があり、シナリオはいくつかの側面に触れます。
String
オブジェクト値をから適切なタイプに変換する
- クラス名から適切なクラスをロードし、インスタンスを作成する
- それらの値をオブジェクトに割り当てる
これらの各ポイントを徹底的に議論することは、動的言語としてのJavaの疑いの余地のないリベットでの扱いの章全体を占めるでしょう。しかし、これらの複雑さを学ぶ時間がない、または巨大なサードパーティのライブラリに依存していると仮定して、あなたを道に連れて行く何かを作りましょう。乗り心地がでこぼこになるので、常に車内に手を入れてください。
まず、型変換の問題に取り組みましょう。値はとして提供されますが、オブジェクトはそれらを、、、などStrings
として格納します。したがって、を適切なターゲットタイプに解析する関数が必要です。double
long
int
String
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
栄光