質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

745閲覧

Stringクラスについて

ganmodoki_

総合スコア6

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

3グッド

0クリップ

投稿2021/09/10 18:30

初心者の質問です。
ある時ふと、思ったのですが、javaで

String a="あいうえお";
System.out.println(a);

みたいに記述するとStringクラス型の変数aに格納されている参照値を読み込んで
参照番地のメモリ?から文字列を参照していると解釈しているのですが、
上のコードの'a'は参照型の変数ですよね?

BufferedReader br = new BufferedReader();

でいう所の'br'と区分的には同じだと思っているのですが、
なぜ、参照型の変数である'a'だけをSystem.out.printlnに入れるだけで
文字を出力できているのでしょうか。(メソッド名が必要ない?)
Stringクラスの中の何を呼び出しているのでしょうか?
BufferedReaderクラスでは同じようなことはできませんよね。

Stringクラスは、他のクラスとは根本的になにかが違うのでしょうか?

kansuke_t, dodox86, yohhoy👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

String a="あいうえお";

...

上のコードの'a'は参照型の変数ですよね?

そうですね。Stringクラスのインスタンスへの参照を収める変数です。

なぜ、参照型の変数である'a'だけをSystem.out.printlnに入れるだけで
文字を出力できているのでしょうか。(メソッド名が必要ない?)

色々な疑問が湧いてしまったようですが、それぞれは関連していて、また、Javaと言うプログラミング言語を理解するきっかけとしてもとても良いものだと思います。話が前後するかたちになりますが、説明の前にポイントをまとめておきましょうか。

  • 全てのクラスはObjectクラスの派生クラスであり、toStringメソッドを持っている。
  • Java APIでは、toStringがそのクラス相応の文字列を返すようオーバーライドによって再実装されているものがある。Stringクラスはその最たる代表と言える。
  • System.out.printlnメソッドの実体は、標準出力のPrintStream.printlnである。 PrintStream.printlnは、Stringクラス並びに根幹であるObjectクラスをも引数と取る各種のオーバーロード版のメソッドがある。
  • PrintStream.printlnメソッドは、その処理の中で引数に対してvalueOfメソッドやtoString()メソッドを適時実行し、文字列を出力する

です。では見ていきましょう。まず、疑問の発端となったSystem.out.printlnメソッドのリファレンスを見てみます。
System.out.println から辿ってPrintStream#printlnに行き着きます。引数の型ごとにいくつもオーバーロードされたprintlnがありますが、System.out.println(a)を実行した場合に呼ばれるメソッドは、aStringクラスなので、public void println(String x) です。Stringではない別のクラスであれば、Objectクラスの変数を引数とする public void println(Object x)が呼ばれます。このメソッドに関してリファレンスには次のように書いていますね。

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

String.valueOf(x)を呼び出す」そうです。aを引数として渡す場合、String.valueOf(a)と読み替えられます。String.valueOfとは何でしょう。これもリファレンスを確認します。String#valueOf(Object obj)

「Object引数の文字列表現を返します」そうです。戻り値としては「引数がnullの場合は"null"に等しい文字列。それ以外の場合はobj.toString()の値が返される。」とあります。

つまり、System.out.println(a) は、そのメソッドの中で a.toString()を実行しています。toString()メソッドとは何でしょう。これは、Javaのすべてのクラスの根本であるjava.lang.Objectクラスが持つ、最低限の機能を必ず実装しているメソッドです。Object#toStringデフォルトの実装ではtoString()は単純に参照の値を出力するようものですが、Stringクラスはこれをオーバーライドして、自身が管理している文字列を出力するようになっています。Stringクラスが担う役割を考えると、適当ですね。

参考:
toStringメソッドのオーバーライドについて - teratial#70200

BufferedReaderクラスでは同じようなことはできませんよね。

そのままではできませんが、BufferedReaderを継承すればできます。上記も踏まえ、書いてみたサンプルプログラムが以下、です。BufferedReaderのインスタンスがtoStringで何を出力すべきかは、考えどころでしょうけれども。

Java

1import java.io.InputStreamReader; 2import java.io.Reader; 3import java.io.BufferedReader; 4 5public class Main 6{ 7 public static void main(String[] args) 8 { 9 Main obj = new Main(); 10 obj.run(); 11 } 12 13 void run() { 14 System.out.println("run"); 15 System.out.println(this); 16 System.out.println(String.valueOf(this)); 17 18 InputStreamReader isr = new InputStreamReader(System.in); 19 BufferedReader br = new BufferedReader(isr); 20 System.out.println(br); 21 22 br = new XBufferedReader(isr); 23 System.out.println(br); 24 } 25 26 @Override 27 public String toString() { 28 return "Mainクラスのインスタンスです。"; 29 } 30 31 class XBufferedReader extends BufferedReader { 32 XBufferedReader(Reader in) { 33 super(in); 34 } 35 36 XBufferedReader(Reader in, int sz) { 37 super(in, sz); 38 } 39 40 @Override 41 public String toString() { 42 return "XBufferedReaderクラスのインスタンスです。"; 43 } 44 } 45}

