Javaについて徹底解説!

charは文字でStringは文字列! Javaでの文字の扱い方を基礎から解説

大石 英人

開発エンジニア/Java20年/Java GOLD/リーダー/ボールド歴2年

Javaのchar16ビット(2バイト)のプリミティブ型で、Unicodeという文字コード規格での一文字を、065,535の範囲の数字で表したものです。プログラムやコンピュータでは、文字も数字で表しますので、charJavaで文字を扱う時の最小単位です。

charは数字でもあり文字でもあります。ですので、プログラム上でcharを表現できる書き方はいろいろあって、文字そのもの、2進数、10進数、16進数、Unicodeのコードポイントなどが使えます。

Javaの文字列であるStringは、charが集まってできたものとも言えるので、charStringは大変関連の深い間柄です。ですので、charを理解することはStringを理解することにもつながり、ゆくゆくはUnicodeの理解にもつながっていく大事なことなのです。

この記事では、Javacharについて、そもそもcharとはどういうものかという基礎から、じっくりとお伝えします。もちろん、Stringとの相互変換の仕方など、便利な知識も盛りだくさんです。

※この記事のサンプルは、Java 11の環境で動作確認しています


1.charはUnicodeの一文字を表す065535の数字

Javaのchar16ビット(2バイト)のプリミティブ型(primitive、基本データ型)で、Unicode(ユニコード)という文字コード規格での一文字を、065535の範囲の整数で表すものです。

charはプリミティブ型ですので「数字そのもの」です。ですから、何かのクラスのインスタンスではありません。クラスとしてcharを表現する場合は、JavaではCharacterというクラスを使います。

charと他のプリミティブ型を比較すると、以下のようになります。

データ型 値の種類 ビット数 表現できる値の範囲 接尾語 備考
boolean 真偽値 1ビット true/falseのどちらか
byte 整数 8ビット(1バイト) -128~127
short 整数 16ビット(2バイト) -32,768~32,767
char 文字 16ビット(2バイト) 0~65,535 Unicode文字、\u0000\uffff
int 整数 32ビット(4バイト) -2,147,483,648~
2,147,483,647
±2147百万、Unicodeコードポイント
long 整数 64ビット(8バイト) -9,223,372,036,854,775,808~
9,223,372,036,854,775,807
Lまたはl ±922
float 浮動小数点 32ビット(4バイト) ±3.40282347E+38~ 1.40239846E-45 Fまたはf 単精度
±3.4×1038乗~約±1.4×10-45
double 浮動小数点 64ビット(8バイト) ±1.79769313486231570E+308~±4.94065645841246544E-324 Dまたはd

倍精度
±1.8×10308乗~約±4.9×10-324

1-1.プログラムでは文字も数字で表現する

Javaに限らずプログラムやコンピュータは、内部ではすべてを数字で表現します。文字や文字列もすべて数字です。例えば、‘A’という文字には、Unicodeでは65という数字が割り当てられています。12354です。

文字と数字の紐付け方には、たくさんのルールがあります。Javaではその一つであるUnicodeが最初から採用されていて、その中のUTF-16というルールが使われています。このUTF-16“16”は、16ビットが処理単位だよということで、だからchar16ビットなのです。

同じようなルールには、日本語環境ではいわゆるシフトJISEUC-JPJISなどがあります。Unicodeの中でも、UTF-8UTF-32というものもあります。Javaでもこれらのルールはもちろん扱えますが、Javaのプログラム中で文字・文字列を扱う時は、UnicodeおよびUTF-16を前提にするのが普通です。

1-2.charとStringは遠くて近いモノ

charと、Javaで文字列を表すクラスのStringは、お互いに違ったモノ同士です。charは一文字を表す数字なのに対して、JavaString0文字以上の文字が集まったモノで、Stringクラスのインスタンスです。

charとStringはプログラム上で違うモノなので、お互いに代入は出来ませんし、値を直接比べられもしません。そういうことをするなら、charStringのどちらかに寄せる必要があります。そのやり方は後述します。

なお、ぜひ知っておいていただきたいのは、Stringcharが集まってできているモノで、Stringは配列のようなインデックスでcharにアクセスできるということです。そんなStringの詳細については、以下の記事も参考にしてください。

関連記事

2.charの使い方

この章ではcharの使い方を解説します。charを使う上では、どうしてもいわゆる「文字コード」の知識があることが前提になってくるので、最小限の文字コードの知識についてもお伝えしていきます。

2-1.charの宣言と代入

charは整数を表すデータ型の一つです。変数の宣言の仕方、代入の仕方などは、配列の場合も含めてJavaの他のプリミティブと同じやり方で行えます。

