7

サードパーティの API を使用して、次のことを確認しました。

使用する代わりに、

public static string getString(){
   return "Hello World";
}

次のようなものを使用します

public static void getString(String output){

}

「出力」文字列が割り当てられています。

そのような機能を実装する理由が気になります。このような出力パラメータを使用する利点は何ですか?

4

8 に答える 8

25

あなたの例では何かが正しくありません。

class Foo {

    public static void main(String[] args) {
        String x = "foo";
        getString(x);
        System.out.println(x);
    }

    public static void getString(String output){
        output = "Hello World"
    }
}

上記のプログラムでは、 「Hello World」ではなく「foo」という文字列が出力されます。

一部の型は可変であり、その場合、関数に渡されたオブジェクトを変更できます。不変型 ( などString) の場合は、代わりに渡すことができるある種のラッパー クラスを構築する必要があります。

class Holder<T> {
    public Holder(T value) {
        this.value = value;
    }
    public T value;
}

次に、代わりにホルダーを渡すことができます。

public static void main(String[] args) {
    String x = "foo";
    Holder<String> h = new Holder(x);
    getString(h);
    System.out.println(h.value);
}

public static void getString(Holder<String> output){
    output.value = "Hello World"
}
于 2009-09-10T07:58:38.050 に答える
5

その例は間違っています。Javaには出力パラメータがありません。

この動作をエミュレートするためにできることの1つは、次のとおりです。

public void doSomething(String[] output) {
    output[0] = "Hello World!";
}

しかし、私見では、これは複数のレベルで吸い込まれます。:)

メソッドが何かを返すようにしたい場合は、それを返すようにします。複数のオブジェクトを返す必要がある場合は、これらのオブジェクトを入れて返すコンテナクラスを作成します。

于 2009-09-10T08:05:27.410 に答える
3

私は Jasper に同意しません: 「私の意見では、これは複数の結果を返すには本当に醜く悪い方法です」. .NET には、出力パラメーターを利用する興味深い構造があります。

bool IDictionary.TryGet(key, out value);

とても便利でエレガントだと思います。また、アイテムがコレクションにある場合は、それを返すと同時に返す最も便利な方法です。それを使用して、次のように書くことができます。

object obj;
if (myList.TryGet(theKey, out obj))
{
  ... work with the obj;
}

次のような古いスタイルのコードを見ると、開発者を常に叱ります。

if (myList.Contains(theKey))
{
  obj = myList.Get(theKey);
}

ご覧のとおり、パフォーマンスが半分になります。Java では、既存のアイテムの null 値と Map 内のアイテムが存在しないことを 1 回の呼び出しで区別する方法はありません。これが必要な場合もあります。

于 2010-12-28T21:48:47.763 に答える
1

この機能には大きな欠点が1つあります。それは機能しません。関数パラメーターは関数に対してローカルであり、それらに割り当てることは関数の外部に影響を与えません。
一方で

void getString(StringBuilder builder) {
    builder.delete(0, builder.length());
    builder.append("hello world");
}

動作しますが、これを行う利点はありません(複数の値を返す必要がある場合を除く)。

于 2009-09-10T08:04:18.247 に答える
1

このメカニズムにより、新しいオブジェクトの作成を回避できる場合があります。

例:適切なオブジェクトがとにかく存在する場合、それをメソッドに渡して、フィールドを変更する方が高速です。

これは、呼び出されたメソッド内に新しいオブジェクトを作成し、その参照を返して割り当てる(いつか収集する必要のあるガベージを生成する)よりも効率的です。

于 2009-09-10T08:05:53.487 に答える
1

文字列は不変であるため、Java の疑似出力パラメーターを不変オブジェクトで使用することはできません。

また、出力の範囲はgetStringメソッドに限定されます。出力変数を変更すると、呼び出し元には何も表示されません。

ただし、できることは、パラメーターの状態を変更することです。次の例を検討してください。

void handle(Request r) {
    doStuff(r.getContent());
    r.changeState("foobar");
    r.setHandled();
}

