前回はJFrameというもともとあるクラスをそのまま利用しました。Javaにはこの他に、元のクラスに自分で機能を付け加えて新たに別のクラスをつくって使うという使い方があります。これを継承といいます。
前回は javax.swing の中にある、JFrame というクラス(ライブラリ)を使って、フレームを作りました。
使用法は new JFrame() を使用して自分が利用するフレームを作って myframe と名前を付け、それに対して、myframe.setSize() のように指示をだすというものでした。
/* フレームを作成 */ JFrame myframe = new JFrame(); /* サイズを指定 */ myframe.setSize(400, 300); /* 終了処理を設定 */ myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); /* 実際に表示する */ myframe.setVisible(true);
オブジェクト指向の言葉では、new JFrame() をコンストラクタを使って、インスタンスをつくり、setSize などのメソッドを使って、設定をしたということになります。setSizeなどはもともと JFrame というクラスにある機能でJFrameのインスタンスを作ることで、適用できるようになります。
クラスは自分で作成して利用することもできます。(というより、java のプログラミングはクラスの作成そのものですが)そのとき、すでにあるクラスに、必要な機能を付け加えて利用することができます。この時もともとのクラスの持っている機能はそのまま使えます。これを継承 と呼びます。
継承によってできたクラスをサブクラス、元になったクラスをスーパークラスといいます。サブクラスの方が拡張されている分、機能的にはスーパーなのですが、名前がサブ。機能と名前のイメージが違うので注意が必要です。
import javax.swing.*; /** JFrame の拡張 */ public class ExFrame01 extends JFrame{ /** コンストラクタ ************/ public ExFrame01(){ /* サイズを指定 */ setSize(400, 300); /* 終了処理を追加 */ setDefaultCloseOperation(EXIT_ON_CLOSE); /* 実際に表示する */ setVisible(true); } /** main ***********************/ public static void main(String[] args){ /* 拡張されたフレームを作成 */ ExFrame01 myframe = new ExFrame01(); } }
extends JFrameは、ExFrame01 が JFrame を継承してつくったことを宣言します。
次の行、public ExFrame01(){ で始まるブロックはコンストラクタといい、あとで new でオブジェクトが作られるときにどのような機能を持たせるかの定義を行う部分です。いわばオブジェクトの設計図です。
JFrameには大きさの指定がなく。オブジェクトを作ってからあとで myframe.setSize(400, 300);で指定しました。ここではコンストラクタにsetSize(400, 300);を書いて、いちいち指示しなくてもよくしました。また、[×]ボタンで終了することや、見えるようにすることもいちいち指示しなくてもよくしました。
もともとJFrameを継承しているのでこのコンストラクタはJFrameのコンストラクタを使ってフレームを作ります。これは書かなくてもいいので楽です。その上にいろいろ付け加えて拡張機能をもったExFrame01クラスを作ったということになります。
コンストラクタのブロックの後にやっと main の部分が出てきます。javaではプログラムを実行するときに、この main から始めます。この上にあった ExFrame01クラスは main の中から呼ばれるまでは実行されません。
main の中にはたったひとつ、ExFrame01クラスのオブジェクトを new を使って生成しそれにmyframeという名前を付けているだけです。これで ExFrame01 のコンストラクタが呼び出され、拡張されたフレームが作られ、表示までされます。
前回のプログラムと全く同じ機能です。結果だけ見ればつまらないですし、プログラムの中身も似たようなものに写るかも知れません。でも考え方はまるで違います。
それは自分のクラスライブラリを作ったからです。プログラムの中に、依然として main があるので、しっくり来ないかもしれませんが、この ExFrame01 というクラスは、別のプログラムからも、new ExFrame01() などとして利用することができます。
次のようなプログラムを作って実行しても同様の結果を売ることができます。
public class UseExFrame01 { public static void main(String[] args){ /* 拡張されたフレームを作成 */ ExFrame01 myframe = new ExFrame01(); } }
このような使い方をするときには、ExFrame01.java に main の部分は必要ありません。
import javax.swing.*;
/** JFrame の拡張 */
public class ExFrame01 extends JFrame{
/** コンストラクタ ************/
public ExFrame01(){
/* サイズを指定 */
setSize(400, 300);
/* 終了処理を追加 */
setDefaultCloseOperation(EXIT_ON_CLOSE);
/* 実際に表示する */
setVisible(true);
}
/** 他から呼ばれるだけならmainはいらない****/
}
前回 JFrame を利用したと同様に ExFrame01 を使うことができるのです。今回は動作テストのため、たいした機能を拡張していませんが、この方法は大規模なプログラムを作るときは大変な力になります。
他から呼び出して使うと考えて、上記のようにmainを別にしてもいいのですが、小さなプログラムの場合、普通は面倒なのでmainもひとつのファイルにまとめてしまいます。大きなプログラムでも、起動するだけのmainにしてしまってテスト用にしておくと便利なことがあります。
作成するクラスにどのような機能をもたせ、どの部分を main から指定していくか、これはとても大事なことです。これを上手に設計するとプログラムの流れが理解しやすくなり、間違いのないプログラムを書くことができます。
上記の ExFrame01.java をつくり実行してみなさい
ExFrame01.javaを拡張してフレームを2つ作る ExFrame02.java をつくり実行してみなさい
フレームの位置を指定しないと、全く同じところに2つフレームを作るのでわからないかも知れません。タイトルバーをドラッグして、2つになっていることを確認しなさい。
この場合も、setLocation(10, 20) などのメソッドを使って、位置をずらすこともできますが、コンストラクタ内に書くとみんな同じになりますから、結局重なります。
解決策は2つ。
(1) main の中で、myframe.setLocation(10, 20); として変更できます。setLocation は、JFrameクラスのメソッドですが、ExFrame02 は JFrame を継承しているので、このメソッドが含まれています。myframe はExFrame のインスタンスなのでこのメソッドを使えます。
(2)フレームの場所をWindows任せにできます。コンストラクタ内に次のように書けば、少し(タイトルバーの幅程度)ずらして表示します。この場合はmainには書く必要がありません。
setLocationByPlatform(true);