クラス
同じファイル内に別のクラスを作る。
ファイル名と異なるクラスはアクセス修飾子を付けるとコンパイルエラーになる。
public class Main {
public static void main(String[] args) {
System.out.println(Sub.add(4, 5)); // ①
//************* System.out.println(Sub.multi(4, 5)); // ②
Sub s = new Sub(); // ③
System.out.println(s.multi(4, 5)); // ④
//************* System.out.println(s.div(4, 5)); // ⑤
System.out.println(s.div2(4, 5)); // ⑥
//************* int num1 = Sub.num1; // ⑦
int num1 = s.num1; // ⑧
int num2 = Sub.num2; // ⑨
num2 = s.num2; // ⑩
//************* int num3 = s.num3; // ⑪
int num3 = s.getNum3(); // ⑫
System.out.println(num1 + " " + num2 + " " + num3); // ⑬
}
}
// Sub クラス -----------------------------------------
class Sub {
// フィールド --------------------------------------
int num1;
static int num2;
private int num3;
// コンストラクタ ------------------------------------
Sub(){
this.num1 = 6;
this.num2 = 7;
this.num3 = 8;
}
// メソッド ----------------------------------------
static int add(int a, int b) {
return a + b;
}
int multi(int a, int b) {
return a * b;
}
private int div(int a, int b) {
if(b != 0) {
return a / b;
}
return 0;
}
int div2(int a, int b) {
return div(a, b);
}
int getNum3() {
return this.num3;
}
}
①Subクラスの add() メソッドを呼び出している。直接呼び出す場合は「クラス名.メソッド名(引数)」
②は同じく multi() メソッドを呼び出そうとしているがコンパイルエラー。
main() メソッドが static なので main() メソッドから直接呼び出す場合は同じ static でないとエラーになる。
③Subクラスをインスタンス化している。Sub型の s という変数名にSubクラスを代入するイメージ。
④インスタンス化した s を使って multi() メソッドを呼び出している。
インスタンス化すれば s は main() メソッド内の変数となるのでインスタンスを経由すれば static は関係なくなる。
⑤private なメソッドにアクセスしようとしてるのでコンパイルエラー。
private はそのクラス内でしかアクセスできない。
⑥は private なメソッドにアクセスするためにSubクラスの他の private ではないメソッドを経由している。
⑦num1 が static ではないので直接アクセスできずコンパイルエラー。
⑧インスタンス経由なので s.num1 の値を取得できる。
⑨Subクラスの num2 も static なのでアクセスできる。
⑩インスタンスの static なフィールドにアクセスするので警告(黄色い線)はでるが可能。
⑪private はそのクラス内からしかアクセスできない。インスタンスからでも同じ。コンパイルエラー。
⑫Subクラスの getNum3() を経由して private な num3 にアクセスしている。
継承
import java.util.ArrayList;
public class Inheritance {
public static void main(String[] args) {
AAA c1 = new CCC(); // 実装元・継承元の型でインスタンス化できる!
AAA d1 = new DDD();
CCC c2 = new CCC(); // インスタンス化するクラスと同一型
DDD d2 = new DDD();
c1.aaa(); // AAA クラスにも num はあるが一番近い BBB クラスの num
d1.aaa(); // AAA型でも DDD クラスの num になる
// c1.className(); // コンパイルエラー
// AAA型なのでAAAにあるメソッドしか使えない
// className()メソッドが存在する型にキャストしなければならない
// 型を事前確認してからキャスト
if(c1 instanceof CCC) {
c1 = (CCC)c1; // これは意味がない AAA型で宣言しているのでAAA型のまま
CCC c3 = (CCC)c1; // 新しく宣言した変数に代入
c3.className(); // CCC型なので使える!
}
c2.className();
c2.aaa();
d2.className();
d2.aaa();
// 多態性 CCC と DDD を 同じBBB型として扱うよ!
System.out.println("\n多態性の確認だよ!");
ArrayList b1 = new ArrayList<>();
b1.add(new CCC());
b1.add(new DDD());
for(BBB b2 : b1) {
b2.className();
b2.aaa();
}
// インスタンスの外から直接 num を呼ぶと AAA型が優先される
// 混乱するので継承関係でフィールドは重複宣言しないようにする!
// それとできるだけインスタンス内のメソッドからフィールドを利用する!
System.out.println(c1.num);
System.out.println(d1.num);
}
}
// インターフェース ------------------------------------------------------------------
interface AAA {
int num = 3; // interface では final 扱いになる
void aaa(); // このクラスを実装または継承するクラスで必ず実装されなければコンパイルエラー
// インターフェースでは abstract を省略できる!
}
// AAA を実装 抽象メソッドを含んでいるので abstract にする ------------------------
abstract class BBB implements AAA {
int num = 4;
@Override
public abstract void aaa(); // オーバーライドしているが未実装
public abstract void className(); // 多態性利用のための宣言
}
// 抽象クラス BBB を継承 -------------------------------------------------------------
class CCC extends BBB {
private String name = "CCC";
@Override
public void aaa() { // ここで実装
System.out.println(num); // BBB で定義している num
}
@Override
public void className() {
System.out.println(this.name + "クラスだよ~~~ん");
}
}
// 抽象クラス BBB を継承 -------------------------------------------------------------
class DDD extends BBB {
private String name = "DDD";
int num = 5;
@Override
public void aaa() { // ここで実装
System.out.println(num);
}
@Override
public void className() {
System.out.println(this.name + "クラスだぜ!");
}
}