このエントリーをはてなブックマークに追加

ポイントというか心にとまったことのアウトプットです。

※個人的な重要度のバイアスがかかっているので、「べつにいいかー」と思ってたりすることはメモしてません。

※手を動かして理解したことなど、間違いを含む可能性があります。

※手元の環境は断りがなければ基本はjava 7 をIntelliJ IDEA Ultimate on OSX で動かしてます。


「クラス」

  • インスタンスメソッドは、オブジェクト生成のたびにコピーされない
  • 「インスタンス」は実体(化)という日本語をあてると「オブジェクト」という言葉と区別しやすいかも。
  • 例:Aクラスのインスタンスであるaオブジェクト

  • クラス内フィールド変数が同じオブジェクトを参照している例

public class MyRef {

    public final StringBuilder name;

    public MyRef(StringBuilder argName) {
        name = argName;
    }

    public void printName() {
        System.out.println(name);
    }
}

↑こんなクラスがあってこう↓

StringBuilder argName = new StringBuilder("abc");
MyRef obj1 = new MyRef(argName);
MyRef obj2 = new MyRef(argName);

obj1.printName(); //abc
obj2.printName(); //abc

argName.append("add"); //同じ参照が持たれているオブジェクトの状態変更
obj1.printName(); //abcadd
obj2.printName(); //abcadd

obj1.name.append("_add");
obj1.printName(); //abcadd_add
obj2.printName(); //abcadd_add
  • final は再代入が出来ないだけで、状態変更はできる(↑の例もそう)
  • フィールド修飾子の省略時のアクセス制御はpublic相当
  • 可変長引数 型... の形式で書ける
  • コンストラクタはメソッドじゃない
  • 独自の初期化メソッドは非推奨
  • コンストラクタ内のthis呼び出し(オーバーロード時)
  • コンストラクタは必ず書くことを推奨(デフォルトコンストラクタを避ける)
  • static 初期化ブロック
  • クラスフィールドと継承の実験
public class MyStatic {

    public static StringBuilder sb1 = new StringBuilder("sb");
    public static String s1 = "s";

    public static StringBuilder sb2 = new StringBuilder("sb2");
    public static String s2 = "s2";

}

public class MyExStatic extends MyStatic{

    public static StringBuilder sb2 = new StringBuilder("exsb");
    public static String s2 = "exs";

}
System.out.println(MyStatic.sb1); //sb
System.out.println(MyStatic.s1); //s
System.out.println(MyStatic.sb2); //sb2
System.out.println(MyStatic.s2); //s2

System.out.println(MyExStatic.sb1); //sb
System.out.println(MyExStatic.s1); //s
System.out.println(MyExStatic.sb2); //exsb
System.out.println(MyExStatic.s2); //exs

//スーパークラスから オーバーライドしていないフィールドの変更実験
MyStatic.sb1.append("append1");
MyStatic.s1 = "change1";

System.out.println(MyStatic.sb1); //sbappend1
System.out.println(MyStatic.s1); //change1
System.out.println(MyExStatic.sb1); //sbappend1
System.out.println(MyExStatic.s1); //change1 //※要注意 クラスフィールドが共通のため、サブクラスにも影響がある

//サブクラスから、オーバーライドしていないフィールドの変更実験
MyExStatic.sb1.append("exappend1");
MyExStatic.s1 = "exchange1";

System.out.println(MyStatic.sb1); //sbappend1exappend1 //※要注意 クラスフィールドが共通のため、スーパークラスにも影響がある
System.out.println(MyStatic.s1); //exchange1 //※要注意 クラスフィールドが共通のため、スーパークラスにも影響がある
System.out.println(MyExStatic.sb1); //sbappend1exappend1
System.out.println(MyExStatic.s1); //exchange1


//スーパークラスから オーバーライドしているフィールドの変更実験
MyStatic.sb2.append("append2");
MyStatic.s2 = "change2";

System.out.println(MyStatic.sb2); //sb2append2
System.out.println(MyStatic.s2); //change2
System.out.println(MyExStatic.sb2); //exsb  //オーバーライドしており影響なし
System.out.println(MyExStatic.s2); //exs //オーバーライドしており影響なし

//サブクラスから オーバーライドしているフィールドの変更実験
MyExStatic.sb2.append("exappend2");
MyExStatic.s2 = "exchange2";

System.out.println(MyStatic.sb2); //sb2append2 //スーパークラスには影響なし
System.out.println(MyStatic.s2); //change2 //スーパークラスには影響なし
System.out.println(MyExStatic.sb2); //exsbexappend2
System.out.println(MyExStatic.s2); //exchange2
  • サブクラスがスーパークラスと同じクラスフィールドを持っている時に、サブクラスからでもスーパークラスに影響を及ぼせるので、要注意
  • クラスをオブジェクトのように扱わない

  • 継承とメソッドの関係をテスト

public class MyBase {

    private void priMethod(String arg){
        System.out.println(arg + " : private");
    }

    protected void proMethod(String arg){
        System.out.println(arg + " : protected");
    }

    public void pubMethod(String arg){
        System.out.println(arg + " : public");
    }


    private static void priClassMethod(String arg){
        System.out.println(arg + " : private class");
    }

    protected static void proClassMethod(String arg){
        System.out.println(arg + " : protected class");
    }

