Javaの出力パラメーター
-
05-07-2019 - |
質問
サードパーティAPIを使用して、次のことを確認しました。
使用する代わりに、
public static string getString(){
return "Hello World";
}
次のようなものを使用します
public static void getString(String output){
}
と「出力」を取得しています;割り当てられた文字列。
このような機能を実装する理由に興味があります。このような出力パラメーターを使用する利点は何ですか?
解決
例では何かが正しくありません。
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"
}
}
上記のプログラムでは、文字列" foo"出力されます。ではありません" Hello World"。
一部の型は変更可能です。その場合、関数に渡されるオブジェクトを変更できます。不変型( 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"
}
他のヒント
Jasperには同意しません。「私の意見では、これは複数の結果を返すのは本当にくて悪い方法です」。 .NETには、出力パラメーターを利用する興味深い構造があります:
bool IDictionary.TryGet(key, out value);
非常に便利でエレガントです。そして、アイテムがコレクション内にあり、同時にそれを返す場合に確認する最も便利な方法です。それを使って次のように書くことができます:
object obj;
if (myList.TryGet(theKey, out obj))
{
... work with the obj;
}
次のような古いスタイルのコードが表示される場合、開発者を常にconstantlyります:
if (myList.Contains(theKey))
{
obj = myList.Get(theKey);
}
なるほど、パフォーマンスが半分になります。 Javaでは、1回の呼び出しで既存のアイテムのnull値とマップ内のアイテムの非存在を区別する方法はありません。時々これが必要です。
この例は間違っていますが、Javaには出力パラメーターがありません。
この動作をエミュレートするためにできることの1つは次のとおりです。
public void doSomething(String[] output) {
output[0] = "Hello World!";
}
しかし、私見は複数のレベルでひどいです。 :)
メソッドが何かを返すようにする場合は、それを返すようにします。複数のオブジェクトを返す必要がある場合は、これらのオブジェクトを入れて返すコンテナクラスを作成します。
この機能には大きな欠点が1つあります-機能しません。関数パラメーターは関数に対してローカルであり、それらに割り当てることは関数の外部には影響しません。
一方、
void getString(StringBuilder builder) {
builder.delete(0, builder.length());
builder.append("hello world");
}
機能しますが、これを行う利点はありません(複数の値を返す必要がある場合を除く)。
文字列は不変です。Javaの疑似出力パラメーターを不変オブジェクトで使用することはできません。
また、出力の範囲は getString メソッドに限定されます。 output 変数を変更しても、呼び出し元には何も表示されません。
ただし、できることは、パラメータの状態を変更することです。次の例を考えてください:
void handle(Request r) {
doStuff(r.getContent());
r.changeState("foobar");
r.setHandled();
}
1つのリクエストで複数のハンドルを呼び出すマネージャーがある場合、リクエストの状態を変更して、変更されたコンテンツの(他のハンドラーによる)さらなる処理を許可できます。マネージャーは、処理を停止することもできます。
利点:
- 新しいコンテンツと処理を停止するかどうかを含む特別なオブジェクトを返す必要はありません。そのオブジェクトは一度しか使用されず、オブジェクトを作成するとメモリと処理能力が浪費されます。
- 別のRequestオブジェクトを作成して、ガベージコレクターに現在廃止されている古い参照を削除させる必要はありません。
- 場合によっては、新しいオブジェクトを作成できないことがあります。たとえば、そのオブジェクトはファクトリを使用して作成されており、そのオブジェクトにアクセスできないため、またはオブジェクトにリスナーがあり、古いリクエストをリッスンしているオブジェクトに代わりにすべきことを伝える方法がわからないためです新しいリクエストを聞いてください。
実際には、javaにoutパラメーターを設定することはできませんが、不変がジェネリックであるジェネリッククラスを記述することにより、メソッドが不変のストリングとプリミティブの逆参照を行うように回避することができます値とセッターとゲッター、または要素0(長さ1)が最初にインスタンス化される値である配列を使用して、複数の値を返す必要がある場合があるクラスはテキストの無駄だけで使用され、実際には再利用できません。
現在、C / C ++であり、.Net(モノまたはMS)であるため、javaは少なくともプリミティブの逆参照をサポートしていないことを促しています。そのため、代わりに配列に頼ります。
例を次に示します。インデックスが配列内で有効かどうかを確認する関数(メソッド)を作成する必要があるが、インデックスが検証された後に残りの長さを返す必要があるとします。 cで「bool validate_index(int index、int arr_len、int&amp; 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:検証= True puts:残りの要素は2に等しい
配列要素は、常にスタック上のオブジェクトまたはヒープ上のオブジェクトのアドレスを指します。したがって、配列の間接参照として使用することは、myArrayPointer = new Class [1] []としてインスタンス化する二重配列にすることにより、配列の場合でも絶対に可能です。配列の長さがわからない場合があるため「Boolean tryToGetArray(SomeObject o、T [] [] ppArray)」のようなアルゴリズムを通過する呼び出しは、「template bool tryToGetArray(SomeObject * p、T ** ppArray)」と同じc / c ++と同じになるまで、またはC# 'bool tryToGetArray(SomeObject o、ref T [] array)'。 [] []または[]が最初に少なくとも1つの要素を使用してメモリ内でインスタンス化される限り、正常に機能します。
このメカニズムにより、新しいオブジェクトの作成を回避できる場合があります。
例: とにかく適切なオブジェクトが存在する場合、それをメソッドに渡し、フィールドを変更する方が高速です。
これは、呼び出されたメソッド内に新しいオブジェクトを作成し、その参照を返し、割り当てる(いつか収集する必要があるガベージを生成する)よりも効率的です。
私の意見では、これは関数に複数の結果がある場合に便利です。