web-dev-qa-db-ja.com

Javaメソッドの動的な戻り値の型

ここでこれに似た質問を何度も見ましたが、大きな違いが1つあります。

他の質問では、戻り値の型はパラメーターによって決定されます。私がしたい/する必要があるのは、byte[]の解析された値によって戻り値の型を決定することです。私が集めたものから、以下がうまくいく可能性があります:

public Comparable getParam(String param, byte[] data) {
    if(param.equals("some boolean variable")
        return data[0] != 0;
    else(param.equals("some float variable") {
        //create a new float, f, from some 4 bytes in data
        return f;
    }
    return null;
}

私は何かを台無しにする前にこれが機能する可能性があることを確認したいだけです。前もって感謝します。

13
Jon Egeland

できません。 Java戻り値の型は、固定の基本型またはオブジェクトクラスのいずれかである必要があります。可能な最善の方法は、さまざまな可能な型の値をフェッチするメソッドを持つラッパー型を返すことです。 、およびどちらが有効かを示す内部列挙型。

---編集---ダニエスの訂正後!

public <Any> Any getParam(boolean b){
return((Any)((Boolean)(!b)));
}
public <Any> Any getParam(float a) {
 return((Any)((Float)(a+1)));
}
public <Any> Any getParam(Object b) {
 return((Any)b);
}
public void test(){
  boolean foo = getParam(true);
  float bar = getParam(1.0f);
  float mumble = getParam(this); // will get a class cast exception
}

ボクシングアイテムと型チェックの戻り値には引き続きいくつかのペナルティが発生します。もちろん、呼び出しがgetParamの実装が実際に行うことと一致しない場合は、クラスキャスト例外が発生します。

13
ddyer

これ[〜#〜] can [〜#〜]実行できます。次のコードが機能します。

public byte BOOLEAN = 1;
public byte FLOAT = 2;
public static <Any> Any getParam(byte[] data) {
    if (data[0] == BOOLEAN) {
        return (Any)((Boolean)(boolean)(data[1] != 0));
    } else if (data[0] == FLOAT) {
        return (Any)((Float)(float)data[1]);
    } else {
        return null;
    }
}

戻り値の型にジェネリックを使用することにより、any Javaメソッドは任意のオブジェクトまたはプリミティブ型を動的に返すことができます。ジェネリックには任意の名前を付けることができ、この場合は「Any」と呼びます。このコードは、メソッドが呼び出されたときに戻り値の型をキャストしないようにします。次のようなメソッドを使用します。

byte[] data = new byte[] { 1, 5 };
boolean b = getParam(data);
data = new byte[] { 2, 5 };
float f = getParam(data);

このトリックなしでできる最善のことは、オブジェクトを手動でキャストすることです。

float f = (float)getParam(data);

Javaの動的戻り値の型は、定型コードを減らすことができます。

22
Danieth

私はこれらの人々が何について話しているのか分かりません。懸念される型安全性を失いますが、ジェネリックスでこれを簡単に達成できます...次のようなものです。

public <T> T getSomething(...) { }

または

interface Wrapper<T> { T getObject(); }

public <T> Wrapper<T> getSomething(...) { }

後者は 戦略パターン の可能性を促進します。バイトをストラテジーに渡し、実行させて出力を取得します。あなたはバイト戦略、ブール戦略などを持っているでしょう。

abstract class Strategy<T> {
    final byte[] bytes;

    Strategy(byte[] bytes) { this.bytes = bytes; }

    protected abstract T execute();
}

その後

class BooleanStrategy extends Strategy<Boolean> {
    public BooleanStrategy(byte[] bytes) { super(bytes); }

    @Override
    public Boolean execute() {
        return bytes[0] != 0;
    }

}

ただし、サンプルコードは悪いユースケースであり、お勧めしません。あなたの方法はあまり意味がありません。

21
hisdrewness

実際にbooleanまたはfloatのみを返す場合は、Objectが最善です。

変数オブジェクトを返す場合は、最も一般的でないスーパークラスの戻り値の型を選択する必要があります。プリミティブにはスーパークラスはありませんが、共通のスーパークラスがBooleanであるオブジェクト表現(FloatObjectなど)にボックス化されます。

1
Kane

Google HTTPクライアントの例で私の2セント:

static public <Any> Any getJson(final String url, final Class<Any> parseAs) throws IOException {
        HttpRequestFactory requestFactory
                = HTTP_TRANSPORT.createRequestFactory(
                (HttpRequest request) -> {
                    request.setParser(new JsonObjectParser(JSON_FACTORY));
                });

        HttpRequest request = requestFactory.buildRequest(HttpMethods.GET, new GenericUrl(url), null);

        return request.execute().parseAs(parseAs);
    }

このように使用できます:

HashMap<String, Object> out = HttpUtils.getJson( "https://api.qwant.com", HashMap.class);
1
Thomas Decaux