String
クラスは、文字列(テキスト)を扱うためのクラスです。Javaでは "Hello"
のようなダブルクォートで囲んだ文字列は、すべて String
型のオブジェクトになります。
Stringの基本
ポイント | 内容 |
---|---|
イミュータブル | 一度作った文字列は変更できない(変更すると新しいオブジェクトになる) |
生成方法 | "文字列" または new String("文字列") |
主なメソッド | length() , charAt() , substring() , equals() , toUpperCase() |
よく使う用途 | ユーザー入力、ファイル内容、メッセージのやり取りなど、文字情報の処理全般 |
String greeting = "Hello"; System.out.println(greeting.length()); // 5 System.out.println(greeting.charAt(1)); // e System.out.println(greeting.toUpperCase()); // HELLO
JavaのStringは文字列を表すデータ型・・・というように想像・理解している方が多いかもしれません。このページではその誤解を解きつつ、故にStringを扱うときにどのような注意点があるのか?Stringの正体は何か?について焦点を当てた解説を行います。
前提:JavaのString(文字列)はデータ型ではない

Javaにおける「データ型」についての基本からおさらいしておきます(おそらくこの前段がJava初心者にとっては一番大事なStringの基礎知識となります)。
Javaの「データ型」といった場合、これは厳密にはプリミティブ型(primitive type)を指します(参考 プリミティブ型/参照型)。Javaのプリミティブ型は以下8種類のみ存在します。
boolean
byte
short
int
long
float
double
char
上記をご覧いただければわかりますが、この中に今回の主題となるString
は含まれておりません。対してchar
はプリミティブ型として存在している点に注目してください。つまり
char
… データ型(プリミティブ型)String
… オブジェクト(参照型)
まずはここが大きな出発点です。Javaの世界において「文字列」は言語仕様レベルでは1つのデータ型ではなく、特別なクラス(java.lang.String
)として扱われています。
なぜStringはプリミティブ型でないのか?
char
は16ビットの値(UTF-16のコードユニット)を格納する1文字専用のデータ型です。しかし、現実世界で扱う文字列は複数文字の連続から成り、それらを安全かつ効率的に扱うためには、配列管理や文字コードの処理が必要になってきます。(現にC言語などでは、文字列は文字の配列として扱われます。)
これを配列でやるのではなく、クラス(オブジェクト)の仕組みを使ってより簡単に/直感的に管理できるようにしようというのがStringの基本思想です。
ポイント クラスであることで得られるメリット
String型(文字列)の生成方法
方法 | コード例 | 説明 |
---|---|---|
① 文字列リテラルを使う | String str = "Hello"; | 最も簡単で一般的。 リテラルの場合、同じ内容なら同じインスタンスを共有 |
② コンストラクタを使う(非推奨) | String str = new String("Hello"); | 常に新しいインスタンスが作られるので非推奨 |
ポイント 初心者が間違えやすいポイント
- 文字列は基本「
"
(ダブルクォート)」で囲む。 new
を使う必要はほとんどない。- 同じ内容の文字列ならJavaが自動で同じものを再利用する。
Stringはイミュータブル
一度作られたString
オブジェクトの中身(文字列の内容)は変更できないという設計です。たとえば、str.replace("a", "b")
を呼び出しても、オリジナルの str
は変わらずに、新しい文字列オブジェクトが返ってきます。
ポイント イミュータブルなメリット
- 文字列プール(String Pool)の利用
同じ内容の文字列リテラルがあれば、JVMがそれを再利用してメモリを節約します。 - スレッドセーフ
どのスレッドからアクセスしても内容が変わらないため、ロックなしで安全に扱える。 - セキュリティ
パスワード文字列やシステムプロパティなど、書き換えられると困る情報を安全に保持できる。
Stringの注意点
同値性を比較する場合は == で比較しない
char
はプリミティブ型なので、==
で比較すれば「数値」としての等価比較ができます。しかし、String
はオブジェクトなので、==
で比較すると参照が同一かどうかを判定します。内容ではなく、実際に指し示すオブジェクトが同じかどうかの比較になります。
したがって、Java Silverでも頻出の「文字列比較問題」で失敗しやすいのがこれです。文字列の内容を比べたい場合はequals()
を使わなければなりません。
char c1 = 'A'; char c2 = 'A'; System.out.println(c1 == c2); // true → 値('A'のコード=65)が同じなのでtrue String s1 = new String("Hello"); String s2 = new String("Hello"); System.out.println(s1 == s2); // false → 参照が異なる System.out.println(s1.equals(s2)); // true → 内容が同じ
文字列リテラルは同じオブジェクトを参照する場合がある
コードに直接 String
リテラルを書いたとき、同一内容であれば同じオブジェクトを指すことが多いです。これがいわゆるString Poolの仕組みです。よって、次のようなケースは ==
でも true
になり得ます。
String s3 = "Hello"; String s4 = "Hello"; System.out.println(s3 == s4); // true (プールの同じオブジェクトを参照する場合)
ただし、リテラル以外(例: new String("Hello")
)では常に別オブジェクトを生成するので、==
はfalse
になりやすい。ここも資格試験でよく問われるポイントです。
Java では、リテラル(参考 改めて「リテラル」とは?)で作成した文字列は自動的に String Pool(ヒープ内の特別な領域) に保存されます。
String s1 = "Hello"; String s2 = "Hello"; System.out.println(s1 == s2); // true(同じ参照を指す)
✅ ポイント: s1
と s2
は、同じ "Hello"
を String Pool から取得しているため、==
で true
になる。

