Javaでのアクセス修飾子の使い分け・なしにするとどうなるのか徹底的に解説!!

Java

こんにちは、uhablogです。
今回はJavaのアクセス修飾子について現役エンジニアであるuhablogが徹底的に解説していきます。

アクセス修飾子というのはJavaのメソッドやフィールドの前についているpublicやprivateのことです。
この記事では

  • アクセス修飾子とは
  • アクセス修飾子の種類

という基礎的な内容から、サンプルプログラムを用いた実践的な解説もしていきます。
Javaを勉強し始めた初学者の方やアクセス修飾子についていまいち理解できていない方におすすめの記事となっています!
ぜひ最後まで読んでいってください!

アクセス修飾子とは

Javaのプログラムを見たことある人・書いたことがある人であれば、メソッドやフィールドに対して「public」や「private」というものを見たことがある・知っている人は多いと思います。
この「public」や「private」というのがアクセス修飾子です。

このアクセス修飾子はメソッドやフィールドに対してアクセスの制限をかけています。
例えば、「このフィールドの値は外部で書き換えられたくない」というときにprivateを指定すると外部からの書き換えが不可能になります。
システムやプログラムが大規模になればなるほどどこからクラスが使われるかわかりません。
そうなったときに適切なアクセス修飾子を付与しておくことで、思わぬバグやエラーを防ぐことができます。

アクセス修飾子の種類

アクセス修飾子がメソッドやフィールドに対してアクセス制限をかけるものであることがわかりました。
ここからはそれぞれのアクセス修飾子について解説していきます。
Javaでのアクセス修飾子は次の4つがあります。

  • public
  • protected
  • デフォルト(指定なし)
  • private

それでは一つずつ見ていきましょう!

public

まずはpublicです。
publicが付けられたメソッドやフィールドはどこからでもアクセスすることが可能です。
一番制限が弱いアクセス修飾子となっています。

publicは「公共の」や「公開の」といった意味があるので、わかりやすいですね。

protected

protectedは同じパッケージのクラスからアクセスすることが可能です。
また違うパッケージであっても、継承しているサブクラスであれば利用可能になります。

デフォルト(アクセス修飾子の指定なし)

アクセス修飾子を指定しなかった場合はデフォルトとみなされます。
デフォルトは同じパッケージ内からのみ利用することが可能です。

private

privateは最も制限が強いアクセス修飾子です。
同じクラス内からのみアクセスが可能になります。

アクセス修飾子を一覧で見比べる

ここまでそれぞれのアクセス修飾子の違いを見てきました。
次の表は各アクセス修飾子の制限範囲をまとめた表です。

アクセス修飾子同じクラス同じパッケージ継承したクラス(サブクラス)全て
public
protected×
デフォルト(指定なし)××
private×××

下に行けば行くほど制限が強く、アクセス可能な範囲が狭くなっています。

アクセス修飾子をサンプルプログラムで解説!

ここまではアクセス修飾子について言葉で解説してきました。
ここからは実際にプログラムを見て、動きを確認していきましょう!

基準となるクラス

まずは基準となるクラスを準備します。
パッケージは「sampleA」、クラス名は「Base」としました。

このクラスはpublic, protected, デフォルト, privateの4つのアクセス修飾子がついたString型のフィールドを持っています。
各フィールドはstaticなフィールドにしています。staticなフィールドにすることで、インスタンス化しなくても利用できるため、今回の検証では便利です。

これらのフィールドにアクセスできるかどうかで、アクセス修飾子の範囲を検証していきます。
mainメソッドを用意して、各フィールドを出力してみます。

package sampleA;

/**
 * 基準となるクラス
 * @author uhablog
 *
 */
public class Base {

	/**
	 * publicなフィールド
	 * どこからでもアクセス可能
	 */
	public static String publicStr = "publicなフィールドです";

	/**
	 * protectedなフィールド
	 * 同じパッケージ、継承したクラスからアクセス可能
	 */
	protected static String protectedStr = "protectedなフィールドです";

	/**
	 * デフォルト(アクセス修飾子なし)
	 * 同じパッケージ内からアクセス可能
	 */
	static String defoStr = "アクセス修飾子なしのフィールドです";

	/**
	 * privateなフィールド
	 * このクラスからしかアクセスできない
	 */
	private static String privateStr = "privateなフィールドです";

        /**
	 * 確認用メソッド
	 */
	public static void main(String[] args) {
		System.out.println(publicStr);
		System.out.println(protectedStr);
		System.out.println(defoStr);
		System.out.println(privateStr);
	}
}

