オブジェクト指向プログラミング(1)では,以下の項目に関して学ぶ.
識別子と予約語
クラス,メソッド,変数などの名前を識別子(identifier)と呼ぶ.識別子には,半角英数字,アンダーバー,ドル記号,Unicode文字を使用できる.ただし,数字を先頭文字にすることはできない.また,ドル記号は,主に処理系が内部で識別子を自動生成する場合に用いられる.大文字と小文字は区別されて扱われる.
さらに,以下に示す予約語は,識別子には使えない.
abstract assert boolean break byte case catch char class const continue default do double else extends final finally float for goto if implements import instanceof int interface long native new package private protected public return short static strictfp super switch synchronized this throw throws transient try void volatile while
演算子と文
基本的な文,式,制御構造,演算子などの構文はC言語やC++言語に類似している.
主な演算子には,算術演算子(+
, -
, *
, /
, %
, ++
, --
, ?:
),代入演算子(=
, +=
, -=
, *=
, /=
, %=
),比較演算子(<
, <=
, >
, >=
, ==
, !=
),論理演算子(&&
, ||
, !
)がある.これら以外の重要な演算子として,インスタンスを生成するnew
,型を変換するキャスト(型を括弧で括る),インスタンスの型を判定するinstanceof
,配列の生成やアクセスに用いる[]
,限定名を形成するドット(.
)がある.
また,条件文(if
, switch
-case
),繰り返し文(while
, for
),break
文,continue
文,return
文を備える.これらの記法と意味は,C言語やC++ 言語のものとほぼ同様である.
変数と定数
データを保持する場合には,変数(variable)を用いる.C言語と同様に,変数は使用する前に宣言しておく必要がある.変数の名前は,識別子で与えられる.
変数はすべて型(type)を持つ.Javaのデータ型には,基本型(primitive type)と参照型(reference type)がある.基本型は,論理型のboolean
(true
あるいはfalse
をとる),整数型のbyte
(8ビット符号付), short
(16ビット符号付), int
(32ビット符号付), long
(64ビット符号付),浮動小数点型のfloat
(32ビット単精度), double
(64ビット倍精度),Unicode文字型のchar (16ビット)である.配列,クラス,インタフェースは参照型であり,その変数の値はすべてインスタンスへの参照(ポインタのようなもの)となる.
変数の宣言,代入,初期化の方法は,C言語と同様である.ただし,Javaは強い静的型言語であるため,あらかじめ規定されている型変換が適用される場合や多態変数に対する代入を除いて,変数の型と異なる型の値を代入することはできない.また,変数に代入される値(value)の型には,静的な型(見かけ上の型)と動的な型(実行時の型)がある.静的な型はプログラムコードで明示的に宣言されているため,コードを見れば判別可能である.それに対して,動的な型はプログラムの実行時に決まる.
さらに,変数はスコープ(scope)を持つ.スコープとは,その変数を単純名(名前のみ)で参照できる範囲である.インスタンス変数(フィールド)のスコープは宣言されたクラスであり,メソッド引数のスコープは宣言されたメソッドである.ローカル変数のスコープは,それが宣言された位置から始まり,それが宣言されたブロックの終りまでとなる.
定数リテラル(literal)には以下のものがある.
1
, 123
など)1.0
, 3.1415
, 1.23E5
など)true
, false
など)'A'
, '#'
, '\n'
, '\t'
など)"Java"
,"X"
など)null
)整数リテラル,浮動小数点数リテラル,真偽リテラル,文字リテラルに関しては,それぞれ対応する基本型の変数を用いて扱う.文字列リテラルに関しては,それを扱う基本型は用意されていないので,文字列を扱うクラスString
,StringBuilder
,StringBuffer
などを用いる.String
から生成したインスタンスは不変であるため,それに格納されている文字列を変更することはできない.これに対して,StringBuilder
やStringBuffer
から生成したインスタンスでは,文字の追加や挿入ができるようになっている.また,String
のインスタンスは頻繁に利用されるため,new
演算子を使わなくとも,次のようにインスタンスの生成が可能である.
String str = "Java"; // String str = new String("Java"); と同じ
変数の宣言にfinal修飾子をつけることにより,変数を定数のように扱うこともできる.たとえば,以下のように変数MAX_VALUE
を宣言すると,一度代入が行われた変数は2度と値を変更できない.これにより,定数のように扱うことできる.
final int MAX_VALUE = 1024;
String
から生成したインスタンスは参照型であるため,文字列の比較には==
演算子ではなく,メソッドequals()
やcompareTo()
を用いる必要がある.nullリテラルは,null
型に属する唯一の値であり,参照型変数がまだ有効な値(インスタンス)を指していないことを表す.
コメント
//
からその行の終りまでの文字,/*
と*/
にはさまれる文字はコメントとなる.
クラス(class)とはデータ(属性)とそれに対する処理(操作)をひとまとめにして定義した抽象データ型である.Javaプログラムは1つ以上のクラスで構成される.
クラスは,予約語class
を用いて宣言する.スマートフォンを指すクラスSmartphone
を宣言するソースコードを以下に示す.
class Smartphone { // クラスの本体 }
Javaでは,クラスの保持する属性をフィールド(field)と呼ぶ.名前(name
)と価格(price
)のデータを格納するフィールド宣言を追加したソースコードを以下に示す.
class Smartphone { String name; // 名前データを格納するフィールド(フィールド変数) int price; // 価格データを格納するフィールド(フィールド変数) }
クラスの保持する操作はメソッド(method)と呼ばれる.メソッド宣言を追加したソースコードを以下に示す.
class Smartphone { String name; int price; Smartphone(String name, int p) { // コンストラクタ this.name = name; price = p; } Smartphone(String name) { // コンストラクタ this(name, 30000); } String getName() { // 名前データを取得するメソッド return name; } void setPrice(int p) { // 価格データを設定するメソッド price = p; } int getPrice() { // 価格データを取得するメソッド return price; } String getPriceInfo() { // 価格情報を取得するメソッド return String.valueOf(getPrice()) + "-yen"; } void print() { // 名前と価格の情報を表示するメソッド System.out.println(name + ": " + getPriceInfo()); } }
getName()
,setPrice()
,getPrice()
,getPriceInfo()
,print()
は通常のメソッドである.一方,クラスと同じ名前を持つメソッドSmartphone()
は,コンストラクタ(constructor)である.コンストラクタはインスタンス生成時に実行されるため,インスタンスの初期化に用いる.Smartphone()
内に存在する予約語this
は,自分自身のインスタンスへの参照を表す.たとえば,Smartphone
のコンストラクタが呼び出された場合,this
は生成したインスタンスそのものを指し,this.name
はそのインスタンスのフィールドname
を指す.コンストラクタ内の代入文の右辺のname
はローカル変数(メソッドの引数)である.よって,この代入文で,引数name
の値がフィールドname
に代入される.また,this()
はコンストラクタ内のみで使用可能で,自分自身のインスタンスの別のコンストラクタを呼び出す際に用いる.
インスタンスではなくクラスに属する静的フィールドや静的メソッドを宣言するためには,予約語static
を付ける.これらは,クラス変数(class variable)またはクラスメソッド(class method)と呼ばれる.たとえば,クラスSystem
のフィールドout
はクラス変数である.また,クラスString
のメソッドvalueOf()
はクラスメソッドである.クラス変数やクラスメソッドは,インスタンスを生成しなくともクラス名を指定するだけで参照(System.out
)や呼び出し(String.valueOf()
)が可能である.クラス変数は同一のクラスから生成したインスタンス群で値を共有したい場合や定数を保持するために用いる.また,クラスメソッドは,複数のクラスから利用されるユーティリティ関数の実現などに用いる.
ここで,メソッドprint()
の本体に記述されているSystem.out.println()
のSystem.out
は標準出力を意味し,println()
は文字列を(標準出力に)表示するメソッドである.
最後に,可視性を付与して完成させたクラスSmartphone
のソースコードを以下に示す.
public class Smartphone { private String name; int price; public Smartphone(String name, int p) { this.name = name; price = p; } public Smartphone(String name) { this(name, 30000); } public String getName() { return name; } public void setPrice(int p) { price = p; } public int getPrice() { return price; } private String getPriceInfo() { return String.valueOf(getPrice()) + "-yen"; } public void print() { System.out.println(name + ": " + getPriceInfo()); } }
クラスSmartphone
の宣言に付与されているpublic
は,そのクラスがどこからでもアクセス可能なことを指す.また,フィールドprice
やメソッドgetPrice()
の宣言に付与されているpublic
は,あらゆるクラスから,そのフィールドやメソッドにアクセス可能なことを指している.一方,フィールドweight
やメソッドgetPriceInfo()
の宣言に付与されているprivate
は,そのフィールドやメソッドがクラス内からのみアクセス可能なことを指している.可視性を表す予約語が付与されていないprice
は,同じパッケージのクラスからアクセス可能である.パッケージとアクセス制御の詳細については,オブジェクト指向プログラミング(2)で説明する.
Javaソースファイルを作成する際の注意として,ファイル内の公開クラスの名前(たとえば,Smartphone
)とファイル名(この場合,Smartphone.java
)は一致させる必要がある.
クラスSmartphone
のインスタンスを生成し,そのインスタンスのフィールドの値を読み書きしたり,メソッドに記述された処理を実行するソースコードを以下に示す.
public class Sample1 { public static void main(String[] args) { Smartphone phone1 = new Smartphone("ABC", 35000); System.out.println("Price = " + phone1.price); System.out.println("Price = " + phone1.getPrice()); Smartphone phone2 = new Smartphone("XYZ"); System.out.println("Price = " + phone2.price); System.out.println("Price = " + phone2.getPrice()); } }
クラスSample1
のメソッドmain()
では,phone
というSmartphone
型の変数を宣言し,new
演算子により生成したインスタンスをその変数に保持させている.生成したインスタンスは,phone
という名前で参照する.フィールドやメソッドのアクセスには,ドット演算子を用いる.phone.price
によりphone
のフィールドprice
を参照したり,phone.getPrice()
によりphone
のメソッドgetPrice()
を呼び出したりすることができる.
メソッドmain()
はJava プログラムにおいて特殊なメソッドであり,java
コマンドの引数として指定したクラスの実行開始点である.たとえば,クラスSample1
を実行した場合,Sample1
のmain()
から実行が始まる.
Javaプログラムは以下に示す手順で実行する.
ソースファイルとは,Javaソースコードを格納したテキストファイルであり,拡張子".java
"を持つ.C言語のプログラム作成と同様に,Emacsなどのテキストエディタを用いて作成することができる.
ソースファイルをJavaコンパイラ(javac)でコンパイルすると,クラスやインタフェースごとにクラスファイルと呼ばれるバイナリファイルが作成される.クラスファイルは,拡張子".class
"を持つ.クラスファイルはバイトコード(bytecode)とも呼ばれ,プラットフォームに依存しないという特徴を持つ.ソースファイルSample.java
のコンパイルは,以下のコマンドにより行う.
% javac Sample.java
バイトコードは,Java仮想機械(JVM: Java Virtual Machine)と呼ばれるインタプリタ上で解釈実行する.インタプリタは,バイトコードを各計算機に向けの機械語に逐次変換して,その処理を実行する.クラスファイルSample.class
の実行は,以下のコマンドにより行う.
% java Sample
Sample1.javaのソースコードをコンパイルして実行すると,以下のようになる.
% javac Sample1.java
% java Sample1
Price = 35000
Price = 35000
Price = 30000
Price = 30000
ここで,クラスSmartphone
がクラスSample1
で利用されているため,Smartphone.javaも自動的にコンパイルされる.
大規模なプログラムを作成する際には,他の開発者が作成したクラス(あるいはインタフェース)を再利用する場合が多い.さまざまな開発者が作成したクラスを混在させて利用する場合の名前の衝突を避けるため,Javaにはパッケージという仕組みが用意されている.Java SEのクラスライブラリに含まれる主なパッケージを以下に示す.
java.lang
: Java言語の機能java.util
: ユーティリティ機能java.io
: 入出力機能java.math
: 算術演算java.net
: ネットワーク処理java.awt
: グラフィカルユーザインタフェース(GUI)javax.swing
: グラフィカルユーザインタフェース(Swing)
ソースファイルの先頭にpackage
宣言が存在すると,そのファイルで定義したクラスやインタフェースはそのパッケージ(名前空間)に属することになる.たとえば,次のように記述すると,クラスFile
はパッケージjp.ac.ritsumei.cs
に属する.
package jp.ac.ritsumei.cs; public class File { // クラスの本体 }
この場合,Fileの完全限定名(fully-qualified name)はjp.ac.ritsumei.cs.File
となり,Java SEの標準ライブラリ(java.io
パッケージ)に含まれるjava.io.File
と区別される.ソースファイルにpackage
宣言が存在しない場合,そのファイルで定義されているクラスは無名パッケージに属することになる.同じパッケージに属するクラスどうしは,特にパッケージ名を指定しなくともお互いに利用可能である.異なるパッケージに属するクラスを利用する場合は,パッケージ名を含む完全限定名で指定することになる.たとえば,パッケージjp.ac.ritsumei.cs
に含まれるクラスFile
を指定する場合は,jp.ac.ritsumei.cs.File
とすればよい.また,import
文を用いると,完全限定名を指定しなくともクラス名だけでクラスを指定可能となる.よって,次のコードにおいて,単純にFile
と記述した場合は,jp.ac.ritsumei.cs.File
と同じものを指す.つまり,file3
の型はjp.ac.ritsumei.cs.File
となる.
import jp.ac.ritsumei.cs.File; public class FileManager { jp.ac.ritsumei.cs.File file1; // 完全限定名で指定 java.io.File file2; // jp.ac.ritsumei.cs.Fileとは異なるクラス File file3; // jp.ac.ritsumei.cs.Fileと同じクラス }
特定のパッケージの直下に属するクラス群をまとめて指定する場合は,次のように"*
"を用いてimport
宣言を記述することができる.
import java.io.*; public class FileManager { // クラスの本体 }
このように記述することで,パッケージjava.io
に属するクラスをクラス名だけで指定できる.ここで,java.lang
パッケージについては,特にimport
文を記述しなくとも自動的に取り込まれている.たとえば,今まで何度も登場したSystem
クラスの完全限定名はjava.lang.System
である.
パッケージに関連して,アクセス制御(可視性)に関する)修飾子を以下にまとめる.
public
: どのパッケージのクラスからも,そのクラス,フィールド,メソッドにアクセス可能protected
: 同じパッケージとその子クラスから,そのクラス,フィールド,メソッドにアクセス可能private
: クラス内からのみ,そのクラス,フィールド,メソッドにアクセス可能フィールドやメソッドには上記の4つのアクセスレベルを指定することができる.また,トップレベルクラス(ネストしていないクラス)には,public
とデフォルトが指定できる.クラスへのアクセスが不可能な場合,そのクラスの内部のフィールドやメソッドにもアクセスできない.
統合開発環境Eclipseは,ソースコードの編集,コンパイル,実行,テスト,デバッグ,版管理に関する機能を備えている.
Eclipseのダウンロード
EclipseのWebサイトにアクセスし,右上の[Download]
から,Eclipseの[Download Packages]をクリックし,それぞれの環境に適したパッケージをダウンロードする.本演習では,[Eclipse IDE for Java Developers]
版で十分である.
Eclipseのインストール
ダウンロードしたファイルを展開し,任意のフォルダ(ディレクトリ)にコピーするだけで完了する.Eclipseをアンインストールしたければ,フォルダを削除すればよい.
Eclipseの起動と終了
配置したフォルダ内にeclipseの実行ファイルが存在するので,それをダブルクリックなどして起動する.最初の起動時には,ワークスペースの選択ダイアログが表示されるので,ワークスペースを指定する.ワークスペースとは,作成したソースコードなどを保存する作業領域のことを指す.一度ワークスペースを指定すると,今後指定は不要である.ワークスペースの指定が完了すると,Welcome
画面が現れる.ここで,"Always show Welcome at start up"のチェックを外しておくと,次回から"Welcome"画面がでなくなる."Welcome"画面で,Workbench
アイコンをクリックして,ワークベンチを開く.ワークベンチとは,Eclipseで作業を行う際の土台である.Eclipseを終了させたい場合は,通常のアプリケーションと同様に,ウインドウを閉じるアイコンをクリックするかメニューで終了を選択する.
Javaプログラムの作成と実行
EclipseでJavaプログラムを作成する際には,プロジェクトが必要である.プロジェクトとは,Eclipseにおける作業単位で,ソースコードファイルや実行ファイルを格納する入れ物となる.プロジェクトを作成するには,Eclipseのメニューから[File]→[New]→[Java Project]
を選択する.プロジェクトの名前を入力するダイアログが表示されるので,適当な名前を入力する.ここでは,Test
とする.Eclipseの画面左側に存在するPackage Explorer
ビュー(view)にプロジェクトSample
が作成されたことがわかる.ビューとは,Eclipseの画面上のサブウィンドウを指す.
Package Explorer
ビューのプロジェクトSample
をクリックすると,src
フォルダが存在しているので,これを右クリックをすることで,メニューが現れる.メニューにおいて,[New]→[Class]
を選択すると,クラス作成ダイアログが現れるので,作成したいクラスの名前を[Name]
に入力する.パッケージも指定したい場合は,パッケージ名を[Package]
に指定する.ここでは,例題1のプログラムで説明するので,クラス名にSample1
と入力し,[Finish]
を押す.これにより,クラスのひな形のコードが記述された
例題1のプログラムSample1.java
のコードを編集し,クラスSample1
を完成させる.コードの編集が完了したら,ファイルを保存([File]→[Save]
あるいはSave
アイコンをクリック)する.
クラスSample1
を実行したい場合は,そのクラスのmain
メソッドを含むJavaファイルを右クリックし,メニューから[Run As]→[Java Application]
を選択する.例題1のプログラムの実行結果は,画面下側のConsole
ビューに出力される.ここでは,デバッガを用いた実行の方法は省略するが,興味があれば各自試してみるとよい.
Javaプロジェクトのインポート
プロジェクトを一括してインポートする(取り込む)方法を説明する,ここでは,あらかじめ用意しておいた例題1〜22のプログラムコードを含むSample.jar
をインポートする.このjarファイルはインポートの前にダウンロードしておく.
まず,例題を格納するプロジェクトを作成する.ここでは,プロジェクトの名前をSample
とする.Sample
プロジェクトのsrc
フォルダを右クリックし,メニューから[Import]
を選択する.インポートダイアログが現れるので,[General]→[Archive File]
を選択し,[Next]
を押す.次に,[From archive file]
にさきほどダウンロードしておいたjarファイルを指定する.[Finish]
を押すことで,インポートが完了する.ファイル上書きの確認ダイアログが現れるので,すべてYesでよい.
JUnitとは,Javaプログラム開発用の単体テストツールである.Eclipseに標準で内蔵されており,Eclipseから簡単に利用可能である.テストコードをプログラムに埋め込むことで,テストの自動化を実現している.
テストケースの作成
一般的に,JUnitではクラスごとにテストケースを用意する.ここでは,クラスSmartphone
に対するテストケースの作成を説明する.Package Explorer
ビューにおいて,Smartphone.java
を右クリックする.現れるメニューにおいて,[New]→[JUnit Test Case]
を選択する.テストケースを含むクラスを作成するダイアログが現れるので,[Finish]
を押す.テストケースのクラス名をデフォルトから変えたい場合は[Name]
で変更できる.JUnit5のビルドパスへの追加の確認ダイアログが現れた場合は,Ok
を選択すればよい.この例では,SmartphoneTest.java
ファイルが作成される.
SmartphoneTest.java
ファイル中にテストケースに合わせたテストコードを記述する.テストコードの例を以下に示す.
import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; class SmartphoneTest { @Test public void test1() { Smartphone phone = new Smartphone("ABC", 35000); assertEquals(phone.getPrice(), 35000); } @Test public void test2() { Smartphone phone = new Smartphone("XYZ"); assertEquals(phone.getName(), "XYZ"); } }
クラスSmartphoneTest
の内部にテストメソッドを記述する.テストメソッドの先頭には@Test
というアノテーション(注釈)を付けておく.これにより,JUnitがテストの際に自動的に呼び出すメソッドを特定できる.この例では,test1()
とtest2()
がテストメソッドに指定されている.テストメソッドの内部には,通常のJavaプログラムと同様にコードを記述する.test1()
では,クラスSmartphone
から(変数phone
で参照できる)インスタンスを生成し,その価格に対してテストを行っている.インスタンス生成時に指定した価格は35000であるため,この値が35000であればテストが成功する.同様に,test2()
では,名前のテストを実行している.assertEquals()
は2つの引数が等しいことを確認するメソッドである.他にも,assertNotNull()
, assertSame()
, assertTrue()
などが用意されている.また,各テストの前後に必ず実行したいメソッドが存在する場合,@BeforeAll/BeforeEach
と@AfterAll/AfterEach
というアノテーションを付ける.
SmartphoneTest.java
のimport
宣言でエラーが出る場合は,EclipseのPackage Explorer
ビューのプロジェクトSample
を右クリックして,[Build Path]→[Add Library
を選択する.[JUnit]
をクリックして,JUnit library version
がJUnit 5
であることを確認し,[Finish]
を押す.
テストの実行
JUnitを用いてテストを実行する場合,テストクラスを含むJavaファイルをPackage Explorer
で右クリックし,[Run As]→[JUnit Test]
を選択する.テストの実行が完了すると,新たにJUnitビューが現れ,テスト結果が表示される.この例では,2つのテストが実行され,すべてのテストに成功しているのでバーが緑色になる.
次に,テストが失敗する場合を説明する.いま,SamrtPhone.java
において,クラスSamrtPhone
のメソッドgetPrice()
を以下のように変更する.
public int getPrice() { return 0; }この変更により,メソッド
getPrice()
の戻り値は必ず0となる.これは,誤りである.この状態で,テストを実行すると,テストメソッドtest1()
の実行において,テストが失敗し,バーが赤色になる.
このサイトでは,Eclipseのインストールを説明しましたが,他の開発環境を利用してもかまいません. 以下のサイトからダウンロードできます.
Visual Studio Codeのダウンロード
IntelliJ IDEAのダウンロード
Exercise11を実行した際の画面出力を求めよ.
以下のクラス図に基づき,ソースコード Person.java を作成せよ.Book.java は(1-1)と同じとする.
回答例はこちら
Copyright 2024 Katsuhisa Maruyama. All rights reserved.