1 つの Request で複数のハンドルを呼び出すマネージャがある場合、Request の状態を変更して、変更されたコンテンツに対して (他のハンドラによる) さらなる処理を許可できます。マネージャーは、処理を停止することもできます。

利点:

  • 新しいコンテンツと処理を停止するかどうかを含む特別なオブジェクトを返す必要はありません。そのオブジェクトは一度しか使用されず、オブジェクトを作成するとメモリと処理能力が無駄になります。
  • 別の Request オブジェクトを作成する必要はなく、ガベージ コレクターが古い参照を削除できるようにします。
  • 場合によっては、新しいオブジェクトを作成できないことがあります。たとえば、そのオブジェクトがファクトリを使用して作成され、それにアクセスできないため、またはオブジェクトにリスナーがあり、古いリクエストをリッスンしていたオブジェクトに、代わりにそうする必要があることを伝える方法がわからないためです。新しいリクエストを聞いてください。
于 2009-09-10T08:14:48.753 に答える
1

実際には、Java でパラメーターを使用することは不可能ですが、不変が値とセッターを持つジェネリックであるジェネリック クラスを作成することで、メソッドが不変の String とプリミティブの参照解除を行うようにすることができます。 getter または、要素 0 (長さ 1) が値である配列を使用して、最初にインスタンス化します。これは、複数の値を返す必要がある状況があり、クラスが存在する場所にそれらを返すためだけにクラスを作成する必要がある場合があるためです。使用されるだけで、テキストが無駄になり、実際には再利用できません。

現在は C/C++ であり、.Net (mono または MS) でもあるため、Java は少なくともプリミティブの逆参照をサポートしていないことを強くお勧めします。そのため、代わりに配列に頼っています。

ここに例があります。インデックスが配列で有効かどうかを確認する関数 (メソッド) を作成する必要があるが、インデックスが検証された後に残りの長さも返したいとします。これを c で「bool validate_index(int index, int arr_len, int&rem)」と呼びましょう。Java でこれを行う方法は、'Boolean validate_index(int index, int arr_len, int[] rem1)' です。rem1 は、配列が 1 つの要素を保持することを意味します。

public static Boolean validate_index(int index, int arr_len, int[] rem1)
{
    if (index < 0 || arr_len <= 0) return false;

    Boolean retVal = (index >= 0 && index < arr_len);

    if (retVal && rem1 != null) rem1[0] = (arr_len - (index + 1));

    return retVal;

}

これを使用すると、ブール値の戻り値と剰余の両方を取得できます。

 public static void main(String[] args)
 {
    int[] ints = int[]{1, 2, 3, 4, 5, 6};
    int[] aRem = int[]{-1};
    //because we can only scapegoat the de-ref we need to instantiate it first.
    Boolean result = validate_index(3, ints.length, aRem);

    System.out.println("Validation = " + result.toString());
    System.out.println("Remainding elements equals " + aRem[0].toString());

 }

puts: Validation = True puts: 残りの要素が 2 に等しい

配列要素は常に、スタック上のオブジェクトまたはヒープ上のオブジェクトのアドレスのいずれかを指します。したがって、配列の長さがわからない場合があるため、 myArrayPointer = new Class[1][] としてインスタンス化する double 配列にすることで、配列に対しても逆参照として使用することが絶対に可能です。呼び出しが「Boolean tryToGetArray(SomeObject o, T[][] ppArray)」のようなアルゴリズムを通過するまで、これは c/c++ と同じ「template bool tryToGetArray (SomeObject* p, T** ppArray)」またはC# 'bool tryToGetArray(SomeObject o, ref T[] array)'. [][] または [] が最初に少なくとも 1 つの要素を使用してメモリ内でインスタンス化されている限り、機能します。

于 2012-08-08T03:10:03.530 に答える
0

私の意見では、これは関数に複数の結果がある場合に便利です。

于 2009-09-10T12:17:50.240 に答える