new String() を使うと?
String s3 = new String("Hello"); System.out.println(s1 == s3); // false(異なる参照)
new String("Hello")
を使うと、ヒープ領域に新しい String インスタンスが作成されるため、String Pool とは異なるオブジェクトになります。

後述しますが、intern() を使うと String Pool の参照を取得するようになります。
String s4 = new String("Hello").intern(); System.out.println(s1 == s4); // true(String Pool の "Hello" を参照)
✅ ポイント:
s4
はintern()
を呼び出すことで、String Pool 内の"Hello"
を参照するようになる。- これにより、
s1 == s4
はtrue
になる。
StringBuilder / StringBuffer
String
はイミュータブルであるが故に「連結」を頻繁に行うと、そのたびに新しいオブジェクトを作るため、パフォーマンスが落ちる場合があります。そこでJavaは、可変文字列を扱うStringBuilder
(単一スレッド向け)や StringBuffer
(スレッドセーフ)を提供しています。
StringBuilder sb = new StringBuilder(); sb.append("Java"); sb.append("Silver"); String result = sb.toString(); // "JavaSilver"
資格試験でも、「String
をループ内で +=
しているコードが非効率」といった内容の設問がよく出ます。イミュータブルな特性を理解していれば、StringBuilder
を使うべき理由がスッと頭に入るでしょう。
Stringクラスの主要メソッド
JavaのString
クラスは、文字列操作に関する多種多様なメソッドを提供しています。ここでは、よく使われる主要なメソッドとその使い方を、注意点を含めてわかりやすくまとめます。

ポイントは、String
がイミュータブル(不変)であることを前提に、各メソッドが「元の文字列を変更せず、新しい文字列を返す」という点です。
長さや文字を取得するメソッド
length()
- 概要: 文字列の長さ(
char
単位)を返す。 - 使用例:
String str = "Hello"; int len = str.length(); // 5
Javaは内部的にUTF-16で文字を管理しているため、サロゲートペア(絵文字など)が含まれる場合、画面に見える「文字数」とlength()
が返す値が異なることがあります。
charAt(int index)
- 概要: 指定した位置の文字(
char
)を取得する。 - 使用例:
String str = "Hello"; char c = str.charAt(1); // 'e'
インデックスは 0から始まります。範囲外を指定すると StringIndexOutOfBoundsException
が発生します。
文字列比較系
equals(Object anObject)
- 概要: 文字列の内容が同じかを比較する。最も基本的な文字列比較。
- 使用例
String s1 = "Hello"; String s2 = new String("Hello"); System.out.println(s1.equals(s2)); // true (内容が同じかを判定)

何度か解説した通り ==
はオブジェクト参照が同一かどうかを比較するため、文字列内容の比較には常にequals()
を使う点に注意しましょう。
equalsIgnoreCase(String anotherString)
- 概要: 大文字・小文字を区別せずに内容が同じかを比較する。
- 使用例
String s1 = "Hello"; String s2 = "hello"; System.out.println(s1.equalsIgnoreCase(s2)); // true
完全にケースを無視するため、英字以外の言語や特殊なケース変換(ß → SSなど)では予期しない結果となることもあり得るので注意が必要です。
compareTo(String anotherString)
- 概要: 辞書順で大小関係を比較する。返り値は負数・0・正数。
- 使用例:
String s1 = "apple"; String s2 = "banana"; System.out.println(s1.compareTo(s2)); // 負の値(辞書順でappleはbananaより小さい)
部分文字列・位置検索系
substring(int beginIndex, int endIndex)
- 概要: 文字列の一部を切り出して、新しい文字列を返す。
endIndex
は最後の位置の1つ後ろを指定する。 - 使用例:
String str = "HelloWorld"; String sub = str.substring(1, 5); // "ello" (1~4文字目)
範囲外を指定すると StringIndexOutOfBoundsException
が発生します。また、元の文字列は変更されない(イミュータブル)。
尚、終了インデックスを省略すると、最後まで切り出してくれます。
String str = "HelloWorld"; String sub2 = str.substring(5); // "World"(5文字目以降)
indexOf(String str)
/ lastIndexOf(String str)
- 概要: 指定した文字列や文字が、最初または最後に登場する位置を返す。見つからなければ
-1
。 - 使用例
String text = "Hello World"; int index = text.indexOf("o"); // 4 ("o"の最初の出現位置) int last = text.lastIndexOf("o"); // 7 ("o"の最後の出現位置)
startsWith(String str)
/ endsWith(String str)
メソッド名 | 概要 | 戻り値の型 | 使用例 | 戻り値(例) |
---|---|---|---|---|
startsWith | 指定した文字列で始まるか判定する | boolean | "Hello".startsWith("He") | true |
endsWith | 指定の文字列で終わるか判定 | boolean | "Hello".endsWith("lo") | true |
startsWith
は、文字列が指定した文字で始まるか判定します。endsWith
は、文字列が指定した文字で終わるか判定します。
String str = "HelloWorld"; boolean start = str.startsWith("Hell"); // true boolean end = str.endsWith("World"); // true
文字列の置換・分割系
replace(CharSequence target, CharSequence replacement)
- 概要: 指定した文字列を、別の文字列に すべて 置き換える。
- 使用例:
String str = "banana"; String replaced = str.replace("a", "o"); System.out.println(replaced); // "bonono"