charの配列は文字の集まりです。ですが、charの配列はStringそのものではありません。charの配列は、charをひとまとめにして取り扱うためのもので、インデックスで素早くアクセスしたい場合に一時的に使うもの、くらいの感覚でいてください。

charをフィールドや配列で使った時は、初期値は0になります。これは他の数字型プリミティブと同じ動きです。

2-1-1.charへは065535以外は代入できない

charは065535までの整数なので、小数点以下がある数字、マイナスの数字、65536以上の数字を直接代入できません。

ただし、それらをcharにキャストしたなら話は別です。仕組み的には、intにキャストされた後、あらためてcharにキャストされます。

charはキャストしないで使うのが普通なので、キャストの仕組みの詳細は省きます。でも、charは数字型なので、intdoubleなどの間でこのようなキャストができることは、頭の片隅に入れておきましょう。

プリミティブ型同士のキャストのロジックは以下の記事でも触れていますので、参考にしてください。

関連記事

2-2.charのリテラル表現のいろいろ

2-2-1.10進数、2進数、8進数、16進数での表現

Javaでは、数字は10進数以外にも、2進数、8進数、16進数で表現できます。charで扱える065535の範囲内なら、それらの表現でも意味は同じです。16進数なら、後述するUnicodeのコードポイントと見た目の値が同じになるので(※)、分かりやすくなるケースもあるかもしれませんね。

※もう少し正確にお伝えするなら、charを数字のリテラルで記述する場合は、UTF-16というエンコーディングでの数字であって、コードポイントとは必ずしも同じになりません。例えば、後述するサロゲートペアの範囲の文字は違う値になります。

2-2-2.文字の数字はシングルクォーテーションでくくっても表せる

Javaでは一つの文字に対する数字を、シングルクォーテーション(‘)でくくっても表せます。ずっとお伝えしているとおり、charは整数のデータ型ですが、数字そのままでは文字が何か分かりづらいので、文字そのものでの表現もできるのです。

”で数字の代わりに表現できるのは一文字だけです。複数の文字をでくくってしまうとコンパイルエラーになります。文字を“”(ダブルクォーテーション)でくくるとStringになるのですが、JavaではcharStringは違うモノなので相互に代入はできず、こちらもコンパイルエラーになります。

”でくくられたモノは、Javaのプログラム上ではその文字が表す数字として扱われます。ですので、以下のif文はtrueになりますし、“-“を付けたり-1と掛け算すればマイナスの数字になりますし、char同士を足し算できたりします。これで、文字は数字の別表現なのだと、おわかりいただけたでしょうか。

2-2-3.特殊な文字はエスケープシーケンスで表す

ある種の文字は、直接ソースコード上に書いても目に見えづらかったり、扱いづらかったりします。例えばタブや改行です。それらの文字を表現するには、「\」と組み合わせた、エスケープシーケンスという特別な書き方があります。エスケープシーケンスでの文字の表現は、Stringの中でも使えます。

  • バックスペース \b (\u0008でも同じ)
  • 水平タブ \t (\u0009でも同じ)
  • 改行 \n (\u000aでも同じ)
  • 改ページ \f (\u000cでも同じ)
  • 復帰 \r (\u000dでも同じ)
  • ダブルクォーテーション \” (\u0022でも同じ)
  • シングルクォーテーション \’ (\u0027でも同じ)
  • \文字 \\ (\u005cでも同じ)

2-2-4.Unicodeのコードポイントでの文字指定

Unicodeの文字には、一つ一つに数字が割り当てられています。その数字をコードポイント(codepoint)と呼びますが、charを使う上でもコードポイントが使えます。コードポイントで文字を表す場合は、Javaでは「\u + コードポイント」を使い、これはUnicodeエスケープとも呼ばれます。

【参考】List of Unicode characters

https://en.wikipedia.org/wiki/List_of_Unicode_characters

 

【参考】Code Charts

http://unicode.org/charts/

例えば、Unicodeコードポイントは「U+3042」なので、Unicodeエスケープでは「\u3042」です。コードポイントを使えば、日本語環境では入力が難しい文字もリテラルで表現できます。そして、コードポイントでの文字の表現は、Stringの中でも使えます。

2-2-5.【参考】2つのcharで表現するサロゲートペア

コードポイントとUTF-16charが表す数字は基本的には同じです。ただ、ごく初期のUnicodeならすべての文字でそれが通じましたが、Unicode 2.0で追加された「サロゲートペア(代用対)」と呼ばれる範囲(いわゆる追加面)の文字は違います。

