4

多くの質問を読んだ後、ハードコードされたアプローチを使用せずに、文字列を一般的な数値に変換するというジレンマを解決できるかどうかを自問しました。

例: メソッドから Class With Number.isAssignableFrom 型のパラメーターを取得するか、これが数値クラスであるかどうかを確認できるその他の方法を取得します。しかし、ユーザーからの入力も得ます。文字列として。

問題は、すべてのケースに対して if ステートメントを作成せずに、この文字列を要求された数値オブジェクトに変換できるかどうかです。

コード例、正しく動作しない:

Object ret = null;

for(int i=0;i<method.getParameterTypes().length; i++ ) {
    Class<?> param = method.getParameterTypes()[i];
    String argString = getUserInput(_in, "Argument ("+param.getSimpleName()+"): ");

    if( Number.isAssignableFrom(param) )
        ret = ((Class<NumberChild>)param).valueOf(argString);
    /// OR
        ret = param.cast( Double.valueOf(argString) )
}

さらにこの質問を進めます: 上記の方法と同様の方法ですべてのプリミティブをキャストすることは可能でしょうか?

注: ここでのアプローチは、ハードコーディングされていないソリューションに完全に焦点を当てる必要があります。現在実行中のコードは、すべてのケースをハードコーディングするアプローチを使用しています。しかし、そのような場合は、より一般的な解決策の方がはるかに興味深いものになります。

編集: 誤解して申し訳ありませんが、ハードコードされたアプローチ、つまり次のようなすべての可能なケースをテストするアプローチを意味します。

 if( integer ); do ...
 if( double ); do ...
 if( long ); do ...

しかし、それはまさに、私が回避したいことです。明確にするために:これは単なる挑戦です。私の人生やコードはそれに依存していません。それが可能かどうか知りたいだけです!!

4

3 に答える 3

3

アップデート

元の回答 (以下を参照) で説明されているメソッドはプリミティブをサポートしておらず、単一のStringパラメーターを持つコンストラクターを持つクラスのみをサポートできるため、使用するパーサー メソッドをクラスごとに明示的に指定することをお勧めします。

Java 8 メソッド参照を使用すると、これがはるかに簡単になります。

ご覧のとおり、適切な解析メソッドを使用してプリミティブ値も処理できますが、このparse()メソッドは依然として を返すObjectため、プリミティブ値はボックス化されたままです。これは通常、リフレクションを通じてプリミティブを処理する場合に当てはまります。

これは縮小された例です。完全な動作例については、 IDEONEを参照してください。

private static HashMap<Class<?>, Function<String,?>> parser = new HashMap<>();
static {
    parser.put(boolean.class   , Boolean::parseBoolean); // Support boolean literals too
    parser.put(int.class       , Integer::parseInt);
    parser.put(long.class      , Long::parseLong);
    parser.put(Boolean.class   , Boolean::valueOf);
    parser.put(Integer.class   , Integer::valueOf);
    parser.put(Long.class      , Long::valueOf);
    parser.put(Double.class    , Double::valueOf);
    parser.put(Float.class     , Float::valueOf);
    parser.put(String.class    , String::valueOf);  // Handle String without special test
    parser.put(BigDecimal.class, BigDecimal::new);
    parser.put(BigInteger.class, BigInteger::new);
    parser.put(LocalDate.class , LocalDate::parse); // Java 8 time API
}

@SuppressWarnings({ "rawtypes", "unchecked" })
private static Object parse(String argString, Class param) {
    Function<String,?> func = parser.get(param);
    if (func != null)
        return func.apply(argString);
    if (param.isEnum()) // Special handling for enums
        return Enum.valueOf(param, argString);
    throw new UnsupportedOperationException("Cannot parse string to " + param.getName());
}

元の答え

(Java 7) のJavadoc にNumberは、次の「直接既知のサブクラス」がリストされており、単一のString引数を解析するためのメソッドが示されています。

ご覧のとおり、Stringパラメーターを指定してコンストラクターを使用することをお勧めします。そうすれば、BigDecimalandBigIntegerもサポートされるでしょう。

さて、方法ですが。反射を使用します。があるClassので、コンストラクターを要求して呼び出します。

Class param = /*code here*/;
String argString = /*code here*/;

Object ret;
try {
    Constructor ctor = param.getConstructor(String.class);
    ret = ctor.newInstance(argString);
} catch (ReflectiveOperationException e) {
    throw new UnsupportedOperationException("Cannot convert string to " + param.getName());
}
于 2016-04-02T02:22:32.523 に答える
0
  1. リフレクション ( example ) を使用して、クラスパスに存在する Number (Double、Integer など) のすべての既知の実装を試します。
  2. それぞれについて、静的メソッド valueOf(String) と String コンストラクターを試してください (Numberインターフェースにはありません)。
  3. Number インスタンスごとに、ユーザー入力と同等の String 表現を取得できることを確認してください。そうしないと、整数オーバーフローが発生する可能性があります。
于 2016-04-02T02:16:10.853 に答える