Javaは参照渡しがないの?他の言語との違いについてもご紹介

- システム
エンジニア - Javaの参照渡しとはどのようなことなのでしょうか。
- プロジェクト
マネージャー - Javaでいう参照渡しは変数の参照先(アドレス)を渡すことを言います。
Javaには参照渡しがない⁉他言語との違いやString型の書き換え方も解説します!
C/C++をはじめ、C#、VB.net、果てはExcel VBAにも存在している「参照渡し」ですが、Javaには「参照渡し」が存在しません。
ただし、Javaでも「参照渡し」に似たような処理は作れます。また、Javaではこの処理を「参照の値渡し」と呼ぶこともあるため、余計に混乱してしまう方も多いのではないでしょうか。
本記事では、Javaと他言語(主にC#)に触れながら、Javaの「参照渡し」について紹介していきます。
そもそも『参照渡し』とは? 参照渡しの概念について説明します
まず、そもそも「参照渡し」とはどういう概念なのか見て行きましょう。なお、他言語にて、充分に理解されている方は読み飛ばしていただいて構いません。
まず、「参照渡し」を語る上で,欠かせない相棒は「値渡し」です。
「値渡し」とは値を渡すもので、「参照渡し」とは参照先を渡すものと、読んで字のごとしですが、抽象的すぎてイメージが難しいと感じる方も多いことでしょう。
以下で詳しく解説しましょう。
値渡し
先述の通り、値渡しとは「値を渡すもの」です。
もう少し詳しく説明すると「値(プリミティブ)型の中身をコピーして渡すもの」です。
ちなみに、値(プリミティブ)型は、「boolean、byte、char、short、int、float、long、double」の8つです。
「値のコピーを渡すから値渡し」と考えれば覚えやすいでしょう。
実際にソースコードで見てみましょう
1 2 3 4 5 6 7 8 9 10 11 12 |
public class ValuePass{ public static void changeValue(int x){ x = 777; } public static void main(String[] args){ int x = 111; System.out.println(x); changeValue(x); System.out.println(x); } } |
実行結果は次のようになります
1 2 |
111 111 |
changeValueには、値“111”を渡しているので、書き換えることはできません。
参照渡し
対して、参照渡しとは「参照先を渡すもの」だと先述しました。もう少し詳しく説明すると、「変数のアドレスを渡すもの」です。
値渡しの時は、値(プリミティブ)型にする必要がありましたが、参照渡しはアドレスを渡すので、基本的にはどんな型でも渡すことができます。
「変数の参照先(アドレス)を渡すから参照渡し」と考えれば覚えやすいでしょう。
なお、Javaには参照渡しはありませんので、ここでは「参照渡しのようなもの」のソースコードを紹介します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class ReferencePass{ public static class Pages{ public int value; public Pages(int value){ this.value = value; } } public static void changeValue(Pages book){ book.value = 777; } public static void main(String[] args){ Pages book1 = new Pages(111); System.out.println("changeValue: "); System.out.println(book1.value); changeValue(book1); System.out.println(book1.value); } } |
実行結果は次のようになります
1 2 3 4 |
changeValue: 111 777 |
changeValueには、book1のアドレス値を渡しているので、値が777に書き換えられて戻ってきます。
なぜJavaには参照渡しがないの?
ここでは、先ほど紹介したソースコードに、不可解なコードを追加しています。
「changeValue」と「NewValue」の違いは何かを考えながら、こちらのソースコードを見てみてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
class ReferencePass{ public static class Pages{ public int value; public Pages(int value){ this.value = value; } } public static void changeValue(Pages book){ book.value = 777; } public static void NewValue(Pages book){ book = new Pages(888); } public static void main(String[] args){ Pages book1 = new Pages(111); System.out.println("changeValue: "); System.out.println(book1.value); changeValue(book1); System.out.println(book1.value); Pages book2 = new Pages(222); System.out.println("NewValue: "); System.out.println(book2.value); NewValue(book2); System.out.println(book2.value); } } |
これを実行すると
1 2 3 4 5 6 |
changeValue: 111 777 NewValue: 222 222 |
となります。
つまり、changeValueとNewValueの違いは「新しいオブジェクトを割り当てようとした」ことです。
Javaでは、オブジェクトを初期化しようとすると、今までの領域はそのままにして新しい領域を確保してしまうことを覚えておきましょう。
上記のソースコードを抜粋して説明します。
1 2 3 4 5 6 |
Pages book2 = new Pages(222); ⇒ 100番地にbook2を確保 NewValue(book2); ⇒ 100番地にbook2があることを知らせる public static void NewValue(Pages book){ ⇒ 100番地にbookがあることを知る book = new Pages(888); ⇒ 200番地に新しいbookを作る } ⇒ そのまま戻る つまり、100番地のbook2の値は変わらない。 |
さらに、C#で見ると違いが分かりやすいです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
private void ReferencePass(List<string> arg){ arg = new List<string>(); arg.Add("ドーナツ"); } List<string> list = new List<string>(); list.Add("プリン"); ReferencePass(list); System.Console.WriteLine(list[0]); =================================================== 実行結果:プリン =================================================== private void ReferencePass2(<strong><mark>ref</mark></strong> List<string> arg){ arg = new List<string>(); arg.Add("ドーナツ"); } List<string> list = new List<string>(); list.Add("プリン"); ReferencePass2(ref list); System.Console.WriteLine(list[0]); =================================================== 実行結果:ドーナツ</string></string></string></string></string></string></string></string> |
C#では「ref」を付ければ参照渡しになりますが、Javaには「ref」のような仕組みがありません。よって「Javaには参照渡しがない」ということになります。
Javaの参照渡しでString型を変更する方法
ここまでJavaの参照渡しについて紹介してきました。Javaでは「参照渡し」自体はないものの、似た処理は作れました。
続いて、「JavaのString型を参照渡しして、値を変更して戻す」という処理について見てみましょう。
JavaのString型は「immutable な(状態を変えられない)」特殊なオブジェクトです。そのため、次のようなソースコードを書いても、addString内で変更した文字列は戻ってきません。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Main { public static void main(String[] args) { String str = "Hello."; addString(str); System.out.println(str); } public static void addString(String str) { str = str + "World."; } } =================================== 実行結果:Hello. |
これは「str = str + “World.”;」の時点で、新しい領域を確保してしまうからです。
なので、元のstrは何も変更されていない。という結果になります。
もし、addString内で変更した文字列を戻したい場合は「StringBuilder」もしくは「StringBuffer」を使ってください。
先ほどのソースコードを「StringBuilder」を使って書き換えると、こうなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Main { public static void main(String[] args) { <strong><mark>var str = new StringBuilder("Hello.");</mark></strong> addString(str); System.out.println(str); } <strong><mark>public static void addString(StringBuilder str) { str.append("World.");</mark></strong> } } =========================================== 実行結果:Hello.World. |
- システム
エンジニア - Javaでは参照渡しという概念ではないので、参照の値渡しと覚えれば良いのですね。
- プロジェクト
マネージャー - 参照の値渡しへの理解をより深めるために、Javaで実践してみましょう。
Javaで参照の値渡しを使ってみよう!
本記事では、「Javaの参照渡し」について紹介してきました。
Javaは基本的には値渡しになるので、メソッドで値を変えて戻す、という処理を作るには少し考慮が必要です。
他言語に慣れていると、どうしても「参照渡し」という言葉を使いたくなるでしょうが、Javaには参照渡しはありません。
Javaを用いる場合は、「参照の値渡し」を使いこなせるよう、本記事を参考にしてください。
FEnetJava・Javaコラムは株式会社オープンアップシステムが運営しています。
株式会社オープンアップシステムはこんな会社です
秋葉原オフィスには株式会社オープンアップシステムをはじめグループのIT企業が集結!
数多くのエンジニアが集まります。

-
スマホアプリから業務系システムまで
スマホアプリから業務系システムまで開発案件多数。システムエンジニア・プログラマーとしての多彩なキャリアパスがあります。
-
充実した研修制度
毎年、IT技術のトレンドや社員の要望に合わせて、カリキュラムを刷新し展開しています。社内講師の丁寧なサポートを受けながら、自分のペースで学ぶことができます。
-
資格取得を応援
スキルアップしたい社員を応援するために資格取得一時金制度を設けています。受験料(実費)と合わせて資格レベルに合わせた最大10万円の一時金も支給しています。
-
東証プライム上場企業グループ
オープンアップシステムは東証プライム上場「株式会社オープンアップグループ」のグループ企業です。
安定した経営基盤とグループ間のスムーズな連携でコロナ禍でも安定した雇用を実現させています。
株式会社オープンアップシステムに興味を持った方へ
株式会社オープンアップシステムでは、開発系エンジニア・プログラマを募集しています。
年収をアップしたい!スキルアップしたい!大手の上流案件にチャレンジしたい!
まずは話だけでも聞いてみたい場合もOK。お気軽にご登録ください。


Java新着案件New Job
官公庁向け業務システム開発/Java/東京都千代田区/【WEB面談可】/テレワーク
月給39万~44万円東京都千代田区(永田町駅)販売管理システム開発/Java/東京都中央区/【WEB面談可】/テレワーク
月給49万~55万円東京都中央区(京橋駅)生命保険会社向けシステム開発/Java/東京都千代田区/【WEB面談可】/テレワーク
月給42万~48万円東京都千代田区(大手町駅)社会保険システムのパッケージ開発/Java/東京都港区/【WEB面談可】/テレワーク
月給42万~48万円東京都港区(新橋駅)金融機関向けシステム更改/Java/東京都江東区/【WEB面談可】/テレワーク
月給46万~51万円東京都江東区(豊洲駅)大手通信会社者向けWebシステム改修/Java/東京都港区/【WEB面談可】/テレワーク
月給42万~48万円東京都港区(品川駅)