イミュータブルゆえに、新しい文字列が返る。元の str
は変化しません。replaceAll(String regex, String replacement)
は正規表現に対応するため、注意が必要です。
メソッド名 | 処理内容 | 引数の型 | 置換対象 |
---|---|---|---|
replace | 文字列の一致する文字または文字列をすべて置換 | char またはCharSequence | 単純な文字・文字列 |
replaceAll | 正規表現に一致した文字列をすべて置換 | String (正規表現) | 正規表現パターンにマッチする文字列 |
String str = "apple apple apple"; // replaceの例(単純な文字列置換) String result1 = str.replace("apple", "orange"); // 出力: "orange orange orange" // replaceAllの例(正規表現で置換) String result2 = str.replaceAll("a.*?e", "orange"); // 出力: "orange orange orange"
- replaceは、シンプルな文字や文字列の完全一致を対象に置換。
- replaceAllは、正規表現パターンを用いてより複雑な条件の置換が可能。
split(String regex)
- 概要: 正規表現
regex
を区切りとして、文字列を分割し、文字列配列を返す。 - 使用例
String fruits = "apple,banana,cherry"; String[] arr = fruits.split(","); // arr[0] = "apple", arr[1] = "banana", arr[2] = "cherry"
大文字・小文字変換系
toUpperCase()
/ toLowerCase()
- 概要: 文字列をすべて大文字/小文字に変換して返す。
- 使用例:
String str = "Hello World"; String upper = str.toUpperCase(); // "HELLO WORLD" String lower = str.toLowerCase(); // "hello world"
前後の空白除去・判定系
trim()
- 概要: 文字列の先頭と末尾の**空白文字(半角スペースやタブ、改行など)**を除去する。
- 使用例
String str = " Hello World "; String trimmed = str.trim(); // "Hello World"
真ん中のスペースは削除されません。Java 11以降には全Unicode空白を対象にするstrip()
なども存在するが、trim()
はASCII制御文字を中心に取り扱うのがポイントです。
isEmpty()
/ isBlank()
(Java 11+)
- 概要:
isEmpty()
は文字列の長さが0かどうかを判定。isBlank()
は空白文字のみで構成されている、または長さが0かどうかを判定(Java 11で追加)。
- 使用例
String s1 = ""; System.out.println(s1.isEmpty()); // true System.out.println(s1.isBlank()); // true String s2 = " "; System.out.println(s2.isEmpty()); // false (空白があるので長さは3) System.out.println(s2.isBlank()); // true
その他特殊メソッド
intern()
intern()
メソッドは、String Poolに文字列を登録し、プール内の同じ内容の文字列を返します。
このメソッドを使用することで、同じ内容の文字列が複数存在する場合にメモリ使用量を削減し、==
による比較が可能になります。
わかりやすく言えば、String Pool に文字列を登録する。既に同じ内容の文字列がある場合はそれを参照するようにするということ。
public class InternExample { public static void main(String[] args) { // 通常の文字列生成 String str1 = new String("Hello"); String str2 = new String("Hello"); // 参照が異なるため false System.out.println(str1 == str2); // intern() を使用してプールに登録 String internedStr1 = str1.intern(); String internedStr2 = str2.intern(); // 参照が同じになるため true System.out.println(internedStr1 == internedStr2); } }

intern()
を頻繁に使いすぎるとヒープ領域の String Pool に負荷がかかり、パフォーマンスが低下する可能性があります。- Java 7以降では、String Pool は ヒープ領域に移動したため、大量の
intern()
呼び出しでメモリ不足(OutOfMemoryError) を引き起こす可能性があります。