1.3. ソースコードの主な構成要素
Javaのソースコードを単純に見ると、そのソースコードが何を表すのかの宣言が行われ、その宣言のブロック内に、値を設定するための変数の宣言とその変数の値を使った処理が記述されています。Javaのソースコードは主に次の3つの要素で構築されています。
- ソースコードが表すものの宣言
- 変数(値を持つもの)の宣言
- 処理の記述
この中で変数の宣言もしくは処理の記述がなくてもソースコードは成り立ちますが、基本的にはこの3つで構成されます。
そして、今回の「人」のサンプルをこれら3つの構成要素で例えると次のようになります。
構成要素 | サンプルでの対象 |
---|---|
ソースコードが表すものの宣言 | 「人」 |
変数(値を持つもの)の宣言 | 「名前」「趣味」「挨拶の言葉」 |
処理の記述 | 「自己紹介をする」「挨拶をする」 |
1.3.1 クラスの宣言
Javaのソースコードでは、そのソースコードで表すものが何なのかをブロックで囲み宣言します。この宣言するものの種類はクラス(class)、インターフェース(interface)、列挙型(enum)と呼ばれるものになります。ここではクラスの記述方法について説明します。他のインターフェースや列挙型については、最初にクラスについて学んだほうが理解しやすいので、まずはクラスについて見ていきます。それではクラスの宣言を見てみましょう。クラスの宣言は次の書式で行います。
class クラス名 { …… }
Javaのクラスを宣言するブロックでは、クラスの識別子の前にキーワードの「class」をつけ、次に半角スペースをつけて、その次にクラス名を指定します。
このクラスのブロックの中にクラスが保持する特有の変数や処理を記述することにより、そのクラスの性質を特徴づけることができます。先の例だと「人」クラスは「名前」と「趣味」の変数を持っていて、「自己紹介する」ことや「挨拶をする」ことを行う処理を持つものとなります。
1.3.2 変数の設定
Javaのアプリケーションは変数を使って値を保持します。変数に値を設定するには「=」を使って「=」の左側に対象の変数を、「=」の右側に設定する値を記述します。これを「代入」と言います。
また、変数は宣言される際にその変数が何の型なのか(例えば文字や数値など、どのような種類の値なのかを特定するもの)を宣言し、ソースコード上でその変数を特定するための変数名を付けます。変数の宣言は次のように記述します。
変数の型 変数名 = 値;
変数の型は数値や文字、クラスなどを指定できます。この変数の型を宣言することにより、その変数には特定の型の値しか設定できないようになります。変数に値を設定した後は変数より値を取得することが可能になります。
また値を設定しないで次のように記述した場合、その変数の型が持つデフォルト値(何も設定されていない場合に設定されることが決まっている値)が自動的に設定されます。
変数型 変数名;
先のサンプルで例えると、「名前」と「趣味」には文字列(プログラミングの世界では1文字だけしか表せない型を「文字(character)」と言い、何文字でも表せる型を「文字列」と言います)を設定するので、Javaの文字列のクラスである「String」を使って型を指定します。次に値を設定するのですが、Javaでは文字列の値は「"」(ダブルクォーテーション)で囲むようになっています。これらを踏まえて先ほどの「名前」の変数の設定を行うと次のように記述することができます。
String 名前 = "○○";
変数の型を指定するのは最初に変数名を宣言するときのみで、後で値を変えたい場合は
変数名 = 値;
とすることで、その値を変えることが可能です。また値の部分に計算式など何らかの処理を入れた場合、変数にはその結果が値として設定されます。例えば変数「計算結果」に「1 + 1」の計算結果を設定する場合は、次のような記述になります。変数型は数値型の一つである「int」にします。
int 計算結果 = 1 + 1;
このクラスの宣言を先の例の「人」で表現すると、「名前」と「趣味」そして「挨拶をする」の中にある「挨拶の言葉」を文字列の変数としてみなすことができます。これをJavaの書式に当てはめて書き直すと、次のようになります。
また、このサンプルの「名前」と「趣味」はクラスの状態を表す変数であり、このようにクラスのブロックで直接宣言された変数は「フィールド」と呼ばれます。
1.3.3 メソッド(処理)の記述
Javaのアプリケーションは何らかの処理を行います。処理の中には「1 + 1」のような処理を表す記号を使って表現する「式」と、いくつかの処理をまとめた「メソッド」があります。メソッドはいくつかの処理を記述した文を順に記述してブロックで囲んだもので、次のように記述します。
戻り値 メソッド名( 引数の型 引数名 ) { …… }
この戻り値(もどりち)は、数値や文字列、クラスなど、メソッドの実行結果のデータの型を指定します。もしメソッドの結果を返す必要がない場合は、Javaのキーワードである「void」を設定します。
また引数とはそのメソッド内で使われる変数のことで、メソッドの丸カッコ「()」内に定義される変数のことです。引数は一つも指定しないことも、複数指定することも可能です。引数がない場合はメソッド名の後に「()」のみにし、複数設定する場合は引数の型と引数名のセットごとに「,」(カンマ)をつけて区切ります。この引数はメソッドを呼び出す際に値を渡すのに使われます。
そしてメソッドのブロックの中には処理を行うための文を順に記述します。もし、そのメソッドが処理の結果を返す必要がある場合、処理を終わりにする箇所に次のようにreturn文を書きます(太字部分)。
戻り値 メソッド名( 引数の型 引数名 ) { ……処理 return 処理結果; }
もし、戻り値が「void」で処理の結果を返す必要がない場合は、return文を書く必要がありません。ただし、処理を途中で終了したい場合、その終了したい箇所に「return;」と処理結果なしのreturn文を書くことでメソッドの処理を終了できます。
それでは先のサンプルをメソッドの記述の書式を使って表現してみましょう。ここでは「~と言う」という処理を、実行している端末に文字列を出力するための「System.out.println」に置き換えています。ちなみに、現段階では「System.out.println」は文字列を出力する文とだけ覚えておいても大丈夫ですが、簡単に説明すると、「System」というクラスが持つフィールド(型は別のクラス)の「out」を取得して、そのoutが持つ「println」という文字列を出力するためのメソッドを呼び出しています。
また、引数の型が同じものが複数個続く場合、引数の型のあとに「...」(ピリオドを3つ続けたもの)をつけることで、0から複数個の引数を追加することが可能になっています。これを「可変長引数」と言い、下記のように記述することが可能になります。
戻り値 メソッド名( 引数の型... 引数名 ) { 処理 }
この場合、受け取った引数は後述する配列という同じ型の値を一つにまとめたものとして扱われます。このメソッドを呼び出す側はこの引数に対し何個でも同じ型の値をカンマ区切りで渡すことができるようになります。また、値を渡さないことも可能です。
メソッド名(); メソッド名( 値1); 変数の型 変数名 = メソッド名( 値1, 値2, 値3 );
また、この「...」が付いた引数の他に他の型の値も引数として使いたい場合もあります。その場合、「...」が付いた引数を使える箇所は、メソッドの最後の引数のみになります。
戻り値 メソッド名( 引数1の型 引数名1, 引数2の型... 引数名2 ) { 処理 }
1.3.4 コンストラクタ
Javaでは、コンストラクタという特殊なメソッドとみなせるものがあります。このコンストラクタは、一般的なメソッドと違い、戻り値を宣言せず、メソッド名をクラス名と同一にします。コンストラクタは次の書式で宣言されます。
クラス名( 引数の型 引数名 ) { …… }
Javaでは、あるクラスから別のクラスを呼び出す際に「new」キーワードを使ってクラスから新しいインスタンスを生成します。インスタンスとは、クラスで定義されている内容を実体化したものです。Javaのアプリケーションはクラスから生成したインスタンスに対して値の設定や処理を行います。インスタンスの生成を簡単に例えると、クラスという設計書からインスタンスという実物を作成するようなものです。
そして、このコンストラクタはクラスからインスタンスを生成する際に呼び出されるものであり、その性質からコンストラクタでそのインスタンスの初期設定を行うことが通例となっています。また、コンストラクタは引数を経由して外部から値を受け取ることができ、よく使われる手法としてコンストラクタが受け取った引数をクラスが持つフィールドに値を設定して初期化することがあります。
また、コンストラクタの記述は省略が可能です。ただし、省略された場合、実際には引数なしのコンストラクタが暗黙的に作成されており、実行時に呼ばれるようになっています。
それでは、先のサンプルにコンストラクタをつけて、インスタンスの生成時に名前と趣味を設定できるようにしてみましょう。コンストラクタを記述する前はいくつインスタンスを作っても、すべて同じ「名前」と「趣味」の値しか持てませんでしたが、今回はインスタンスを生成する際に名前と趣味を設定できるよう、次のようにします。
このクラスからインスタンスを生成する場合、次のようになります。ここでは人クラスから名前が「太郎」で趣味が「音楽鑑賞」の人クラスのインスタンスを生成し、同じ人クラスから名前が「花子」で趣味が「サッカー」の別のインスタンスを生成しています。
1.4. パッケージ
アプリケーションの規模が大きくなってくると、作成するクラスの数がどんどん増えていき、ある程度の単位、例えば同じ種類のクラスを集めるなどして、それらのクラスをまとめる必要がでてきます。その際にJavaではパッケージを使ってクラスをまとめることができます。
1.4.1 パッケージの概要
パッケージとは、種類などで分類したクラスの集まりをフォルダに入れることで管理する仕組みのことです。パッケージは、基点となるフォルダから対象のフォルダまでの構成を、フォルダごとに「.」(ドット)で連結した名称で表します。そして、このパッケージ名は名前空間(名前をキーとして、他と同じ名前が発生しないようにする領域)として他のパッケージとの識別に使われます。そのため、パッケージ名はアプリケーション内で唯一無二の名称となるようにしなければなりません。
このパッケージが必要になる理由は、例えば大規模なアプリケーションを作成する場合、無数のクラスファイルが作成されるため、クラスの名前が重複してしまう状態になることがあります。その際にパッケージを変えることにより、パッケージによってクラスの違いを識別できるようにします。これにより、同じクラス名を持つ複数のクラスを作成できるようになります。例えば、先ほどの「動物.哺乳類」と「動物.爬虫類」のパッケージと「犬」や「猫」などのクラスを持つアプリケーションに新たに「ぬいぐるみ」パッケージの「犬」「猫」「ヘビ」「ワニ」のクラスを追加したい場合、下記のようにして分類することができます。
また、業務アプリケーションの場合、パッケージは他のアプリケーション(特にサードパーティのJava製品)と区別をするため、全世界で唯一無二のものになるようにすることがあります。また、規模も大きくなるため、ライブラリという他のアプリケーションを集めたものを使うことがあります。その際に作成する業務アプリケーションのクラスと、それらライブラリのクラスとを区別できるようにしなくてはいけません。
そのため、Javaでは慣例的に会社のホームページに使われているドメイン名を逆にしたものがパッケージ名の最初の部分として使われます。例えばドメインがcodezine.jpの場合、jp.codezineと頭につけたパッケージが作られます。ただしパッケージ名は「-」(ハイフン)を許可していないので、ドメインにハイフンが含まれる場合は「_」(アンダーバー)が代わりに使われることが多いです。
1.4.2 パッケージの宣言
パッケージの宣言はソースファイル上で最初に宣言しないといけません。パッケージは次の書式のように「package」の後にパッケージ名を記述した文で宣言します。
package パッケージ名;
1.4.3 インポート文
Javaではパッケージ外のクラスを使いたい場合、特殊なパッケージのクラスを除いて、どのパッケージのどのクラスを呼び出したいのかを区別するため、次の書式のようにパッケージ名を含んだクラス名を記述しなければなりません。
パッケージ名.クラス名
しかし、このように毎回パッケージ名を含んだクラス名、例えばデータ型がjava.util.Dateの場合、Dateクラスを示すたびにjava.util.Dateと記述していると助長なソースコードになってしまい、読みにくくなってしまいます。それを解決するために、Javaでは他のパッケージのクラスをimport文で宣言することにより、インポートしたクラスに関してはクラス名だけで、どのパッケージのクラスなのかを特定できるようにしています。このimport文は下記の書式で行います。
importパッケージ名.クラス名;
先ほどのjava.util.Dateをインポートする場合は、次のようになります。
import java.util.Date;
また、Eclipseを使っている場合、import文を自動で生成するので、あまり使うことはないですが、import文を「*」を使って次のように記述することにより、そのパッケージ内のすべてのクラスをインポートすることも可能です。
importパッケージ名.*;
ただし、この書式はパッケージ内のクラスのみであって、その下の階層にあるパッケージは含まれません。例えば、先ほどのjava.util.Dataを呼び出す際に次の宣言をしてもDateクラスを識別することはできません。
import java.*
また、特定のパッケージを除いてインポートが必要と書きましたが、この特定のパッケージはjava.langのパッケージのことです。このパッケージのクラスはインポートしなくてもクラス名のみで使うことが可能です。
Eclipseで開発している場合、Windowsなら「Ctrl」+「O」(アルファベットの「O」)で、Macなら「Shift」+「Command」+「O」でimport文を自動生成することができます。
1.5. アクセス修飾子
Javaでは他のクラスからアクセスできるかどうかを制限できます。またアクセスできるものもクラス、フィールド、メソッドとそれぞれに対して指定することができます。Javaではアクセス修飾子を使ってそれらの制限を定義しています。アクセス修飾子には次のものがあります。
修飾子 | 概要 |
---|---|
public | どのクラスからでもアクセスできるようにする修飾子です。 |
protected | パッケージ内のクラスおよび継承(クラス)したクラスまでアクセスできるようにする修飾子です。 |
(修飾子なし) | パッケージ内のクラスまでアクセスできるようにする修飾子です。 |
private | 自分自身のクラス内でしかアクセスできなくする修飾子です。 |
これらをクラス、フィールド、メソッドの宣言とともに記述することにより、アクセスされる範囲を制限できます。
アクセス修飾子 class クラス名 { …… }
アクセス修飾子 データ型 データ名;
アクセス修飾子 戻り値の型 メソッド名 (引数の型 引数名){ …… }
ただし、クラスの場合、付けられるアクセス修飾子はpublicかアクセス修飾子なしのみで、インナークラス(クラスの中に作られたクラス)など特別なクラスのみprivateも可能になります。