サロゲートペアの範囲にある文字は1つのcharでは表現できず、2つのcharのペア(組み合わせ)で表現します。char配列の長さもその分伸びます。コードポイントも16ビットの範囲を超えたところにありますので、コードポイントの数字をJava上で表すならintを使うことになります。

サロゲートペアの詳細はこの記事の範囲を超えますので、説明は省略します。でも、いわゆる𠮷(つちよし)や𩸽(ほっけ)はサロゲートペアの範囲にある文字ですし、絵文字もそうです。これらの文字の範囲をプログラムで扱う場合は、サロゲートペアについて学んでおくといいでしょう。

2-3.charは==で比較する

charを比較する時は、値を比較する演算子の==を使います。charはそれ自体が一つの数字なので、単純に数字として比較すれば同じ文字か分かります。

charは何かのクラスのインスタンスではありませんので、==で安全に比較できるのです。もちろん、大小関係を判断する > >= < <=なども、他の数字に使う場合と同じように使えます。

2-3-1.charとStringはどちらかに寄せて比較する

繰り返しですが、charStringJavaでは違うモノなので、==では比較できません。String.equalsによる比較でも、もちろんfalseになります。

charとStringを比較するなら、以下のようにcharStringのどちらかに寄せなければなりません。charStringの変換方法については後述します。


3.charとStringの使い方いろいろ

この章では、Javaのプログラミング上でよく見かける、charStringを関連させて使うパターンを紹介します。

Javaではcharをそれ単独で使うことはあまりありません。charを最終的にStringにしたり、Stringからcharを取り出すなど、charStringを組み合わせて使うことが普通です。

3-1.charをStringに変換する

charの一文字をStringに変換するには、String.valueOf(char)あるいはCharacter.toString(char)を使うと簡単です。

3-2.複数のcharを一つのStringに変換する

char同士を+しただけでは、charで表している文字が繋がったStringにはできません。charが表す数字を足し合わせた値を持つintになるだけです。

このやり方はいろいろあって、“”を間に挟む、String.valueOfをして+する、StringBuilderを使う、String.formatを使うなどがあります。後述する、char配列からStringを作る方法でも構いません。

3-3.charの配列をStringに変換する

charの配列をStringに変換するには、StringのコンストラクタのString(char[])を使うといいでしょう。

あるいは、StringBuildercharの配列をappendした後にtoStringすれば、他の文字・文字列ともお手軽につなげられます。

3-4.Stringから指定インデックスのcharを取得する

Stringから、指定したインデックスにあるcharを取得するには、String.charAtを使います。Stringのインデックス範囲外の数字を指定すると、メソッド呼び出し時に例外が発生するので気を付けましょう。

3-5.Stringをcharの配列に変換する

Stringをcharの配列に変換するなら、String.toCharArrayを使うのがお手軽です。

3-6.Stringとcharを連結する

Stringとcharは、+を使えば二つをつなげた新しいStringが作られます。結果の文字列では、charが数字になることはありませんので、ご安心を。もちろん、StringBuilderなどを使ってつなげても構いません。

3-7.charを2進数、10進数、8進数、16進数の文字列に変換する

プログラムのデバッグなどで、charを文字ではなく、2進数、8進数、10進数、16進数で出力したい時があります。特に文字コード表は16進数のことが多いので、文字そのものよりも16進数の方が便利なことがあります。

いずれのパターンでも、Javaの標準APIだけを使うなら、String.formatを使うと簡単でしょう。2進数の場合は、Integer.toBinaryStringを組み合わせると楽にできます。


5.charとCharacter

Javaでは16ビットの整数を表現するために、charCharacterおよびshortShortの四つの方法があります。

charとshortは文字と数字の違いなのでそういうように使い分ければいいとして、Javaプログラミングの初心者は、なぜ同じ文字の表し方がcharCharacterで二つあるのか混乱すると思います。

この章ではその理由と、charCharacterの使い分けの方針などをお伝えします。

5-1.二種類の表現方法は性能確保のため

Javaではプリミティブ型のcharと、クラスのCharacterは別物です。C#などではこういう区別がないのに、なぜJavaではあるのか。これは、Javaが生まれた当時にプログラムの実行速度を確保するためでした。

Javaは1995年に登場したプログラミング言語です。当時のCPUのクロック周波数は今とは桁が違い、一般向けのCPUでようやく100MHzを超えたくらい。メモリの量も全体で数MB~数10MBと非常に乏しかったものです。