    public static void pubClassMethod(String arg){
        System.out.println(arg + " : public class");
    }
}

public class MySub extends MyBase{

    public void exec(){

        System.out.println("--------");

        // priMethod("MySub"); //コンパイルエラー
        proMethod("MySub");
        pubMethod("MySub");

        // priClassMethod("MySub");  //コンパイルエラー
        proClassMethod("MySub"); //インスタンスからクラスメソッドへアクセス可能
        pubClassMethod("MySub"); //インスタンスからクラスメソッドへアクセス可能

        System.out.println("--------");

    }

    public static void execStatic(){

        System.out.println("--------");

        // priMethod("MySub"); //コンパイルエラー
        // proMethod("MySub"); //コンパイルエラー
        // pubMethod("MySub"); //コンパイルエラー

        // priClassMethod("MySub");  //コンパイルエラー
        proClassMethod("MySub");
        pubClassMethod("MySub");

        System.out.println("--------");
    }


    @Override
    public void proMethod(String arg){
        // protected のメソッドをpublic でオーバーライド

        //アクセス可能
        super.proMethod(arg);
        System.out.println(arg + " : override proMethod");
    }

    @Override
    public void pubMethod(String arg){
        //アクセス可能
        super.pubMethod(arg);
        System.out.println(arg + " : override pubMethod");
    }

    // コンパイルエラー
    // 親のprivate をオーバーライド出来ない(というかオーバーライドできる意味が無い?)
//    @Override
//    protected void priMethod(String arg) {
//        System.out.println("override priMethod : " + arg);
//    }

    // コンパイルエラー
    // protected のメソッドをprivate でオーバーライドしようとした
//    @Override
//    private void proMethod(String arg){
//        System.out.println("override proMethod : " + arg);
//    }

    //コンパイルエラー
    // staticメソッド(クラスメソッド)のオーバーライドは出来ない
    // superはstaticメソッドでは参照できない
//    @Override
//    public static void pubClassMethod(String arg){
//        super.pubClassMethod(arg);
//    }
}
MyBase myBase = new MyBase();
myBase.proMethod("myBase"); //myBase : protected  //※要注意 継承先じゃなくても同パッケージ内であればアクセス可
myBase.pubMethod("myBase"); //myBase : public

System.out.println();

// MyBase.priClassMethod("MyBase"); //コンパイルエラー
MyBase.proClassMethod("MyBase"); //MyBase : protected class  //※要注意 継承先じゃなくても同パッケージ内であればアクセス可
MyBase.pubClassMethod("MyBase"); //MyBase : public class

System.out.println();

MySub mySub = new MySub();
mySub.proMethod("mySub");
//mySub : protected
//mySub : override proMethod

mySub.pubMethod("mySub");
//mySub : public
//mySub : override pubMethod

System.out.println();

// MySub.priClassMethod("MySub"); //コンパイルエラー
MySub.proClassMethod("MySub"); //MySub : protected class //※要注意 継承先じゃなくても同パッケージ内であればアクセス可
MySub.pubClassMethod("MySub"); //MySub : public class

System.out.println();

mySub.exec();
//--------
//protected : MySub
//public : MySub
//override pubMethod : MySub
//protected class : MySub
//public class : MySub
//--------

MySub.execStatic();
//--------
//protected class : MySub
//public class : MySub
//--------
  • protected は同パッケージ内であれば別クラスからでもアクセスできる(知らんかった。。。)
  • デザパタ「テンプレートメソッド」
  • フィールド、メソッドのpublic 有りと無しは、パッケージ外から見れるかどうか。
  • アクセス制御を適切につかうことで、「見えなくする」→「考えなくてもいい状態」にできる。
    • ↑でも実際の仕事では、親クラスの実装とか、見ちゃう。。。これからは意識してみよう。
  • ネストしたクラス
  • private static なネストクラスのプライベートフィールド・メソッドは、エンクロージングクラス(囲っているクラス)からアクセス可能。エンクロージングクラスのプライベートフィールド・メソッドもネストクラスからアクセス可能
  • 内部クラス(非staticネストクラス) エンクロージングオブジェクトへの参照を持つ。依存関係を生む記述ができるので、特別な理由がない限りはstatic なネストクラスを利用する。
  • ローカル内部クラス メソッドなどのブロック内で定義されており、ブロック外からのアクセスは不可
  • 匿名クラス  (具体的な利用シーンを思い浮かべながら試しに実装しないとな。。。)
  • クラス設計については別途勉強する必要があると思った、個人的に。

疑問

  • 「型と雛形」のところがよくわからなかった
  • ユーティリティクラスは本当にfinalにするべきなのか
  • クラス修飾子のpublic 有無の違い
    • → publicはパッケージ外から見れる。ついてなければ見れない
  • フィールド修飾子の、transient, volatile
  • オブジェクト用の初期化ブロック(コンストラクタとどっちが先に実行される?)
    • 書かれた順に実行される。いくつでも書ける。共通処理の記述と、匿名クラスの初期化のため。コンストラクタの前に呼び出される。
  • メソッド修飾子のsynchronized, native
  • クラスの初期化タイミング(static 初期化ブロック)
  • 継承と委譲の使い分け「型定義の共通部のくくりだしが必要な場合のみ拡張継承に」