はじめに
Javaの参照型は、String、ArrayList、HashMap、自作のclassなどを扱うときに避けて通れない考え方です。プログラミング初心者がJavaプログラミングでつまずきやすいのは、変数に値そのものが入る場合と、オブジェクトへの参照が入る場合を同じ感覚で読んでしまう点にあります。
その違いを押さえると、null、NullPointerException、メソッド呼び出し、配列、コレクションの見え方が整理できます。Javaのコーディングでは参照型を正しく読む力が、サンプルコードを理解する速さにも直結するのが基本です。
具体的には、Javaの参照型は「オブジェクトを直接変数に詰める」のではなく、「オブジェクトへたどるための参照を変数が持つ」と考えると理解しやすくなります。この見方を軸にすると、プログラミング学習でよく混乱する代入、比較、引数渡しの挙動も追いやすくなります。
- Java SE 21 / JDK 21
- TypeScript 5.4 / Python 3.12 / Google Chrome 126
- Javaの参照型とプリミティブ型の違い
nullとNullPointerExceptionを避ける考え方- クラス、文字列、配列、コレクションで参照型を読む方法
- カスタムクラスを使ったJavaプログラミングの組み立て方
- TypeScript、Python、JavaScriptとの参照の比較
| 対象 | 型の分類 | 主な例 | コーディング時の見方 | 注意点 |
|---|---|---|---|---|
| 数値 | プリミティブ型 | int、double | 値そのものを扱います | nullを代入できません |
| 真偽値 | プリミティブ型 | boolean | trueかfalseを保持します | オブジェクト操作はできません |
| 文字列 | 参照型 | String | 文字列オブジェクトへの参照を扱います | 比較ではequalsを使います |
| 配列 | 参照型 | String[]、int[] | 複数要素を持つオブジェクトを参照します | 要素変更が共有される場合があります |
| リスト | 参照型 | ArrayList、List | 可変長の要素集合を操作します | ジェネリクスの型をそろえます |
| マップ | 参照型 | HashMap、Map | キーと値の対応を管理します | 順序保証の有無を確認します |
| 自作クラス | 参照型 | Car、MyCustomClass | 状態と振る舞いをまとめます | 初期化漏れに注意します |
公式ドキュメントによれば、Javaの型はプリミティブ型と参照型に分かれ、参照型にはクラス型、インターフェース型、配列型などが含まれます。詳しい分類はJava Language SpecificationのTypes, Values, and Variablesで確認できます。
これらの分類は、単なる用語の整理にとどまりません。Javaプログラミングでは、値を渡しているのか、オブジェクトへの参照を渡しているのかによって、メソッド呼び出し後の状態が変わるためです。
Javaとは
Javaは、JVM上で動くプログラムを作るための言語です。結論から言うと、Javaプログラミングでは.javaファイルをjavacでコンパイルし、生成された.classファイルをjavaコマンドで実行する流れを理解すると、参照型の説明も追いやすくなるのが目安です。
その仕組みでは、ソースコードが直接OSに依存するのではなく、Java Virtual Machineがバイトコードを解釈または最適化して動かします。プログラミング初心者にとっては、JDKが開発道具一式、JREが実行環境、JVMが実際に動作を支える層と整理すると理解しやすいです。
歴史と特徴
Javaは1990年代に登場し、現在もサーバーサイド、Android関連、業務システム、組み込み領域で使われています。そのため、古い書き方と新しい書き方が混在したサンプルコードに触れる機会も多く、JavaプログラミングではAPIの世代を意識する読み方が必要になるのがポイントです。
一方、言語の中心にはオブジェクト指向、静的型付け、例外処理、豊富な標準ライブラリがあります。Object、String、Integer、Listなどを扱う場面が多いため、参照型の理解は早い段階で役立ちます。
公式APIでは、java.lang.Objectがクラス階層の根に位置づけられているのが一般的です。これを知ると、Javaの多くのクラスが共通の土台を持ち、toString、equals、hashCodeといったメソッドを共有する理由も見えてきます。
こうした特徴により、Javaのコードは大規模な開発でも型の意図を追跡しやすい形になっています。ただし、型が明示されるからといって参照先の状態まで自動で分かるわけではないため、プログラミング学習では変数宣言とオブジェクト生成を分けて読む必要があるのが現実的です。
基本的な文法
Javaの文法では、変数宣言時に型を明示するのが基本になります。int、double、booleanのようなプリミティブ型と、String、Integer、Carのような参照型を分けて読むことが、プログラミング学習の土台になります。
その上で、if、for、while、switchなどの制御文が処理の流れを作りますし、ここがポイントです。public、private、static、void、returnといったキーワードは、メソッドやクラスの使われ方を決める部品として読みます。
具体的には、JavaのList型を学ぶと、型宣言、ジェネリクス、参照型の関係が一度に出てきます。Javaプログラミングのコーディングでは、単語を暗記するより、値がどこにあり、変数が何を指しているかを追うほうが扱いやすくなると整理できます。
この見方を持つと、mainメソッド、String[] args、System.out.printlnのような定番の記述も読みやすくなります。argsは文字列配列への参照であり、System.outは標準出力へつながるオブジェクトとして扱われます。
参照型の基本
参照型は、オブジェクトや配列そのものではなく、それらに到達するための参照を変数に入れる型です。JavaではString、配列、クラスのインスタンス、インターフェース型の変数がこの分類に入りますが、これは押さえたい点です。
これに対してプリミティブ型は、intやcharのように値を直接扱います。そのため、代入、比較、メソッド呼び出しの見え方が変わり、プログラミング初心者が混乱しやすい差になります。
概念の説明
参照型の変数は、ヒープ上にあるオブジェクトへ向かう参照を保持すると理解できます。厳密なメモリアドレスを直接操作するわけではありませんが、学習段階では「オブジェクトへのリンク」と捉えると、代入の意味を追いやすくなります。
結果: 期待される状態は、変数strがStringオブジェクトを参照している状態です。
このサンプルコードでは、String型の変数に文字列リテラルを代入しています。一般にStringは不変オブジェクトとして扱われ、文字列操作の結果は別のString参照として受け取る場面が多くなると覚えるとよいでしょう。
そのため、strの中に文字列の全データが詰まっていると考えるより、文字列オブジェクトへたどるための参照が入っていると読むほうが自然です。この読み方は配列や自作クラスにもそのまま応用できます。
プリミティブ型との違い
プリミティブ型と参照型の違いは、変数が保持するものにあります。int num = 42では数値そのものを扱いますが、Integer numObjectでは数値を包むオブジェクトへの参照を扱いると考えられます。
結果: 期待される状態は、numがプリミティブ値を保持し、numObjectがIntegerオブジェクトを参照する状態です。
new Integer(42)コンストラクタはJava 9以降で非推奨です。現行のコーディングではInteger.valueOf(42)またはオートボクシングによるInteger numObject = 42;を使う書き方が一般的です。その違いは比較にも表れます。参照型で==を使うと同じオブジェクトを指しているかを見るため、文字列の内容比較ではequalsを使うと整理できます。
一方、オートボクシングによりintとIntegerの変換が自動で行われる場面もあると言えるでしょう。見た目が短くても内部では型変換が絡むため、Javaプログラミングでは警告や非推奨APIの表示を軽視しない読み方が求められます。
メモリー管理
Javaのオブジェクトは主にヒープに作られ、不要になったオブジェクトはガベージコレクションの対象になります。参照が残っている間は、そのオブジェクトへ到達できるため、必要な状態として扱われますし、これが一つの目安です。
結果: 期待される状態は、greetingがヒープ上のStringオブジェクトを参照する状態です。
ただし、文字列リテラルでは文字列プールも関係するため、すべてのString生成を同じ図で説明すると誤解が生まれます。学習段階では、参照型の変数がオブジェクトへの到達手段を持つ点に注目するとよいでしょう。
このとき、到達不能になったオブジェクトは将来的に回収対象になります。回収のタイミングはJVMに委ねられるため、Javaのコーディングでは明示的な解放より、不要な参照を長く保持しない設計を意識するのが基本です。
参照型の使い方
参照型の使い方は、クラスからオブジェクトを作り、そのオブジェクトのフィールドやメソッドを参照経由で使う流れに集約できます。Javaプログラミングのサンプルコードを読むときは、newで何が作られ、どの変数がそれを指すかを追います。
その読み方は、Javaのオーバーライドを学ぶ場面にもつながりますが、覚えておくと役立つでしょう。参照型の変数が親クラスやインターフェース型で宣言され、実体が別クラスのオブジェクトになることがあるためです。
クラスとオブジェクト
クラスはオブジェクトの構造を定義し、オブジェクトは実際にメモリ上で扱われる実体になります。class内のfieldが状態を持ち、methodが振る舞いを表すため、参照型の変数はその実体にアクセスする入口になります。
このとき、複数の変数が同じオブジェクトを参照することもあるのが目安です。片方の変数からフィールドを変更すると、もう片方から見た状態も変わるため、プログラミング初心者は「コピーされたのか、共有されたのか」を意識すると理解が進みます。
基本的に、newが出てきた位置では新しいインスタンスが作られます。逆に、既存の変数を別の変数へ代入しただけでは、参照先のオブジェクトが複製されたとは限りません。
サンプルコード1:オブジェクトの作成と利用
このサンプルコードでは、Carクラスにspeedフィールドとrunメソッドを定義するのがポイントです。mainメソッドでnew Car()を呼び出し、参照型の変数myCarを通じて状態と振る舞いを扱います。
結果: 期待される出力は「車が走りますし、ここを基本と考えるとよいでしょう。速度: 60km/h」です。
そのポイントは、myCar.speedでフィールドを書き換え、myCar.run()で同じオブジェクトのメソッドを呼び出している点です。Javaのコーディングでは、ドット演算子.の左側にある参照が何を指すかを確認すると、処理の流れを読みやすくなります。
サンプルコード2:文字列の操作
文字列はJavaで最もよく使われる参照型の一例です。Stringにはlengthやsubstringなどのメソッドがあり、公式APIのjava.lang.Stringでも文字列の検査、比較、検索、抽出に関する操作が整理されています。
結果: 期待される出力は、文字列の結合、str1の長さ、部分文字列が順に表示される内容です。
この例では、str1 + " " + str2で新しい文字列を作り、length()で長さを取得し、substring(4, 7)で一部を取り出します。ただし、添字は0から始まるため、プログラミング学習では範囲指定の開始位置と終了位置を丁寧に読む必要があります。
同様に、文字列の比較では==ではなくequalsを使う場面が中心になるのが一般的です。参照型であるStringは内容が同じでも別オブジェクトの可能性があるため、比較の目的を明確にして書き分けます。
参照型の応用
参照型に慣れると、コレクションフレームワークの理解が進みます。JavaのArrayListやHashMapは複数のデータを扱う参照型であり、業務系のJavaプログラミングでも頻出するのが現実的です。
一方、コレクションは要素を内部に持つため、変数の代入だけで中身まで複製されるとは限りません。コーディング時には、add、put、get、removeがどのオブジェクトに対して呼ばれているかを確認します。
コレクションフレームワーク
コレクションフレームワークは、リスト、セット、キュー、マップなどのデータ構造を扱うための標準ライブラリです。Listは順序のある集合、Setは重複を避ける集合、Mapはキーと値の対応を表す構造として使い分けます。
具体的には、可変長の一覧が必要ならArrayList、キーから値を取り出したいならHashMapを選ぶ場面が多くなると整理できます。関連する型の扱いはJavaアノテーションやジェネリクスの学習ともつながります。
その選択では、要素数、検索方法、順序の必要性、重複の扱いを同時に考えます。Javaの標準ライブラリは選択肢が多いため、プログラミング初心者は代表的な型から動きを確かめると理解が安定すると理解できます。
サンプルコード3:リストの利用
このサンプルコードでは、ArrayList<String>で文字列だけを入れるリストを作ります。ジェネリクスの<String>により、意図しない型の混入をコンパイル時に防ぎやすくなります。
結果: 期待される出力は、追加した要素を含むリスト表現です。
結果: 期待される表示例は、ArrayListに追加した順序で要素が並ぶ内容です。
この例では、list.addで同じリストオブジェクトに要素を追加しています。参照型の変数listはリスト本体への入口であり、プログラミング初心者は変数名ではなく参照先のオブジェクトに注目すると読みやすくなります。
サンプルコード4:マップの利用
HashMapは、キーから値を取り出すデータ構造です。商品名と価格、ユーザーIDと名前、設定名と値のように、対応関係を扱うコーディングで使われますし、ここがポイントです。
結果: 期待される出力は、キーと値の対応を含むマップ表現です。
結果: 期待される表示例は、各果物名に価格が対応する内容です。
ただし、HashMapは挿入順を保証する目的のクラスではありません。順序が必要な場合はLinkedHashMap、キー順が必要な場合はTreeMapを検討するなど、Javaプログラミングではデータ構造の性質に合わせて選びます。
💡 Tips: コレクションを学ぶときは、List、Set、Mapのインターフェース名で受け、必要に応じてArrayListやHashMapを実体として選ぶ読み方が役立ちます。
参照型の注意点
参照型で特に押さえたいのは、null、比較、共有、可変性です。Javaのサンプルコードでエラーが起きる場面の多くは、変数がオブジェクトを参照している前提でメソッドを呼び出したのに、実際にはnullだったケースになると覚えるとよいでしょう。
そのため、参照型を扱うコーディングでは、オブジェクトが作られたタイミングと、参照が失われたタイミングを読む必要があります。プログラミング学習では、エラーメッセージの行番号だけでなく、その変数に何が代入されたかを戻って確認すると整理できます。
nullとは
nullは、参照型の変数が何も参照していない状態を表す特別な値です。String str = null;では、strという変数は存在しますが、参照先のStringオブジェクトはありません。
一方、空文字""は長さ0のStringオブジェクトを参照している状態です。nullと空文字を同じものとして扱うと、条件分岐や入力チェックで誤りが起きやすくなると考えられます。
逆に、nullを恐れてすべてを空文字や空配列に置き換えると、値がない状態と値が空の状態を区別しにくくなります。Javaの設計では、戻り値、引数、フィールドのどこで欠損を許すのかを明確にすると、後続のコーディングが読みやすくなります。
NullPointerExceptionの回避方法
NullPointerExceptionは、nullの参照に対してメソッド呼び出しやフィールドアクセスを行ったときに発生すると言えるでしょう。Javaでは例外メッセージが改善されており、どの変数がnullだったかを読み取りやすい場合があります。
基本的に、str != nullのようなチェック、Objects.requireNonNullによる早期検出、戻り値にOptionalを使う設計などが対策になります。ただし、Optionalはフィールドや引数に乱用せず、戻り値で「ない可能性」を表す用途に寄せると扱いやすくなるのが基本です。
これらの対策は、例外を見えなくするためではなく、参照がない状態をコード上で表現するために使います。特にAPI境界や外部入力を扱う箇所では、受け取った値がnullになり得るかを文書化しておくと、Javaプログラミングの保守性が上がります。
サンプルコード5:NullPointerExceptionを避けるテクニック
このサンプルコードでは、strがnullかどうかを先に判定してからequalsを呼び出するのが目安です。短絡評価により、左側のstr != nullがfalseなら右側のstr.equals("hello")は評価されません。
結果: 期待される出力は「str is null or not equal to ‘hello’」です。
このとき、&&の左側でnullを除外しているため、右側のメソッド呼び出しに進まず安全に分岐できます。文字列リテラルが固定なら"hello".equals(str)と書く方法もあり、参照型の比較では呼び出し元がnullにならない形を選ぶと安定します。
try、catch、finallyで扱えますが、NullPointerExceptionは捕捉して隠すより、発生しない設計へ寄せるほうが保守しやすくなるのがポイントです。参照型のカスタマイズ
参照型は標準クラスだけでなく、自作クラスでも作れます。Javaプログラミングでは、業務上の概念をCustomer、Order、Productのようなクラスに分け、状態と振る舞いをまとめていきます。
その設計では、フィールドをprivateにし、コンストラクタやメソッドを通じて状態を扱う形がよく使われますが、これは押さえたい点です。これにより、外部から自由に値を書き換えられる範囲を抑え、コーディング時の意図をクラスの形に反映できます。
カスタムクラスの作成
カスタムクラスを作るときは、クラス名、フィールド、コンストラクタ、メソッドの順に読むと構造を把握しやすくなります。クラス名は一般に大文字始まりのUpperCamelCase、メソッド名や変数名はlowerCamelCaseで書かれますし、これが一つの目安です。
具体的には、private int attribute1が整数の状態、private String attribute2が文字列の状態を表します。コンストラクタ内のthis.attribute1は、引数ではなくインスタンス側のフィールドを指す記法です。
結果: 期待される状態は、MyCustomClassに2つのフィールドと表示用メソッドが定義された状態です。
このクラス単体ではmainメソッドがないため、通常は別のクラスからインスタンス化して使います。プログラミング初心者は、クラス定義と実行開始点の違いを分けて読むと、サンプルコードの役割を把握しやすくなります。
ただし、学習用の短いクラスではgetterやsetterを省略する場合があるのが一般的です。実際のJavaプログラミングでは、不変にしたい値はfinalを使う、変更を許す値はメソッド経由にするなど、参照型の状態管理を設計として考えます。
サンプルコード6:カスタムクラスの利用
このサンプルコードでは、先に定義したMyCustomClassをnewで生成し、参照型の変数myCustomClassで受け取ります。その後、displayAttributes()を呼び出してフィールドの値を出力するのが現実的です。
結果: 期待される出力は「Attribute1: 5」と「Attribute2: Hello」が順に表示される内容です。
この例で大切なのは、new MyCustomClass(5, "Hello")がオブジェクトを作り、変数がその参照を受け取る点です。displayAttributesは同じオブジェクトの状態を読むため、参照型の変数とインスタンスの対応が明確になります。
ところで、クラスの責務が増えすぎると、どの参照がどの状態を変更するのか追いにくくなります。Javaのエスケープ処理のように、文字列や入力値の扱いを分けて学ぶと、クラス分割の考え方も身につきますが、覚えておくと役立つでしょう。
参照型と他の言語
参照型の考え方はJavaだけで完結しません。TypeScript、Python、JavaScriptでも、オブジェクトや配列を変数に代入したときに「同じ実体を指しているのか」を意識する場面があります。
一方、言語ごとに型システムや代入の説明は異なります。Javaは静的型付けでコンパイル時の型チェックが強く、TypeScriptはJavaScriptに型注釈を加え、PythonやJavaScriptは実行時のオブジェクト参照を柔軟に扱いると整理できます。
これらを比較すると、Javaの参照型は制約が多いかわりに、型の意図を事前に確認しやすい設計だと理解できます。プログラミング学習では、同じ「参照」という言葉でも、言語ごとの型検査と実行時の動きを分けて読むと混乱を減らせます。
TypeScriptの参照型
TypeScriptでは、オブジェクトの形を型として表せますし、ここを基本と考えるとよいでしょう。公式のTypeScript HandbookのObject Typesでも、オブジェクトを通じてデータをまとめて受け渡す考え方が扱われています。
結果: 期待される出力は「John」です。
この例では、userがnameとageを持つオブジェクトを参照しています。Javaのclassと完全に同じではありませんが、参照先のプロパティをuser.nameで読む点は似ていると理解できます。
Pythonの参照型
Pythonでは、リストや辞書などのオブジェクトを変数が参照します。変数同士の代入でリスト本体が複製されるとは限らないため、Javaの参照型を学んだ後に読むと、共有の挙動を比較しやすくなります。
結果: 期待される出力は「[0, 2, 3]」です。
その理由は、list2 = list1で同じリストを参照する状態になるためです。リストの複製が必要な場合は、Python側のcopyやスライスなどを検討する必要があると覚えるとよいでしょう。
JavaScriptの参照型
JavaScriptでも、オブジェクトや配列は参照を通じて扱われます。MDNのObjectリファレンスでは、Objectがキー付きコレクションや複雑な実体を保持する型として説明されています。
結果: 期待される出力は、プロパティaが3になったオブジェクトです。
この例では、obj.a = 3により、参照先オブジェクトのプロパティを変更していると考えられます。Javaのフィールド変更と似た見た目ですが、JavaScriptは動的型付けなので、型チェックのタイミングやエラーの出方に違いがあります。
ちなみに、Javaでうるう年を判定する処理のような小さな条件分岐でも、入力値をどの型で持つかは読みやすさに影響します。参照型とプリミティブ型を比較しながら学ぶと、プログラミング学習の理解が広がりますし、ここがポイントです。
まとめ
Javaの参照型は、オブジェクトや配列への参照を変数が保持する仕組みとして理解できます。プリミティブ型との違い、null、equals、コレクション、自作クラスをつなげて読むと、Javaプログラミングのコード全体が追いやすくなります。
その理解は、サンプルコードを写すだけの学習から、状態の変化を説明できる学習へ進む助けになると言えるでしょう。プログラミング初心者ほど、変数名ではなく参照先のオブジェクトに注目し、どのメソッドがどの状態を変えるのかを確認するとよいでしょう。
Javaのコーディングでは、new、null、==、equals、ArrayList、HashMap、this、privateなどが参照型の理解に深く関わります。これらを個別の暗記事項ではなく、同じオブジェクトモデルの部品として整理すると、Javaプログラミングの応用へ進みやすくなります。
なお、より細かいAPIの使い分けは公式ドキュメントで確認し、古いサンプルコードでは非推奨の書き方が混ざっていないかを点検してください。プログラミング学習を続ける際は、短いサンプルコードで参照の共有、コピー、比較を試せる形に分けると理解が安定するのが基本です。
これらの観点を持ってコードを読むと、エラーの原因を探すときにも判断材料が増えます。NullPointerExceptionなら参照がない状態、比較の誤りなら==とequalsの使い分け、コレクションの想定外の変化なら同じオブジェクトを共有していないかを順に確認できます。
そのため、参照型の学習は文法暗記ではなく、Javaのプログラムがメモリ上のオブジェクトをどう扱うかを読む練習になるのが目安です。小さなサンプルコードから始め、文字列、配列、リスト、マップ、自作クラスへ範囲を広げると、コーディング中の判断が安定します。
関連記事
- Java List型完全ガイド!初心者でもマスターできる7つのステップ
- Javaアノテーションの12選!初心者から上級者まで徹底ガイド
- Javaでうるう年を判定!初心者でも分かる9ステップ解説
- Javaエスケープ処理の10ステップマスターガイド
- Javaでマスターする!オーバーライドのたった7つのステップ
※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。


