Report#5
[課題]
講義資料オブジェクト指向プログラムJavaI&IIの中のサンプルプログラムについて考察せよ。
- 講義資料サンプルプログラム考察については、ローカル変数以降interface までとする。
[考察]
オブジェクト指向プログラムJava1
ローカル変数 & クラス変数
サンプルプログラム[1からnまでを表示するプログラム]
class Display{
int n //変数nはクラス変数
void Disp(){
int i; //変数iはローカル変数
for(i = 1;i <= n; i++) //i=1がn以下なら+1
System.out.print(i + " "); //iに+1したものを表示
}
class VarSample{
public static void main(String args[]){
Display obj = new Display(); //クラスDisplayのオブジェクトobjを生成
obj.n =10; //オブジェクトobjの変数nに10を代入
obj.Disp(); //オブジェクトobjのDisp()実行
}
}
[実行結果]
[nw0311:~/java] j03011% javac VarSample.java
[nw0311:~/java] j03011% java VarSample
1 2 3 4 5 6 7 8 9 10
|
クラス変数(メンバ変数ともいう.)はオブジェクトの状態を保持する変数です。
つまり各オブジェクトごとではなく、クラス全体で共有して1つの値を格納する
フィールドのことをいいます。オブジェクトに属し,どのメソッド,コンストラクタ
にも属しません。そのため,クラス変数は複数のメソッド,コンストラクタで共通して
使用することができます。
ローカル変数はメソッド内で宣言する変数のこと。各メソッド,コンストラクタ
に限定して使用する変数で他のメソッド,コンストラクタから使用することはできません。
ローカル変数は、メソッドが呼び出されるたびに初期化され、値を持っていられるのは
そのメソッドが終了するまでの間となっている。
クラス変数のスコープはクラス変数を宣言したクラスの{}内です。ローカ
ル変数のスコープはローカル変数を宣言したメソッド,コンストラクタの{}
内です。
ローカル変数とクラス変数が両方ある時は、ローカル変数のほうが優先される。
Static変数
サンプルプログラム[staticを用いて値を共有するプログラム]
Class Sum{
static int total; //クラス変数staticを宣言、totalの値を共有させる
Sum(){ //コンストラクタ(クラスSum)
total = 0; //totalを0に初期化
}
void add(int x){
total += x; //引数xの値をtotalに加える
}
}
class SumSample2{
public static void main(String args[]){
Sum obj1 = new Sum(); //クラスSumのオブジェクト(obj1)を生成
Sum obj2 = new Sum(); //クラスSumのオブジェクト(obj2)を生成
obj1.add(10); //obj1のadd()メソッドに引数x=10を
obj1.add(20); //obj1のadd()メソッドに引数x=20を
obj2.add(30); //obj2のadd()メソッドに引数x=30を
obj2.add(40); //obj2のadd()メソッドに引数x=40を
System.out.println("obj1.total = " + obj1.total);
System.out.println("obj2.total = " + obj2.total);
}
}
[実行結果]
[nw0311:~/java] j03011% javac SumSample2.java
[nw0311:~/java] j03011% java SumSample2
obj1.total = 100
obj2.tatal = 100
|
static変数はインスタンス変数をstatic宣言した変数です。
インスタンス変数とはクラス変数のことで。オブジェクトを作成することにより、
それぞれのオブジェクトのtotalに値を代入したり出力したりすることができる変数のこと。
その変数をstatic宣言することにより、メモリの場所が一か所になる変数になります。
メモリの場所が固定されているので、どこから呼び出されてもいつも同じ変数です。
だから実行結果のtotalの数値は obj1.total = obj2.total となり全部の合計みたいな感じになります。
staticとは直訳すれば、「静的な」「あまり変化しない」という意味。
ちなみに、static宣言をしなかったら(staticをはずしたら)、実行結果はこうなります。
[実行結果]
[nw0311:~/java] j03011% javac SumSample.java
[nw0311:~/java] j03011% java SumSample
obj1.total = 30
obj2.tatal = 70
クラス変数の宣言
class クラス名
{
static 型 クラス変数名; //クラス変数にはstaticをつける
・・・
}
クラスメソッドの宣言
static 戻り値の型 クラスメソッド名(引数のリスト) //クラスメソッドにはstaticをつける
{
文;
・・・
}
コンストラクタ
サンプルプログラム[コンストラクタを用いた合計プログラム]
class Sum{
int total; //インスタンス変数totalを宣言
Sum(){
total = 0; //引数の無いコンストラクタ(totalの値を0に初期化)
}
Sum(int x){ //引数 x のコンストラクタ(totalの値に初期化)
total = x;
}
void add(int x){ //引数の値をtotalに加えるメソッド
total += x;
}
}
class ConstrcSample{
public static void main(String args[]){
Sum obj1 = new Sum(); //引数の無いコンストラクタ(クラスSumのオブジェクトobj1)を生成
obj1.add(10); //obj1に10を加え
obj1.add(20); //obj1にさらに20を加え
System.out.println("sum1 = " + obj1.total);
Sum obj2 = new Sum(100); //引数を1個持つコンストラクタ(クラスSumのオブジェクトobj2)が呼び出される
obj2.add(10); //obj2に10を加え
obj2.add(20); //obj2にさらに20を加え
System.out.println("sum2 = " + obj2.total);
}
}
[実行結果]
[nw0311:~/java] j03011% javac ConstrcSample.java
[nw0311:~/java] j03011% java ConstrcSample
sum1 = 30
sum2 = 130
|
コンストラクタとはクラス名と同じ名前のメソッドのことである。
voidを持たず戻り値を指定することはできない。
コンストラクタを用いるとオブジェクトの生成時にクラス変数の初期化を行うことができる。
コンストラクタは引数の型や引数の数を変更することで1クラス内に複数宣言することができます。
引数の型と引数の数が同じコンストラクタを1クラス内で複数宣言することはできません。
コンパイルエラーとなります。
コンストラクタ宣言における必須項目はコンストラクタ名(引数型 引数名)です。
コンストラクタ宣言時に付与できす修飾子はアクセスレベルのみです。
アクセスレベル コンストラクタ名[クラス名と同じ](引数型 引数名){
文;
・・・
}
コンストラクタを定義していないときにはjavacが引数なしで内容が空のコンストラクタを自動的に作ります。
すなわち、オブジェクトを生成した時に、次のような形のコンストラクタが用意され、自動的に呼び出されることになる。
この引数の無いコンストラクタをデフォルトコンストラクタ(default constructor)という。
sum(){
//コンストラクタを定義しないと、引数の無いコンストラクタが用意される。
}
staticイニシャライズ
サンプルプログラム[staticイニシャライズを行ったプログラム]
class Disp{
static{ //staticイニシャライズ
System.out.println("initialize");
}
Disp(){ //コンストラクタ
System.out.println("construct");
}
}
class StaticSample{
public static void main(String args[]){
Disp obj1 = new Disp(); //オブジェクト生成時にコンストラクタを処理
Disp obj2 = new Disp(); //オブジェクト生成時にコンストラクタを処理
}
}
[実行結果]
[nw0311:~/java] j03011% javac StaticSample.java
[nw0311:~/java] j03011% java StaticSample
initialize //Dispクラスのロード時に処理
construct //Disp.obj1 = new Disp();が実行される時に処理
construct //Disp.obj2 = new Disp();が実行される時に処理
|
static initializerとはオブジェクトが参照されたときに一番最初に実行される処理のことをいい、
コンストラクタよりも早く処理したいときや、一度だけ処理を行いたいときに使います。
コンストラクタの処理の部分[Disp obj1 = new Disp();]をロードするより先にstaticイニシャライズ
の検査がされる。
Disp obj1 = new Disp();の処理を行うときは1度検査した後なのでそのまま実行される。
めそッドのオーバーロード
サンプルプログラム[メソッドのオーバーロードを行ったプログラム]
class Display{
void Disp(){ //Dispメソッド 引数なし
System.out.println("Nothing");
}
void Disp(int x){ //Dispメソッド int型の引数x
System.out.println(x);
}
void Disp(int x, int y){ //Dispメソッド int型の引数x,y
System.out.println(x + y);
}
}
class OvldSample{
public static void main(String args[]){
Display obj = new Display(); //クラスDisplayのオブジェクトobj生成
obj.Disp(); //オブジェクトobjのDisp()を実行
obj.Disp(1); //オブジェクトobjのDisp(1)を実行
obj.Disp(1,2); //オブジェクトobjのDisp(1,2)を実行
}
}
[実行結果]
[nw0311:~/java] j03011% javac OvldSample.java
[nw0311:~/java] j03011% java OvldSample
Nothing
1
3
|
オーバーロードとは同じ名前の異なる引数を持つメソッドを多数宣言することです。
そうすることによって、引数の数にそれぞれ違った処理をするというのを、if文やswith文を使わないでできるのです。
メソッドのオーバーロードを行う場合は、引数の数や型が異なっていなければ ならない 。
メソッドを識別するのは「引数の型と個数」であり、メソッド名と引数リストの組を使います。
これをシグネチャ(署名)と呼び、同じメソッド名でも、引数リストの異なるものは、
別のものとして扱われます。
アクセス制御
サンプルプログラム[privateを用いて、変数の参照を不可にするプログラム例]
class keisan{
static int tanka; //static変数
private float rate; //float型のprivate変数rateを宣言
keisan(){ //コンストラクタ
tanka = 1000; //tankaを1000に初期化
rate = 0.05f; //tateを0.05に初期化
}
init keisan(int kazu){
int kingaku; //int型でkingakuを宣言
kingaku = (int)(tanka *kazu * (1.0 + rate));
return kingaku; //kingakuを返す
}
}
class PrvSample{
public static void main(String args[]){
keisan obj1 = new keisan(); //クラスkeisanのオブジェクトobjを生成
int kazu = 3; //int型kazuを3で初期化
int kingaku = obj1.keisan(kazu); //obj.keisanメソッドを
//引数kazu = 3を入力して呼び出す。
System.out.println("tanka = " + obj1.tanka);
System.out.println("kazu = " + kazu);
System.out.println("kingaku = " + kingaku);
/* System.out.println("rate = " + obj1.rate); */ //private変数のために参照不可
//変数rateにはprivate修飾子が指定されてるので、クラスPrvSampleからは参照できない
}
}
[実行結果]
[nw0311:~/java] j03011% javac PrvSample.java
[nw0311:~/java] j03011% java PrvSample
tanka = 1000
kazu = 3
kingaku = 3150
|
アクセス制御とは変数を宣言する時のアクセス修飾子などを用いてアクセス制限することである。
プログラマは、パッケージの外からどのクラスを使えるのか、またクラスの外からどのメソッドが使えるのかを決めることができる。このためのJava言語の機構をアクセス制御という。
具体的には、public、protected、privateという3つの修飾子を使って、クラスやメソッドの宣言を行う。
強
↓
↓制
↓限
↓
弱
|
private |
同じクラス内からしか呼び出せないが、同じクラスから作られたオ
ブジェクト同士であれば、相互の private メンバーにアクセスできる。 |
修飾子無し |
同じパッケージ内からしか呼び出せない。 |
protected |
同じパッケージか、そのサブクラスからしか呼び出せない。 |
public |
すべてのクラスから呼び出せる。 |
オブジェクト指向プログラムJava2
継承
サンプルプログラム[継承]
class Display{
void Disp(){ //スーパークラス Display
System.out.println("Hello!"); //メソッド
}
}
class Succeed extends Display{ //スーパークラス Display を継承したサブクラス Succeed
public static void main(String args[]){ //メソッド
Succeed obj = new Succeed(); //オブジェクト生成
obj.Disp(); //スーパークラスから継承したメソッドを利用
}
}
[実行結果]
[nw0311:~/java] j03011% javac Succeed.java
[nw0311:~/java] j03011% java Succeed
Hello!
|
継承は既存のクラス(スーパークラスまたは親クラス)を元に,
新しいクラス(サブクラスまは子クラス)を作成することができます。そしてサブクラスの中で
スーパークラスの変数やメソッドが継承され利用可能となります。
継承する場合には, extends キーワードを用いて継承します。
継承方法
class 子クラス名 extends 親クラス名{
処理;
}
サンプルプログラム[オーバーライド]
class Display{
void Disp(){ //スーパークラス Display
System.out.println("Hello!"); //メソッド
}
}
class Override extends Display{ //サブクラス Override
void Disp(){ //メソッドのオーバーライド
System.out.println("Helo! Java!!");
}
public static void main(String args[]){ //メソッド
Override obj = new Override(); //オブジェクト生成
obj.Disp(); //メソッド Disp 実行
}
}
[実行結果]
[nw0311:~/java] j03011% javac Override.java
[nw0311:~/java] j03011% java Override
Hello! Java!!
|
クラスが継承できるのは,ある1つのクラスだけで,複数のクラスを継承することはできない。
なぜなら,複数のクラスを継承してしまうと,それぞれのスーパークラスに同じインスタンス変数
やメソッドが存在してしまい,サブクラスではどれを継承していいかわからなくなるからです。
逆にスーパークラスを複数のサブクラスで継承することはできます。
super
サンプルプログラム[superを用いたプログラム例]
class Display{ //スーパークラスDisplayの宣言
void Disp(){ //スーパークラスのDisp()メソッド
System.out.println("Hello!");
}
}
class SuperSample extends Display{ //サブクラス SuperSampleの宣言
void Disp(){ //メソッドのオーバーライド
super.Disp(); //スーパークラスのDisp実行
System.out.println("Hello! Java!!");
}
public static void main(String args[]){ //メソッド
SuperSample obj = new SuperSample(); //オブジェクト生成
obj.Disp();
}
}
[実行結果]
[nw0311:~/java] j03011% javac SuperSample.java
[nw0311:~/java] j03011% java SuperSample
Hello!
Hello! Java!!
|
super.は、サブクラスでオーバーライドしたメソッドを
呼び出す時に、オーバーライドされたスーパークラスのメソッドの方を呼び出したいときに使います。
スーパークラスとサブクラスのフィールドに同じ名前のものがあるとき、スーパークラスのほうの変数
にアクセスしたい場合にsuper.をつけます。
super.Disp();
Dispはスーパークラスのメソッド名で、()のなかにargs(引数の並びで、省略可能)
を入れることもできます。
this
サンプルプログラム[thisを用いたプログラム例]
class Keisan1 {
int x = 100; //Keisan1クラスの変数xに100を代入
void add(int x, int y) { //戻り値の無い引数を2個持つadd()の宣言
int w1 = x + y; //add()の引数から与えられたローカル変数xとyを足してw1に代入
int w2 = this.x + y; //Keisan1クラスのインスタンス変数xとローカル変数yを足してw2に代入
System.out.println("w1 = " + w1 + " w2 = " + w2);
}
}
class ThisSample1 {
public static void main(String args[]) {
Keisan1 obj = new Keisan1(); //Keisan1クラスのオブジェクトobjを生成
obj.add(10, 20); //add(int x, int y)に2つの引数10と20を渡す
}
}
[実行結果]
[nw0311:~/java] j03011% javac ThisSample.java
[nw0311:~/java] j03011% java ThisSample
w1 = 30 w2= 120
|
サンプルプログラム[thisを用いたプログラム例2]
class Keisan2 {
Keisan2(int x, int y) { //引数を2個持つコンストラクタ
System.out.println("Keisan = " + ( x * y));
}
Keisan2(int x) { //引数を1個持つコンストラクタ
this(x, 1); //引数1個のコンストラクタの先頭で引数2個のコンストラクタを呼び出す
}
}
class ThisSample2 extends Display {
public static void main(String args[]) {
Keisan2 obj1 = new Keisan2(200, 5); //引数を2個持つコンストラクタが呼び出される
Keisan2 obj2 = new Keisan2(200); //引数を1個持つコンストラクタが呼び出される
}
}
[実行結果]
[nw0311:~/java] j03011% javac ThisSample2.java
[nw0311:~/java] j03011% java ThisSample2
Keisan = 1000
Keisan = 200
|
thisはインスタンスメソッド内、コンストラクタ内で使用し、
現在処理を行っているオブジェクトを表します。インスタンスメソッド,コンストラクタは
現在のオブジェクトを表すthisを持っているために、インスタンスメソッドや門簾トラクタから
他のメソッドやメンバ変数を参照する場合,オブジェクト変数を指定せず参照することができます。
[ThisSample.javaの考察]
w1は、引数から与えられたローカル変数xとyを足して得た値。(10+20)
w2は、自分のクラスの変数xとローカル変数yを足して得た値。(100+20)
[ThisSample2.javaの考察]
引数1個のコンストラクタの中で this(x, 1); という呼び出しをしています。
これは、 あるコンストラクタ内で、別のコンストラクタを呼び出す指定です。
[宣言方法]
this. メンバ変数;
メンバ変数の陰ぺいを行う場合,インスタンスメソッド内,コンストラクタ内で
陰ぺいされたメンバ変数を参照する際に使用します。
this (引数値,・・・);
複数のコンストラクタを宣言し,あるコンストラクタから別のコンストラクタを
参照する際に使用します。
abstract
サンプルプログラム[abstractを用いたプログラム例]
abstract class PreDefine { //抽象クラス
abstract int add(int x, int y); //抽象メソッドadd()
public int sub(int x, int y) { //メソッドsub()
return x - y;
}
}
class AbstractSample extends PreDefine { //抽象クラスを拡張
int add(int x, int y) { //add()メソッドの処理を定義
return x + y;
}
public static void main(String args[]) {
AbstractSample obj = new AbstractSample(); //オブジェクトの作成
System.out.println("add = " + obj.add(100, 80));
System.out.println("sub = " + obj.sub(100, 80));
}
}
[実行結果]
[nw0311:~/java] j03011% javac AbstractSample.java
[nw0311:~/java] j03011% java AbstractSample
add = 180
sub = 20
|
abstractはクラス・メソッド宣言時に使い、クラス・メソッドを
抽象クラス(abstractクラス)・抽象メソッド(abstractメソッド)として宣言します。
処理内容が定義されていないメソッドを持っている という特徴を持っています。
このようなメソッドにもabstract というキーワードをつけ、抽象メソッド(abstract method)
と呼ばれている。 抽象クラスからは、サブクラスを拡張することが出来ます。
ただし、拡張クラスのサブクラスでオブジェクトを作成できるようにするためには、
抽象クラスから継承した抽象メソッドの内容をサブクラスできちんと定義してオーバーライドする
という作業をしなければなりません。
抽象クラスはオブジェクトを作成することができませんが、抽象メソッドの内容をサブクラスで
低意義しなければ、そのサブクラスでもオブジェクトを作成できないことになっています。
[抽象クラスの構文]
abstract class クラス名{
フィールドの宣言;
abstract 戻り値の型 メソッド名(引数のリスト);
}
interface
サンプルプログラム[interfaceを用いたプログラム例]
interface PreDefine { //インターフェイスPreDefine
int add(int x, int y); //抽象メソッドadd
int sub(int x, int y); //同じくsub
}
class InterfaceSample implements PreDefine { //PreDefineのインプリメント
public int add(int x, int y) { //メソッドの内容
return x + y; //値を返す
}
public int sub(int x, int y) { //メソッドの内容
return x + y;
}
public static void main(String args[]) { //メソッド
InterfaceSample obj = new InterfaceSample();
System.out.println("add = " + obj.add(100, 80)); //表示
System.out.println("sub = " + obj.sub(100, 80));
}
}
[実行結果]
[nw0311:~/java] j03011% javac InterfaceSample.java
[nw0311:~/java] j03011% java InterfaceSample
add = 180
sub = 180
|
interfaceはクラスと同じ参照型です。
インターフェースを使えるようにすることを「インターフェースを実装する」と表現します。
この実装はimplementsキーワード を使って行います。
インターフェースは単独でクラスに実装することができますし、複数のインター フェースを
実装することもできます。またクラスの継承とインターフェースの 実装を同時に指定できます。
この場合も、直属のスーパークラスはただ一つしか持つことができません。
インターフェイスとクラスの違う点は
・インターフェイスが持つフィールドは必ず定数である。
・インターフェイスが持つメソッドは必ず抽象メソッドである。つまりメソッドは実装されてない。
・インターフェイスはインスタンスを作ることができない。
[宣言方法]
[修飾子] interface インターフェイス名 {
データ型 変数名 = 初期値;
.....
戻り値のデータ型 メソッド名(引数リスト);
.....
}
クラスでは、1つ以上のインターフェイスを実装することができる。
インター フェイスの実装には implement キーワードを用いる。
[修飾子] class クラス名 implement interface1, interface2,......{
.....
}
このインターフェイスを実装したクラスは、extendsでさらにクラスを継承することができる。
[感想&反省]
今回のレポートは去年からやっていたのに、もう今年になってしまいました。
長さにして2カ月掛かりました。[自分時間の感覚だと1年費やした気分です。]
その割には理解してないので、グダグダなレポートになってしまいました。
もし、来年もやることになったら、その時は一生懸命頑張ろうと思います。
な〜んて、言ったら一生やらなさそうなので春休み中に勉強し直したいと思います。
[参考文献]
浅煎り珈琲Java アプリケーション入門
Javaへの道
Pratical Programming Java