はじめに
この記事を読めば、Kotlinのアクセス修飾子の使用方法やその詳細を習得することができるようになります。
アクセス修飾子とは何か、どのように使うのか、どのような場合に使うべきなのか、それに加えて、どのように活用するかについて、初心者目線でわかりやすく解説しています。
実用的な19のサンプルコードも紹介し、どのような場面でどの修飾子を使うべきかについても具体的に説明します。
●Kotlinのアクセス修飾子とは
Kotlinでコードを書く際に、変数やメソッド、クラスなどがどれだけ外部からアクセス可能かを制御するためのキーワードを「アクセス修飾子」と言います。
○アクセス修飾子の基本概念
Kotlinにおける主なアクセス修飾子は、public、private、protected、internalの4つです。
それぞれがどのようなアクセスレベルを持つのかについて説明します。
- public:この修飾子がついた要素は、どこからでもアクセス可能です。実は、Kotlinではこの修飾子がデフォルトです。つまり、明示的に修飾子を指定しない場合、
publicとして扱われます。 - private:
private修飾子がついた要素は、宣言された同じファイル内か、同じクラス内からしかアクセスできません。 - protected:
protectedは、主にクラス内とそのサブクラス内からアクセスできるようにする修飾子です。ただし、トップレベルの宣言(クラス外部の変数や関数)には使えません。 - internal:この修飾子がついた要素は、同じモジュール内からアクセス可能です。
●アクセス修飾子の使い方
アクセス修飾子の概念を押さえたところで、次に進んで実際の使い方を見ていきましょう。
それでは、各種のアクセス修飾子を具体的なサンプルコードとともに紹介します。
○サンプルコード1:public修飾子の使用例
Kotlinではpublicがデフォルトの修飾子であり、明示的に指定しなくても他のどの場所からでもアクセスできるようになっています。
このサンプルコードではPublicClassクラスとその中のshow関数がpublicと明示してあります。
この場合でも、publicを省略しても同じ意味になります。このクラスと関数はどこからでもアクセス可能です。
○サンプルコード2:private修飾子の使用例
private修飾子は、宣言された要素がその宣言がされているブロック内でのみアクセス可能であることを意味します。
このコードで定義されたPrivateExampleクラスには、privateVarというprivateな変数があります。
この変数はクラス外から直接アクセスすることができません。
そのため、main関数内でexample.privateVarと書くとエラーになります。
ただし、クラス内のshowPrivateVar関数を使って値を表示することはできます。
これらのコードを実行すると、Private Var = 1という結果が得られます。
privateVarはPrivateExampleクラス内でしかアクセスできないため、このような挙動となります。
○サンプルコード3:protected修飾子の使用例
次に紹介するprotected修飾子は、その名前が示す通り保護された範囲でのみアクセスを許可します。
具体的には、そのクラス自身とそのクラスを継承したサブクラスからアクセスが可能です。
外部のクラスからはアクセスすることはできません。
このサンプルコードにおいては、Parentクラスがprotectedな変数nameを持っており、Childクラスがそれを継承しています。
ChildクラスのメソッドであるchangeNameはこのname変数にアクセスして値を変更しています。
一方で、Parentクラス外部からはnameに直接アクセスできないため、値の変更はChildクラスを通して行います。
このコードを実行すると、最初にName in Parent: Parentと出力され、その後にChildクラスのnameが親クラスのnameと同じであることを確認できます。
さらに、changeName関数を用いて名前をChangedに変更後、Name in Child: Changedと出力されるのが確認できます。
このように、protectedな変数はサブクラスでも利用可能です。
○サンプルコード4:internal修飾子の使用例
Kotlinでは、モジュール内での可視性を制御するためのinternal修飾子も用意されています。
この修飾子は、同じモジュール内であればどこからでもアクセスできるようにします。
ここで出てくるInternalClassは、internal修飾子によって同一モジュール内からはアクセス可能な状態になっています。
main関数内でInternalClassのインスタンスを作成し、そのidプロパティにアクセスしています。
このコードを実行すると、ID: 1と表示されます。
これはinternal修飾子によって、同じモジュール内からアクセスできるためです。
●アクセス修飾子の応用例
基本的な使い方に慣れたところで、アクセス修飾子の応用例について解説していきます。
独自のクラス設計やモジュール設計を行う際に、アクセス修飾子をどのように活用できるかを具体的なサンプルコードとともに紹介します。
○サンプルコード5:クラス外からのアクセス制限
通常、プロパティやメソッドが外部からアクセスできるかどうかを制限する場面があります。
下記の例では、BankAccountクラスにprivate修飾子を用いて、balanceプロパティへの直接アクセスを制限しています。
この例ではBankAccountクラス内でのみbalanceにアクセスできます。
depositメソッドを通じてのみ、balanceを操作できる設計になっています。
main関数でaccount.showBalance()を呼び出すと、”残高は5000 円です。”と出力されます。
一方で、account.balance = 10000のような直接的な操作はコンパイルエラーとなります。
○サンプルコード6:同じモジュール内からのアクセス
複数のクラスやファイルが同じモジュールに属している場合、その中で共有したいプロパティやメソッドが出てくることがあります。
そのような場合はinternal修飾子を使うと便利です。
こちらのサンプルコードでは、SharedResourceクラスがinternal修飾子によって同一モジュール内でアクセス可能な状態になっています。
main関数でSharedResourceのインスタンスを作成し、dataプロパティにアクセスしています。
このコードを実行すると最初に”Data: Initial Data”が出力され、その後に”Data: Updated Data”が出力されます。
○サンプルコード7:サブクラスからのアクセス
クラス階層において、親クラスのプロパティやメソッドをサブクラスで参照または操作する際に有用な修飾子がprotectedです。
この修飾子を使うと、親クラスのプロパティやメソッドがサブクラスからは参照できるが、それ以外のクラスからは参照できなくなります。
このコードでは、親クラスAnimalにprotectedで定義されたプロパティsoundがあります。
Dogクラス(サブクラス)では、このsoundプロパティに直接アクセスし、その値を”Woof”に変更しています。
main関数を実行すると、”Animal makes Woof”と”Dog says Woof”が順番に出力されます。
一方で、myDog.soundのようにmain関数から直接soundプロパティにアクセスしようとするとコンパイルエラーになります。
○サンプルコード8:同じファイル内からのアクセス
同じKotlinファイル内であれば、アクセス修飾子を省略(デフォルトはpublic)したり、privateを指定してもそのファイル内から自由にアクセスできます。
この特性は、小規模なプログラムやスクリプトで特に有用です。
この例ではSampleClassというクラスに二つのプロパティがあります。
一つは修飾子なしで定義されたvisibleToEveryone、もう一つはprivate修飾子で定義されたvisibleInThisFileです。
同じファイル内のshow関数からは、どちらのプロパティも問題なくアクセスできます。
main関数を実行すると、”Public says: I am Public”が出力された後に”Public says: I am Public, Private says: I am Private”が出力されます。
●アクセス修飾子を活用したコード設計
アクセス修飾子の基本的な使い方や応用例を学んだ後、今度はより高度なコード設計に焦点を当てます。
アクセス修飾子は、単に変数や関数に制限をかける以上のものです。
それをうまく使うことで、プログラム全体の安全性とメンテナンス性を高めることができます。
○サンプルコード9:モジュール間のデータのやり取り
モジュールとは、プログラムの一部分を独立させたものです。
internal修飾子は、同じモジュール内でのみアクセスを許可するため、モジュール間のデータのやり取りに役立ちます。
このコード例では、ModuleAというクラスがinternal修飾子で宣言されています。
このクラスは、同じモジュール内(この場合は同じファイル内)であれば自由に使うことができます。
main関数でもModuleAのshowメソッドを呼び出し、”This is ModuleA”と出力されます。
○サンプルコード10:継承を考慮した設計
クラスの継承を行う場合、親クラスのプロパティやメソッドにどのようなアクセス修飾子を設定するかが重要です。
例えば、親クラスのメソッドをサブクラスでオーバーライドしたい場合、openキーワードを使ってそのメソッドをオーバーライド可能にします。
このコードでは、Parentクラスにopen修飾子が付いており、showMessageメソッドも同様にopenで宣言されています。
これによりChildクラスではshowMessageをオーバーライドできます。
main関数で各インスタンスのshowMessageを呼び出すと、それぞれのクラスに合わせたメッセージが出力されます。
○サンプルコード11:内部クラスのアクセス制限
Kotlinでは、クラス内にさらにクラスを定義することができます。
これを内部クラスと呼びます。内部クラスにもアクセス修飾子を指定することができ、それによって内部クラスのアクセス範囲を制限することが可能です。
このサンプルコードでは、OuterClass内にInnerClassという内部クラスを定義しています。
そして、この内部クラスにprivate修飾子を指定しています。
このため、InnerClassはOuterClassからしかアクセスできません。
accessInnerメソッドでは、InnerClassのインスタンスを作成してinnerMethodを呼び出しています。
このinnerMethodはInnerClass内で定義されたメソッドで、”This is inner method.”と出力されます。
main関数でOuterClassのインスタンスを作成し、accessInnerメソッドを呼び出しています。
結果として、”This is inner method.”という出力が得られます。
○サンプルコード12:拡張関数とアクセス修飾子
Kotlinでは、既存のクラスに新しいメソッドを追加することができる拡張関数があります。
この拡張関数にもアクセス修飾子を適用することができます。
このコードでは、StringクラスにaddExclamationという拡張関数を追加しています。
この拡張関数はprivate修飾子が指定されているため、同じファイル内からのみアクセス可能です。
main関数でこの拡張関数を呼び出すと、”Hello!”という出力が得られます。
●注意点と対処法
アクセス修飾子の使用にはいくつか注意すべきポイントがあります。
コーディングの際に問題を回避するために、これらの注意点とその対処法を理解しておくことが重要です。
○サンプルコード13:意図しないアクセスを避ける
アクセス修飾子を適切に設定しないと、予期せぬ場所からクラスやメソッドにアクセスされる可能性があります。
このコードのDangerousClassは、sensitiveDataという重要なデータを持っていますが、アクセス修飾子が設定されていないため、どこからでもアクセス可能です。
この問題を解決する一例として、private修飾子を使います。
このように修正すると、sensitiveDataにはSafeClass内からしかアクセスできなくなります。
○サンプルコード14:修飾子の組み合わせの注意点
Kotlinでは複数の修飾子を組み合わせることがありますが、その際には注意が必要です。
このコードではprivateとopenが組み合わされていますが、これは矛盾しています。
openは継承を許可する修飾子なので、privateと併用することはできません。
○サンプルコード15:アクセス修飾子のオーバーライド
親クラスに設定されたアクセス修飾子は、子クラスでオーバーライドする際には維持されます。
しかし、それを変更することもできます。
このコードでは、Parentクラスにprotectedでshowメソッドが定義されています。
このshowメソッドは、Childクラスでpublicにオーバーライドされています。
main関数でChildクラスのインスタンスを作成し、showメソッドを呼び出すと、「This is parent class.」「This is child class.」と出力されます。
●カスタマイズ方法
Kotlinのアクセス修飾子は基本的なものから応用的な使い方まで多岐にわたりますが、それだけでなく、さらに高度なカスタマイズも可能です。
ここでは、そのような高度な利用法について詳しく説明します。
○サンプルコード16:カスタムアクセス修飾子の作成
Kotlinでは、直接アクセス修飾子をカスタムすることはできませんが、特定の動作をする関数を作って、それをアクセス制御に使用することはできます。
このコードで注目すべきはcustomAccessControl関数です。
この関数は引数userを受け取り、その値が”admin”であればtrueを、それ以外であればfalseを返します。
この関数を使ってCustomAccessClass内のrestrictedFunctionメソッドでアクセス制御を行っています。
main関数を実行すると、”admin”では「アクセス許可」、”guest”では「アクセス拒否」と表示され、カスタムアクセス制御が正しく動作していることがわかります。
○サンプルコード17:特定のクラスや関数にのみアクセスを許可する
Kotlinでは、特定のクラスや関数にだけアクセスを許可するような細かい制御も可能です。
そのためには、拡張関数や高階関数を用いる方法があります。
このコードではSpecialClassクラス内にspecialFunctionというprivateメソッドがあります。
これは通常、クラス外からは呼び出せません。
しかし、accessFromというメソッドを通じて、specialFunctionを呼び出すことができます。
このようにして、特定の関数やクラスからのみアクセスを許可することが可能です。
○サンプルコード18:ライブラリのアクセス制限のカスタマイズ
Kotlinを使っていると、外部ライブラリを多用するケースも多くあります。
外部ライブラリは便利な一方で、必要以上に多くの機能が公開されていることがあります。
これをカスタムアクセス修飾子と組み合わせて制御する方法を見ていきましょう。
このコードでは、LibraryClassをシミュレーションしています。
このクラスにはpublicMethod、internalMethod、privateMethodの三つのメソッドがあります。
続いてCustomLibraryClassクラスでLibraryClassを継承しています。
ここではpublicMethodをオーバーライドしており、何らかの制御を行っています。
main関数を実行すると、publicMethodがオーバーライドされたものが呼び出され、「Public method in library」と出力されます。
続いてcustomMethodが呼び出され、「This is a custom method.」と出力されます。
○サンプルコード19:アノテーションとアクセス修飾子の組み合わせ
アクセス修飾子だけでなく、アノテーションを使用することで、さらに繊細なアクセス制御が可能です。
このコードでは、@SpecialPermissionというアノテーションを定義しています。
そしてAnnotationControlクラスのspecialFunctionメソッドにこのアノテーションを付与しています。
executeFunctionWithPermission関数では、メソッドに@SpecialPermissionアノテーションが付与されているかどうかをチェックしています。
main関数を実行すると、specialFunctionメソッドに@SpecialPermissionアノテーションが付与されているので、このメソッドが実行され、「This function needs special permission.」と出力されます。
まとめ
この記事でKotlinのアクセス修飾子について、初心者にもわかるように詳細に解説してきました。
Kotlinでは、これらの修飾子を使ってコードの安全性を高め、保守性を向上させることが可能です。
Kotlinのアクセス修飾子は、プログラミングスキル全体を向上させる手段の一つと言えるでしょう。
これからもKotlinの様々な機能を学んで、より効率的かつ安全なコードを書く力を身に付けていきましょう。
それでは、この記事の内容が皆さんのKotlinでのプログラミングライフに役立つことを心より願っています。