charは16ビットの数字そのものなので、楽に速く扱えます。しかし、charをクラスとすると、一つのcharの数字を表すのに16ビットよりもずっと多くのメモリを使います。簡単な計算をするにも、処理上では余分なオーバーヘッドが発生します。

5-2.クラスのCharacterならnullを表現できる

JavaでCharacterを使うのは、値がない場合すなわちnullを表現したい時です。例えば、SQLでは値の有り無しをNULLかどうかで表現できますが、それをJavacharでは上手に表現できません。charには必ず何かの値があるからです。なお、ここでのnullは、文字あるいは数字としての0x00とは別のものです。

そういう時に参照型であるCharacterを使えば、値がないことをnullとして表現できます。Characterをどういう時に使うべきか分からない方は、その変数でnullを表現する必要があるかを一つの指針にしてみてください。

あとCharacterを使うのは、Characterが持つメソッドを使いたい時と、ListMapSetなどのCollectionフレームワークを使いたい時です。Collectionフレームワークはクラスが対象ですので、Characterを使います。後述するオートボクシングにより、使い分けをあまり意識せずに済むようになりました。

5-3.オートボクシングでcharCharacterを自動変換する

Java 1.5でオートボクシング(auto boxing)という仕組みが導入されました。オートボクシングで、charCharacterをプログラム上でほぼ同じものとして扱えます。

プログラム上でcharを使う所ではCharacterを使えますし、Characterを使う所ではcharが使えます。本当のプログラム上は相変わらずcharCharacterは別物なのですが、その違いをJavaが裏で自動的に変換をしてくれるのです。

これでJavaの面倒な部分がある程度解消されました。ですが、前述のとおりCharacternullを表せますが、charは必ず何かの整数なので、nullに相当するものがありません。

ですので、以下のように予期せぬところでNullPointerExceptionが発生したりします。これは2019年のJava 11の時点でも変わっていません。プログラマが注意するか、Optionalを使う必要があります。


5.まとめ

この記事では、Javacharに関する情報をお伝えしてきました。char16ビットの整数で、065535の範囲でUnicodeUTF-16での一文字を表します。charの表し方はいろいろありますが、結局のところ、一つの数字がいろいろな見た目をしているにすぎません。

JavaではcharStringは違うものなので、比較したりする場合はどちらかに変換しなければなりません。charからStringを作ったり、Stringからcharを取り出したりする方法なども、普通にプログラムを作る上で必要と思われるものをお伝えしてきました。

なお、この記事では、Unicodeのもう少し深い知識、例えばサロゲートペアの詳細、結合文字、正規化、双方向テキスト、包摂、異体字セレクタなどには触れませんでした。Javaに限らずUnicodeを本格的に扱うには、それらの知識も必要となることがあります。

JavaのcharStringUnicodeは一心同体なので、この記事を足掛かりに、Javaで文字を扱うために必要な知識を身に着けていってください。

私たちは、全てのエンジニアに市場価値を高め自身の望む理想のキャリアを歩んでいただきたいと考えています。もし、今あなたが転職を検討しているのであればこちらの記事をご一読ください。理想のキャリアを実現するためのヒントが見つかるはずです。

8/28(水)開催決定!
【テックジム×ENGINEER.CLUB】ゼロからはじめるPythonプログラミング入門講座

プログラミングは初めてだけどPythonから始めてみたいという方のために、無料のハンズオン開発講座をテックジム×ENGINEER.CLUBで共同開催することになりました。開催日時は以下の通りです。

  • 8月28日(水)19時〜21時 東京開催

本講座で学んでいただく「TechGYM方式」とは、基礎知識なしでも座学なしでプログラミングに専念できるように設計されたプログラミングのカリキュラムメソッドです。「まるで魔法にかかったようにプログラミンスキルが習得できる」と評判の本講座をぜひ一度体験してみてください。

『技術力』と『人間力』を高め市場価値の高いエンジニアを目指しませんか?

私たちは「技術力」だけでなく「人間力」の向上をもって遙かに高い水準の成果を出し、関わる全ての人々に感動を与え続ける集団でありたいと考えています。

高い水準で仕事を進めていただくためにも、弊社では次のような環境を用意しています。

  • 定年までIT業界で働くためのスキル(技術力、人間力)が身につく支援
  • 「給与が上がらない」を解消する6ヶ月に1度の明確な人事評価制度
  • 平均残業時間17時間!毎週の稼動確認を徹底しているから実現できる働きやすい環境

現在、株式会社ボールドでは「キャリア採用」のエントリーを受付中です。

まずは以下のボタンより弊社の紹介をご覧いただき、あなたの望むキャリアビジョンをエントリーフォームより詳しくお聞かせください。