上記プログラムのWindowsコマンドプロンプト上での実行例です。System.out.printlnの実行と照らし合わせてみてください。

CMD

1C>java --version 2java 11.0.9 2020-10-20 LTS 3Java(TM) SE Runtime Environment 18.9 (build 11.0.9+7-LTS) 4Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.9+7-LTS, mixed mode) 5 6C>java --source 8 Main.java 7run 8Mainクラスのインスタンスです。 9Mainクラスのインスタンスです。 10java.io.BufferedReader@323b36e0 11XBufferedReaderクラスのインスタンスです。 12 13C>

投稿2021/09/10 21:03

編集2021/09/11 02:11
dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

momon-ga

2021/09/10 21:28

とても良い回答だと思います。 ただ文章量が多いので、冒頭に要約があると、より理解しやすくなるかと思います。 たとえば、 ・System.out.println引数がnullなら"null"を表示、nullでないなら、toStringの結果を表示する ・全てのクラスは、Objectクラスの派生クラスでありtoStringを持っている ・javaAPIでは、toStringが実装(オーバーライド)されているものがある
dodox86

2021/09/10 21:33

momon-gaさん、ご指摘をいただきましてどうもありがとうございます。その通りですね。確かにポイントを掴みづらいものになっています。一部誤りがあったので修正させてもらったのもあるので、ご指摘も踏まえて追って直します。
dodox86

2021/09/11 02:14

ベストアンサーをいただき、質問は閉じてしまったので、なるべく元の文の印象を変えないかたちで頭の方にまとめてみました。
ganmodoki_

2021/09/11 02:17

ご回答ありがとうございます。 細部まで細かく説明してくださり、とても勉強になりました。 (同時にjava言語の底が見えない程の深さを知り憂鬱になりましたww) わざわざリファレンスのURLまで貼っていただいて とても飲み込みやすかったです。 質問の答えの重要な点は Stringクラスの変数になにか特別な仕様があるわけではなく、 println(); が重要だったということですね。 System.out.println(); が出力命令とだけしか理解していなかったので、 ずっとStringクラスには自分の知らない特性があるのかと思っていました。
dodox86

2021/09/11 02:19

本件とは関係無いですが、Stringクラスの特別さとしてはあと、「これ以上継承できない final」がありましたね。
dodox86

2021/09/11 02:23

finalは自分で定義するクラスにも付けられるので、「Stringクラスは皆に良く使われるはずのクラス」だから、Javaと言うプログラミング言語/API設計の段階で練られて提供された、ということですね。文字列リテラルも使い易くなっているので、便宜をはかったような扱いなのだと思います。
ganmodoki_

2021/09/11 02:42

なるほど、つまりみんなに都合のいいように設計してあるから Stringクラスの仕様として受け入れろ。ということでしょうか。
dodox86

2021/09/11 02:47

いえ、そういう高圧的な意味ではないです。 > Stringクラスの変数になにか特別な仕様があるわけではなく、 > println(); が重要だったということですね。 String#toString()ではStringクラス用に適切な文字列を出力しますが、他のクラスでも実装すれば同様のことができる(<サンプルプログラム通り)なので、扱いは他のクラスとほとんど同じと言って良いです。
dodox86

2021/09/11 02:54

言い方を変えると、Java作った方々:「文字列を扱うStringクラスはプログラマーの皆さん、頻繁に使うでしょう。ですので、あらかじめ使い易いようにJavaの言語仕様に沿って使い易いよう便宜を施しておきました。特別に見えるかもしれませんが、皆さんも独自クラスを定義する際はStringクラスを参考に、同じように特別に見えるものを作ることができます。ただ、String hoge = "Hoge"; のような文字列リテラルのようにはいかなくて申し訳ないのですけれども。」みたいなかんじでしょうか。
ganmodoki_

2021/09/11 06:48 編集

失礼致しました。ありがとうございました。
guest

0

String クラスは他のクラスより特別視されています。
それは(数値と並んで)普遍的な"文字列"を扱うためです。
println からすれば、「"文字列"を表示する」という機能面を考えても String を特別に扱うのは当然ではないでしょうか。

ちなみに、BufferedReader のインスタンスを println に渡すことは可能です。
何が表示されるかは、保証できませんが。

投稿2021/09/10 20:09

編集2021/09/10 20:16
jimbe

総合スコア12756

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ganmodoki_

2021/09/11 02:20

ご回答ありがとうございます。 確かにそのような考え方の方が自分への落とし込みとしては 十分かもしれませんね。
swordone

2021/09/11 03:06

Stringが特別扱いというのは、説明として適さないと考えます。
ganmodoki_

2021/09/11 03:20

コメントありがとうございます。
jimbe

2021/09/11 05:25

正確さを追求すると dodox86 さんのようにどうしても長くなってしまいますので、「ある時ふと、思ったのですが」という雰囲気の回答として、個人的なテキトウさで「(数値と並んで)普遍的な"文字列"を扱うため」に特別と表現させて頂きました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問