25

私はかなり長い間Javaを扱ってきましたが、関数がどのように機能するのか疑問に思っていましたSystem.out.print().

ここに私の疑問があります:

関数であるため、ioパッケージのどこかに宣言があります。しかし、Java 開発者はどのようにそれを行ったのでしょうか? この関数は、配置方法に関係なく、任意の数の引数と任意の引数の型を受け取ることができるためです。例えば:

System.out.print("Hello World");
System.out.print("My name is" + foo);
System.out.print("Sum of " + a + "and " + b + "is " + c);
System.out.print("Total USD is " + usd);

変数のデータ型a, b, c, usd, fooや渡し方に関係System.out.print()なく、エラーをスローすることはありません。

私にとって、要件がこのようなものであるプロジェクトに取り組んだことはありません。とはいえ、このような要件を受け取った場合、どうすれば解決できるのか本当にわかりません。

誰かが私にそれがどのように行われたか説明できますか?

4

9 に答える 9

28

System.outの単なるインスタンスですPrintStreamJavaDocを確認できます。その可変性は、メソッドのオーバーロード(同じ名前でパラメーターが異なる複数のメソッド) に基づいています。

この印刷ストリームは、その出力をいわゆる標準出力に送信しています。


あなたの質問では、可変引数関数(またはvarargs)と呼ばれる手法について言及しています。残念ながら、これは でサポートされていないPrintStream#printため、これを別のものと間違えているに違いありません。ただし、これらを Java で実装するのは非常に簡単です。ドキュメントを確認してください。


また、Java が文字列以外の変数を連結する方法を知っていることに興味がある場合"foo" + 1 + true + myObj、それは主に Java コンパイラの責任です。

連結に変数が含まれていない場合、コンパイラは単純に文字列を連結します。関連する変数がある場合、連結はStringBuilder#appendチェーンに変換されます。結果のバイトコードには連結命令はありません。つまり、+演算子 (文字列の連結について話す場合) はコンパイル中に解決されます。

Java のすべての型は文字列に変換できます (クラス内のintメソッドを介して、クラス内のメソッドを介して、オブジェクト自体を介して、...)。興味があれば、StringBuilder のソース コードを確認できます。IntegerbooleanBoolean#toString


更新:私は自分自身に興味があり、( javapを使用して) 私の例が何にSystem.out.println("foo" + 1 + true + myObj)コンパイルされるかを確認しました。結果:

System.out.println(new StringBuilder("foo1true").append(myObj).toString());
于 2013-06-15T07:42:16.960 に答える
3

System.put.print...()可変数の引数を取るように見えますが、そうではありません。よく見ると、文字列は単純に連結されており、どの文字列でも同じことができます。発生する唯一のことは、渡されるオブジェクトがtoString()メソッドを呼び出すJavaによって暗黙的に文字列に変換されることです。

これを実行しようとすると失敗します:

int i = 0;
String s = i;
System.out.println(s);

理由は、ここでは暗黙の変換が行われていないためです。

ただし、次のように変更すると

int i = 0;
String s = "" + i;
System.out.println(s);

それは機能し、これは使用時にSystem.put.print...()も起こります。

C のようなものを模倣するために Java で可変数の引数を実装したい場合は、次のようにprintf宣言できます。

public void t(String s, String ... args)
{
    String val = args[1];
}

ここで何が起こるかというと、提供された引数の長さで文字列の配列が渡されます。ここでは、Java が型チェックを行うことができます。

本当にprintfが必要な場合は、次のようにする必要があります。

public void t(String s, Object ... args)
{
    String val = args[1].toString();
}

次に、それに応じて引数をキャストまたは解釈する必要があります。

于 2013-06-15T07:58:30.603 に答える
0

そのすべてはMethod Overloadingです。

println() メソッドには、データ型ごとに個別のメソッドがあります

object を渡す場合:

オブジェクトを出力してから行を終了します。このメソッドは、最初に String.valueOf(x) を呼び出して出力オブジェクトの文字列値を取得し、次に print(String) を呼び出してから println() を呼び出すかのように動作します。

プリミティブ型を渡す場合:

対応するプリミティブ型のメソッド呼び出し

String を渡す場合:

対応する println(String x) メソッド呼び出し

于 2013-06-15T07:49:23.243 に答える
0

あなたは方法に混乱していると思いますprintf(String format, Object... args)。最初の引数はフォーマット文字列で、これは必須です。残りは任意の数のObjects を渡すことができます。

print()メソッドとメソッドの両方にそのようなオーバーロードはありませんprintln()

于 2013-06-15T07:49:25.430 に答える
0

何を印刷するかを選択する限り、何でも文字列に変換できます。Objet.toString()デフォルトのダム文字列を返すことができるため、要件は非常に単純でした: package.classname + @ + object number.

print メソッドが XML または JSON シリアライゼーションを返す必要がある場合、 toString() の基本的な結果は受け入れられません。メソッドは成功しますが。

Java が馬鹿げていることを示す簡単な例を次に示します。

public class MockTest{

String field1;

String field2;

public MockTest(String field1,String field2){
this.field1=field1;
this.field2=field2;
}

}

System.out.println(new MockTest("a","b");

何かを印刷しますpackage.Mocktest@3254487!String メンバーが 2 つしかなく、これを実装して印刷することもできますが、

Mocktest@3254487{"field1":"a","field2":"b"}

(または、デバッガーでの表示方法とほぼ同じです)

于 2013-06-15T09:36:04.250 に答える
0

あなたが言及したシナリオはオーバーロードではなく、さまざまな変数を文字列で連結しているだけです。

System.out.print("Hello World");

System.out.print("My name is" + foo);

System.out.print("Sum of " + a + "and " + b + "is " + c); 

System.out.print("Total USD is " + usd);

これらのすべての場合で、何かが文字列と連結されると、そのオブジェクトの toString() を呼び出すことによって文字列に変換され、プリミティブが直接連結されるため、 print(String s) を呼び出すだけです。ただし、さまざまな署名を知りたい場合は、さまざまな引数に対して print() がオーバーロードされます。

于 2018-10-16T07:40:47.890 に答える