実行結果

全てのフィールドにアクセス可能なことが確認できました。

publicなフィールドです
protectedなフィールドです
アクセス修飾子なしのフィールドです
privateなフィールドです

同じパッケージ

次に同じパッケージ内に別のクラスを準備しました。
パッケージは「sampleA」、クラス名は「SamePackage」です。

このクラスからBaseクラスのフィールドにアクセスして出力します。
同じパッケージであるため、修飾子なしのフィールドにはアクセスできますが、privateなフィールドにはアクセスできません

package sampleA;

/**
 * 基準となるクラスと同じパッケージ内のクラス
 * @author uhablog
 *
 */
public class SamePackage {

	/**
	 * 動作確認用メソッド
	 * @param args
	 */
	public static void main(String args[]) {
		// publicなフィールドを出力
		System.out.println(Base.publicStr);
		// protectedなフィールドを出力
		System.out.println(Base.protectedStr);
		// デフォルトのフィールドを出力
		System.out.println(Base.defoStr);
		// privateなフィールドは出力できない
		// System.out.println(Base.privateStr);
	}
}

実行結果

実行結果は次の通りです。

publicなフィールドです
protectedなフィールドです
アクセス修飾子なしのフィールドです

違うパッケージ、継承あり

次に違うパッケージでBaseクラスを継承した場合を確認してみます。
パッケージは「sampleB」クラス名は「ChildClass」としました。

違うパッケージですが、Baseクラスを継承しているのでprotectedなフィールドにはアクセスすることができます。
しかしアクセス修飾子がないフィールドと、privateなフィールドにはアクセスできません。

package sampleB;

import sampleA.Base;

/**
 * 違うパッケージで、基準のクラスを継承する
 * @author uhablog
 */
public class ChildClass extends Base {

	/**
	 * 動作確認用メソッド
	 * @param args
	 */
	public static void main(String args[]) {
		// publicなフィールドを出力
		System.out.println(Base.publicStr);
		// protectedなフィールドを出力
		System.out.println(Base.protectedStr);
		// デフォルトのフィールドは出力できない
		// System.out.println(Base.defoStr);
		// privateなフィールドは出力できない
		// System.out.println(Base.privateStr);
	}

}

実行結果

実行結果は次の通りです。

publicなフィールドです
protectedなフィールドです

違うパッケージ、継承なし

では最後に違うパッケージで、継承がなかった場合のパターンを検証します。
パッケージは「sampleB」クラス名は「SampleClass」としました。

このクラスではpublicなフィールドのみアクセスすることができます。
それ以外の3つのフィールドにはアクセスすることができません。

package sampleB;

import sampleA.Base;

/**
 * 別パッケージで継承もしていないクラス
 * @author uhablog
 */
public class SampleClass {
	/**
	 * 動作確認用メソッド
	 * @param args
	 */
	public static void main(String args[]) {
		// publicなフィールドを出力
		System.out.println(Base.publicStr);
		// protectedなフィールドは出力できない
		// System.out.println(Base.protectedStr);
		// デフォルトのフィールドは出力できない
		// System.out.println(Base.defoStr);
		// privateなフィールドは出力できない
		// System.out.println(Base.privateStr);
	}
}

実行結果

実行結果は次の通りです。

publicなフィールドです
protectedなフィールドです

アクセス修飾子の使い分け

4種類のアクセス修飾子があり、それぞれの違いがわかりました。
ではこのアクセス修飾子はどのように使い分ければ良いのでしょうか?

基本的に外部からアクセスされても良いものはpublic、外部からアクセスされたくないものはprivateをつけるようにしましょう。

ただ上記のような基準で考えたときに迷ってしまい、わからない場合は可能な限りアクセス制限を強くしましょう。
なので、迷ったらとりあえずprivateで宣言してしまって、後から外部からの参照が必要だなとなったときは都度アクセス制限を弱めていきましょう。

しかし闇雲にアクセス制限を弱くしていくと、思わぬバグにつながりますので、注意が必要です。
ゲッターやセッターなどを使うことも検討する必要があるでしょう。

まとめ

今回はJavaのアクセス修飾子について解説してきました。
アクセス修飾子はメソッドやフィールドに付与することができ、アクセス可能な範囲を制限しています。
アクセス修飾子にはpublic、protected、なし、privateの4つがあり、適切なアクセス修飾子をつけることが必要です。

この記事が少しでもあなたのプログラミング学習の助けになることを願っています。
最後まで読んでいただきありがとうございました。

コメント

タイトルとURLをコピーしました