まずはじめに
Javaの学習を始めました。
こんなレベルから・・・?というくらい超基礎~から執筆します。
自身が復習できるような自身の備忘録を作成していきます。
そもそもJavaって何?
Javaはプログラミング言語の名前
三大言語(Java,C++,Python)のひとつ
どんなところに使われている?
- Webサービス
- PC/androidアプリ
- 基幹システム
業務用システムのようなイメージ - 組み込みシステム
電子レンジとかハードウェアに組み込まれるシステムのこと - ソフトウェア
- lot
internet of thingsの略
物がインターネットとつながる仕組みのこと
ネット経由で家電などの"モノ"を操作したり、制御したりするシステム
アレクサで照明をつけたり、エアコンをつけたりするのがわかりやすいかと
などなど
上記のような幅広い分野で使用されている。
イメージできるほぼすべてのITサービスで活用できそう。
逆にJavaにできないことって何?
Javaが苦手なこと
開発スピートが遅い
開発はできるが、オブジェクト指向に基づきクラスなどの定義を行っていく必要があるので
開発には時間がかかる。裏を返せば時間をかけて拡張性を生かしていくという言語でもある。
小規模開発に向かない
もちろんできないということではない。
Javaはオブジェクト指向に基づき、様々な枝を作成しそれらをつなげることで良さを生かせる言語。
小規模開発であれば、Javaに比べ、拡張性が低いが簡易アプリを作成するのに長けているRubyなどの言語を使用するほうが効率が良い。
オブジェクト指向ってなに?
Javaといえば?ときくと「オブジェクト指向」という単語が返ってくるくらい
Javaにおいて最重要キーワードだと思う。そして避けては通れない。
オブジェクト指向を超噛み砕いてイメージ・解釈
プログラムを「部品」と考えて、それぞれ「部品」を構築したのちに紐づけをして、関連動作させる仕組み・考え方。
つまりは、部品一つ一つを構築していくので、かなり細かく作りこみが必要な言語。
また部品(プログラム)同士のつながりの作り方・ルール、つながり方の書き方を理解していくところが大きなポイントとなりそう。
オブジェクト指向を完全攻略
プロジェクト指向を理解するメリット
一回作ったプログラムは修正や追加など変わっていくとがほとんど。
1つのメソッド内で機能実装をするには限界がある。
例えば、複数人での作業ができない、修正が非常に煩雑などデメリット発生する。
オブジェクト指向の考え方に基づいてプログラムを組むことで、
データをわかりやすくまとめて管理することができるようになる。
Javaには2種類のクラスがある
-
実行用クラス
プログラムを実行するためのクラス
クラスの中にmainメソッドが含まれるもの -
設計図クラス
属性・操作を設定できるクラス
オブジェクト指向においてこのクラスがとても重要属性・・・何の データ を持っているのか?変数を用いて用いて実現する。
(ex:教科、点数、名前 など)操作・・・何の 処理 を出来るのか?メソッドを用いて実現する。
(ex:文字を表示する など)
具体的なデータを入れ込んで、生成される結果(クラスから作られる実体)が「オブジェクト」
データと処理に基づいてプログラムを組む考え方が「オブジェクト指向」
この、設計図クラスが「オブジェクト指向」においてとても重要。
クラスが複数になるといいことがある
for文などの構文学習を最初にしてしまうと
1つのクラス内でmainメソッド内のみでの処理実行が行うイメージがあると思う。
だが上記でも述べたが現場は違う。なぜなら実用的ではないから。
実現場ではいくつものクラスが存在し、それらが枝分かれし、つながっている。
そうすることで下記のようないいことがある。
- 開発効率が上がる
ファイルが複数あるため、チーム開発がしやすい - 保守性が上がる
メンテナンスがしやすい。修正箇所が限定できる。 - メモリ効率が上がる
ファイルが1つに集約されていると、処理をする際にすべての読み込みが必要な為、メモリ効率が悪い。
クラスが分かれていることで、必要なプログラムが必要な時だけ作動するため、メモリ効率がいい。 - システム化
データと処理のデータ構成のため、現実社会→データ化がイメージしやすい。
プログラムに落とし込みやすい。
設計図クラスの書き方
- 属性(変数)の定義方法
- 操作(メソッド)の定義方法
がわかれば、設計図クラスが作成できる。
class クラス名{
変数の定義
メソッドの定義
}
変数の定義方法
- データ型
- 変数名
//データ型 変数名;
String name;
int point;
属性として定義する変数のことを「メンバー変数」と呼ぶ
ポイントはメンバー変数はクラスが定義されているすぐ下に定義すること!
メンバー変数は同クラス内が有効範囲になる。
メソッドの定義方法
設計図クラスのメソッドは「呼び出される側」
実行用クラスで「呼び出す側」との対になっている。
必要な要素は下記3点
- 戻り値
呼び出し元へ返す値
戻り値を記載するためにはreturn文を使う。
注意点はreturnで返す数値の型と、メソッド定義で定義する型を必ず合わせること。
そのメソッドが何も戻り値を返さない場合にはvoidを戻り値の型に記述する。 - メソッド名
pointとかscoreとか適してるものであれば、好きに定義してOK - 引数リスト
呼び出し元から受け取る値
必ずデータ型と変数名の記載が必要。無いと実行用クラスから情報が受け取れない。
戻り値の型 メソッド名(引数リスト){
処理
}
//クラス定義
class Student{
//メンバー変数定義
String name;
int engScore;
int mathScore;
//メソッド定義(引数無し、戻り値無し)
void display(){
System.out.println(name + "さん"); //メンバー変数の"name"を使っている
System.out.println("英語" + engScore + "点・数学" + mathScore + "点");
}
//メソッド定義(引数あり、戻り値無し)
void setScore(int eng, int math){
engScore = eng;
mathScore = math;
}
//メソッド定義(引数無し、戻り値あり)
double getAvg(){
double avg = (engScore + mathScore) / 2.0;
return avg;
}
}
System.out.printlnだけだと、実行用クラスからデータは受け取ってるように見えるけど
引数無し扱いになるっぽい。初学者ならではの感覚なのかも?
実行用クラスの書き方
上記で設計図クラスを作成することができました。
しかし設計図クラスは、属性と操作を定義する箱であり、
それらをプログラムとして実現するためには実行用クラスを生成する必要があります。
実行用クラスを生成し、mainメソッドを定義した上で下記コードを記述します。
設計図クラス名 オブジェクト名 = new 設計図クラス名();
Student stu1 = new Student();
newはメモリ領域を確保するようなイメージ
デフォルトで初期値(0など)が勝手に入っており、それらを後から代入で上書きする。
クラスをもとにオブジェクトを生成する作業を「インスタンス化」と呼ぶ
プログラムの中で実際にできたオブジェクトのことを「インスタンス」と呼ぶ場合もある。
インスタンス=オブジェクト?インスタンス化=オブジェクト化?
例えば、山田さんで作成、インスタンス1人目、佐藤さんで登録、インスタンス2人目のようなイメージ。
オブジェクト名.変数名
オブジェクト名.メソッド名(引数)
stu1.name="菅原";
stu1.setScore(80,90);
stu1はStudent stu1 = new Student();で定義したstu1
nameは設計図クラスで定義したメンバー変数、setScoreは設計図クラスで定義したメソッド名
class StuSample{
public static void main(String[] args){
Student stu1 = new Student();
stu1.name = "山田"; //設計図クラスメンバー変数へ代入
stu1.setScore(90, 80); //設計図クラスで定義したメソッドを実行
stu1.display(); //設計図クラスで定義したメソッドを実行
System.out.println("平均" + stu1.getAvg() + "点"); //設計図クラスで定義したメソッドを実行
}
}
実行用クラスをコンパイル・実行すればOK!
オーバーロード
オーバーロードとは、設計図クラスの書き方の手法の1つ。
同じクラス内に同じ名前で引数の型や数が違うメソッドを複数定義する手法。
システムはどちらに分岐したらよいかどのように判別するの?
A:メソッド名プラス+引数の型や数で判別する
class Student{
void setDate(String n){ //1.setDateにString nが引数で設定されている
}
void setDate(String n,int e,int m){ //2.setDateにString型n,int型e,int型mが引数で設定されている
}
}
main(~){
Student stu = new Student();
stu.setDate("山田"); //上記、設計図クラス「1.~」へ分岐
stu.setDate("山田",80,90); //上記、設計図クラス「2.~」へ分岐
}
引数の記載順番って違ったら思った挙動しなかったり、
コンパイルエラーにつながったりするから大切。
オーバーロードのメリットとは
扱うメソッドの種類を増やさず、わかりやすいものを設定することができる。
これをしなかったら「setDate」「settingDate」「dateSet」「setDate2」みたいな
似たような名前で溢れかえって、どれがどれ・・・?みたいなことになりえる。
管理の手間、命名・作成の手間を省ける。
つまり上記例だと、それぞれのデータ型を受け取れる「setDate」があったら楽だよねって話。
余談だが、System.out.println();もシステム内部でオーバーロードされているため()内、どんな内容でも処理ができる。
コンストラクタ
設計図クラスでの使うメソッドの名前
某説明でオブジェクトの初期化のために使われる特殊なメソッドっていう説明があったが、正直よくわからない・・・。
自分なりの解釈は「new クラス名(コンストラクタへの引数)」を設定できるおかげで
Student.setDate("山田");
みたいな代入式をわざわざ書かなくてよくなる。
簡単にコーディングする方法の1つというイメージ。
値が何も入っていない状態というのは、よろしくないとされるため
生成と同時に代入できる状態を指しているコンストラクトはより良いコーディング。
コードは簡単に、機能的にがベストなのでその手法1つっていう認識でOKかと。
コンストラクト設定には下記要件が必要
- 【設計図クラス側】設定するメソッドの名前を名前がクラス名と同じにする必要がある
クラス名と同じで大文字スタート (ex:Student,Car...) - 【設計図クラス側】戻り値を持たない
戻り値の型のところには何も書かない。「void」とも書かない。 - 【実行用クラス型】実行用クラスへの記述 new クラス名(コンストラクタへの引数)
引数をnew クラス名(コンストラクタへの引数)
のコンストラクタの引数に入れれる。
class Student{
Student(String n){ //1.StudentにString nが引数で設定されている
}
Student(String n,int e,int m){ //2.StudentにString型n,int型e,int型mが引数で設定されている
}
}
main(~){
Student stu2 = new Student("山田"); //上記、設計図クラス「1.~」へ分岐
Student stu1 = new Student("山田",80,90); //上記、設計図クラス「2.~」へ分岐
}
コンストラクトは上記のようにオーバーロードできる。
余談、これまでのコンストラクタってStudent stu = new Student();
で
コンストラクタ引数に何も書いてなかったし、設計図クラスにもコンストラクタ作成してなかったよね・・・?
これはコンパイル時に自動でデフォルトコンストラクタ(Student(){})
というものが
設計図クラスに作成されていたが、処理も何もないので終わっていただけ。
逆に、設計図クラスにコンストラクトを設定したのに、
実行用クラスにコンストラクタ引数になにも指定しないと
デフォルトコンストラクタは作成されずにエラーになるで要注意。。。
static
全インスタンスが共通して使える変数を設定できる手法。
インスタンスごとでデータ生成される方式ではなく、インスタンスの生成関係なく共通項としての存在。
メンバー変数やメソッドに「static」をつけるだけで使うことができる。汎用性高い。
でもそれってどういうときに使うの?下記の通り
- 全部のインスタンスから共通して使う変数やメソッドを作りたいとき
- クラスに関連する便利なメソッドをまとめたいとき
- インスタンス生成とは別軸でインスタンスの情報を生成・管理したいとき
正直イメージが沸かないので、下記例でイメージを深めていく。
インスタンスの中の変数ではカウントすることは難しい。
class Student{
int counter=0;
Student(){
...
counter++;
}
}
インスタンスの作成数をカウントしたいのに、
設計図クラスはインスタンスごとにデータが新しく作成されるから
インスタンスごとにcounterが0→1
になるだけでインスタンス数のカウンターにはならない。
class Student{
static int counter=0;
Student(){
...
counter++;
}
static void display(){
System.out.println(counter+"人です");
}
}
設計図クラスでstaticで定義していればオブジェクトを生成しなくても利用できる。
クラス名.変数(メソッド)名
の記述で読み込みを行える。
どんな時に使うの?下記例
class Student{
Student(String n){
}
//displayメソッドにstaticを使用する
static void display(){
System.out.println(n);
}
}
main(~){
Student stu1 = new Student("山田");
//設計図クラスでdisplayメソッドでstaticを使用しているため
//stu1.displayではなく「設計図クラス名.メソッド名(Student.display();)」で呼び出せる
Student.display();
}
そのデータはオブジェクトごとで完結していいものなのか?
それともオブジェクトごとではなく、全体に波及したいものなのか?
そういった視点で「static」を使用する。
カプセル化
設計方針の名前。
メンバー変数をprivate設定、メソッド、クラスはpublic設定する設計方針のこと。
private?public?それなに?→アクセス修飾子
アクセス修飾子とは
クラスやメンバー変数やメソッドの公開範囲を指定することができる
パターンとしては4パターンでどこまで公開するかを決めることができる。
public //同クラス・同パッケージ・サブクラス・他
protected //同クラス・同パッケージ・サブクラス
何もつけない //同クラス・同パッケージ
private //同クラス
具体例は下記の通り
class Student{
private int score;
public void setScore(int s){
score=s;
}
}
Student stu = new Student();
stu.setScore(80); //設計図クラスでpublic指定されているため可能
Student stu = new Student();
stu.score=80; //設計図クラスでprivate指定されているため不可能
【カプセル化のメリット】
- 代入前処理
メンバー変数への直接編集を防止し、メソッドを通じてメンバー変数を編集させることで
メンバー変数の代入ルールをメソッドに定義することができ、適切なルールのもと値の代入を行うことができる。 - プログラムの修正範囲が狭まる
private定義しているものは他へのクラス等への影響が少ないため、修正・追加範囲が狭まる。
逆にpublicだと修正範囲が多くなるイメージも持っておく。
public class Student5{
private String name; //メンバー変数はprivate
private int score; //メンバー変数はprivate
public Student5(String n){ //メソッドはpublic
name = n;
}
public void setScore(int s){ //メソッドはpublic
if(0 <= s && s <= 100){
score = s;
} else {
System.out.println(name + "さんの点数が範囲外です");
score = 0;
}
}
void display(){
System.out.println(name + "さん:" + score + "点");
}
}
class StuSample5{
public static void main(String[] args){
Student5 stu1 = new Student5("山田");
stu1.setScore(80);
stu1.display();
Student5 stu2 = new Student5("佐藤");
stu2.setScore(-50); // stu2.score=-50;はメンバー変数への直代入だがprivateなので不可
stu2.display();
}
}
継承
継承とは、既存クラスをもとに変数やメソッドを追加したクラスを作ること。
言い換えると「拡張」のほうがイメージが沸きやすいかもしれない。
ここまでは実行用クラス:設計図クラス(1:1)の処理であったが、継承が絡むとクラスが増えていく。
継承関係にある親クラスのことをスーパークラス、子クラスのことをサブクラスという。
スーパークラスは最大共通項を記載し、サブクラスで独自の項目を定義したりする。
スーパークラスは階層は一番下のため、開発用クラスとつなげるのはサブクラス。
記述方法は「extends」を記述し、紐づけたいスーパークラスを記述するだけ。
extendsは拡張するという意味。
class Student extends Person{
}
//サブクラスStudentからスーパークラスPersonを呼び出している
【メリット】
- コーディングが楽になる
サブクラスのコーディング量が減る - メンテナンスも楽になる
情報が集約されているため、メンテナンスが楽
【注意点】
- 継承できるスーパークラスは1つだけ
複数クラスの継承はできない - スーパークラスのコンストラクタはサブクラスに継承できない
コンストラクタの発火条件はクラス名=メソッド名だがその条件が揃わないため
サブクラスからスーパークラスのコンストラクタを呼び出して使用することはある。
サブクラスに権限を移さない範囲での使用はできる。
public class Person{
private String name;
public void setName(String n){
name = n;
}
public void display(){
System.out.println("名前" + name);
}
}
public class Student extends Person{
private int stuNo;
public void setStuNo(int s){
stuNo = s;
}
public void displayStuNo(){
System.out.println("学籍番号" + stuNo);
}
}
public class StuSample{
public static void main(String[] args){
Student stu = new Student(); //紐づけをするのはサブクラス
// スーパークラスのメソッド
stu.setName("山田");
stu.display();
// サブクラスのメソッド
stu.setStuNo(1);
stu.displayStuNo();
}
}
【ポイント】
- 実行用クラスに記述する紐づけクラスはサブクラス
- 実行用クラスではサブクラスとスーパークラス両方のメソッドを使える
オーバーライド
スーパークラスで定義されているメソッドをサブクラスで再定義すること。
//スーパークラス
class Person{
void display(){ //スーパークラスでdisplayメソッドを定義
}
}
//サブクラス
class Student extends Person{
void display(){ //サブクラスでスーパークラスのdisplayメソッドを上書き
}
}
//実行用クラス
Student stu = new Student();
stu.display();
スーパークラスで定義されているメソッドをサブクラスで再度同定義をして上書きをする。
オーバーライドするためには
- 戻り値の型 (returnで返すやつ or void)
- メソッド名 (displayメソッドとか)
- 引数の型と数 (setNum(int n)の「int n」部分)
がすべて同じことが発火の条件
参照順が実行用クラス→サブクラス→スーパークラスなので
サブクラスのメソッドが先に発火するイメージ
カプセル化がなされていると、スーパークラスのメンバー変数への直接アクセスはできないため、メソッドを通じてメンバー変数に触れるようにスーパークラスに定義するのがよい
// スーパークラス
public class Super{
//メンバー変数nameをprivateで定義
private String name;
//メソッドでnameを取得できるものを準備しておくとサブクラスから呼び出せる
public String getName(){
return name;
}
}
余談
オーバーライドはメソッドの上書きする方法
オーバーロードは1つのクラスの中で同じメソッドを複数定義する方法
ライドは乗る→上書き、ロードは読み取りみたいな理解をしておくとわかりそう。
似てるけど違うものなので注意
this.~ super.~
自クラス内・スーパークラスのメソッドやメンバー変数を呼び出す方法。
このあたりから、話がぐっと複雑に、便利になるイメージ。
this.~ //自クラスの~
super.~ //スーパークラスの~
//スーパークラス
class Person{
String name;
void setName(String name){
// setNameメソッド内でもnameメンバー変数でもnameがある
// this.name(メンバー変数)にname(メソッド内引数)を=で数値を代入している
this.name=name;
}
void display{
System.out.println(name);
}
}
//サブクラス
class Student extends Person{
int stuNo
void display(){
// displayメソッドがオーバーライドされているが、superを使うことで
// オーバーライドされたスーパークラスのメソッドも呼び出すことができる
super.display();
System.out.println(stuNo);
}
【メリット】
- 同じコードを何度も書かなくていい
- 引数の名前を考えなくてもいい
Eclipseがこのような仕様で自動で初期値を記述してくれるシステムがある
this() super()
コンストラクタの呼び出しをすることができる
コンストラクタ内で使用する。コンストラクタとコンストラクタをつなげるイメージ!
必ずコンストラクタ内の先頭に記述すること
コンストラクタ内にsuper();もしくはthis();がない場合は自動的にsuper();が代入される。
どんな時に使える・・・?
コンストラクタで引数に異常値が入っていた場合の処理
this(引数) //同じクラス内でコンストラクタを呼び出す
super(引数) //スーパークラスからコンストラクタを呼び出す
//スーパークラス
class Person{
String name;
Person(){ //コンストラクタの引数無しで発火
this("未設定"); //Person("未設定")と置き換えられ、下のコンストラクタが発火
}
Person(String name){
this.name=name; //ここでthis.nameに"未設定"が代入される
}
}
//サブクラス
class Student extends Person{
int stuNo;
Student(String name,int stuNo){
// 継承ではスーパークラスのコンストラクタは
// 呼び出せないがsuperを使うことで呼び出せる
super(name);
this.stuNo=stuNo;
}
}
finalキーワード
クラス、メンバー変数、メソッドにつけられる修飾子。
「これで最後」という意味になる。
クラス、メンバー変数、メソッドでそれぞれ意味合いが変わってくる。
final class Student{ //Studentクラスにfinalキーワードをつける
}
//これは継承ができなくなるという意味
//つまりclass DameStudent extends Studentのようにサブクラスは生成できなくなる
final int BASE_NO=1000; //メンバー変数にfinalをつける
//メンバー変数への値の代入ができなくなる。つまり「定数」を作れる。円周率3.14とかよい例
//本例ではBASE_NO=2000;とか代入はできない。定数を設定する場合変数は大文字で設定するのがセオリー
//スーパークラス
final void backup(){ //メソッドにfinalをつける
}
//オーバーライドができなくなる。つまり、スーパークラスのメソッドをサブクラスで再定義できない。
参照型の型変換の前に
参照型の型変換の話をする前に、データ型について少し振り返ってみる。
データ型とは?
データの種類
Javaのデータ型は3,000種類ほどあるといわれている。
基本データ型
全部で8種類のみ。逆に言えば、3000種類のうち8種類しかない。
- 整数 byte short int long
- 小数 float double
- 文字 char
- 真偽値 boolean
参照型
String型などが挙げられる。
別の領域に保存されている参照アドレス値のようなものでデータを管理している。
直接変数に値が代入されているわけではなく、アドレス値で管理されているイメージ。
String name="犬";
はnameに「犬」が直接代入されているわけではなく
「犬」が別の場所に保管され、参照値(住所のようなもの)が入り、nameとつながる。
つまり
変数と内容物のやり取りに、参照値を挟むか、直接代入されているかの違い。
参照型はname⇒参照値⇒犬
となっている。
逆に基本データ型はnumber=1
と直接変数に代入される。
参照型の型変換
継承関係にあるクラス同士でオブジェクトの型変換の方法の話
状況によって記載する内容が異なる。
- サブクラスの値をスーパークラスの値に代入する場合(スーパークラス=サブクラス)
特記は必要なく自動で代入できる。
//スーパークラスがperson、サブクラスがStudentとする
Student stu1 = new Student()
Person psn = stu1
//スーパークラス(person)のpsn変数にstu1を代入する。
//見た目はstu1の情報が丸々代入されているように見えるが処理としては
//stu1の中のPersonクラスが持っている情報のみが代入されている。
- スーパークラスの値をサブクラスに代入する場合(サブクラス=スーパークラス)
キャストを明示する必要がある。
//スーパークラスがperson、サブクラスがStudentとする
Student stu2 = (Student)psn; //(Student)のようにキャストの記載が必要になる
// サブクラスに(stu2)スーパークラス(psn)の値を代入する。
// スーパークラスの内容だけでは、サブクラスの独自の値などの要件を満たせない可能性があるので
// キャストを明示して実行許可をする必要がある
instanceof
便利なコードなのでメモ程度
if (psn instanceof Student5){
...
}
//対象オブジェクト instanceof クラス名
//対象オブジェクトにクラスが含まているかどうかを調べることができる
//結果はtureかfalseで出力される
抽象クラスとポリモフィズム
実装内容を持たないメソッドを「抽象メソッド」とよび頭に「abstract」をつける
クラスの中に抽象メソッドが含まれているクラスのことを「抽象クラス」という。
抽象クラスはインスタンス化はできない。
え?つまりどういうこと?インスタンス化できないクラスに意味ってあるの?
⇒他クラスと紐づけをしてようやく意味が発生するクラス。
こうすることで、同じクラスが条件によって違う挙動をする設定ができる。
いろいろ条件があるが、コードを読む場合は実行用クラスから情報の流れを読み取るとわかりやすい。
public abstract class Club{
private String name; // 部活動名
public Club(String name){ //実行用⇒サブと映ってきた部活情報をnameに代入
this.name = name;
}
public void display(){
System.out.println("部活動名" + name);
}
public abstract void practice(); //抽象メソッド
}
public class TandF extends Club{ //抽象クラス(Club)のサブクラスに設定
public TandF(String name){ //実行用クラスから来た部活名をスーパークラスへ反映
super(name);
}
public void practice(){
System.out.println("準備体操");
System.out.println("走り込み");
}
}
public class Football extends Club{ //抽象クラス(Club)のサブクラスに設定
public Football(String name){ //実行用クラスから来た部活名をスーパークラスへ反映
super(name);
}
public void practice(){
System.out.println("ドリブル練習");
System.out.println("ミニゲーム");
}
}
public class Student6{
private String name; // 生徒の名前
private Club club; // Clubオブジェクト
public Student6(String name, Club club){
this.name = name;
this.club = club;
}
public void display(){
System.out.println("生徒氏名:" + name);
club.display();
}
public void practice(){
club.practice();
}
}
public class StuSample6{
public static void main(String[] args){
//コンストラクトでTandFクラスのnameに「陸上部」を代入
TandF taf = new TandF("陸上部");
//コンストラクトでFootballクラスのnameに「サッカー部」を代入
Football fb = new Football("サッカー部");
Student6 stu1 = new Student6("山田",taf); //コンストラクトでStudent6クラスへデータを2個渡す
stu1.display();
stu1.practice();
Student6 stu2 = new Student6("佐藤",fb); //コンストラクトでStudent6クラスへデータを2個渡す
stu2.display();
stu2.practice();
}
}
すべては実行用クラスから入ってどのように設計図クラスで分岐しているかを把握することが大切
(メモ)Club club/taf/fb周りの挙動がいまいちわからない(また追記します)
インターフェイス
定数と抽象メソッドのみ定義できる。
つまり動かない値や前提条件などをまとめておける箱のようなイメージ。
interface Englishable{
String LANG = "英語"; //public static finalと同義
void displayEng(); //public abstractと同義
}
インターフェイスは抽象クラスと同義であるため、インスタンス化はできない。
インターフェイスを実装(≒継承)したクラスを通じてインスタンス化をすることが可能。
インターフェイスを実装するときには書き方がある!継承の「extends」ではないので要注意!
//StudentクラスにEnglishableインターフェイスを実装する方法
class Student implements Englishable{ //「implements インターフェイス名」で実装
String name;
...
void displayEng(){ //インターフェイス内の抽象メソッドはここでオーバーライドで定義の必要あり!
System.out.println("名前:"+name);
}
...
}
インターフェイスは抽象クラスとは違い複数実装することができる。
抽象クラスは1つしか継承することができない。
【イメージ差・用語差に注意】
抽象クラスは継承・・・枝を張るイメージ 定数・抽象メソッドを持つ
インターフェイスは実装・・・色を塗るイメージ メンバー変数・メソッドを持つ
すごく噛み砕くとインターフェイスはRPGでいう装備のようなイメージ。
パッケージ
パッケージとは複数のクラスをまとめるための仕組み
コード内に宣言をして定義する。
package pack;
public class Student{
...
}
//クラスにパッケージを宣言する
またStudent.javaをpackにパッケージするとコーディングしたので、
実ファイルも同様のファイル構成にする必要がある。
つまりは「pack」フォルダを作成してStudent.java/Student.classを格納させる必要がある。
また、パッケージ化をするとクラスの正式名が変わる。
今回例の場合「pack.Studentクラス」という正式名に代わる。完全修飾名という。
//pack.Student
package pack; //packの中にStudentクラスを配置することを記述
public class Student{
...
}
import pack.student //import完全修飾名で連携ができる pack.studentを利用できる。
public class StuSample{
...
}
実行用クラスと設計図クラスの関係性になる。
package pack;
public class Student8{
private String name;
public Student8(String name){
this.name = name;
}
public void display(){
System.out.println("氏名:" + name);
}
}
import pack.Student8; //importでpack.Student8を連携
public class StuSample8{
public static void main(String[] args){
Student8 stu = new Student8("山田");
stu.display();
}
}
結局、オブジェクト指向って結局なんやねん?
決まりやルールの話ではなく、概念の話。抽象的な理解にどうしてもなってしまう。
機能を部品化し、部品を組み合わせてプログラムを完成させる考え方
【設計で考えること】
・利用者が増えても拡張性が高いものとなっているか
・違うモノとの関係性でバランスが崩れないか
・物の振る舞いや定義が明確になっているか
・利用する人がわかりやすい形になっているか
・ばらばらに考えることができているかという観点で設計をしていかなければならない。
それらをオブジェクト指向の3大要素に基づいて構築していく。
オブジェクト指向3大要素
-
継承
同じようなプログラムは共通化して使う考え方
クラス同士で情報を分割して持ち、それぞれがデータのやり取りが可能にする仕組みのこと。
効率的なソースコードになっているため修正や追加を効率的に実施できる。
(スーパークラス(親クラス)、サブクラス(子クラス)がその具体的な内容にあたる。) -
ポリモーフィズム(多態性)
汎用的な形にできるようにしましょうという考え方
1つの関数・メソッドが状況に応じて処理を、それぞれに適した処理を行う。 -
カプセル化
ほかのプログラムから干渉されないように作る考え方
編集ができる項目とできない項目の定義を行い、情報を管理する仕組み
アクセス修飾子を用いて、直接アクセスを制限する。
すべてがこれらを行わなければならないという意味ではなく、状況に応じて適応していく。
まとめるとオブジェクト指向とは、
いかに効率よく開発を行うか突き詰めた考え方であるということになる。