
ポイントというか心にとまったことのアウトプットです。
※個人的な重要度のバイアスがかかっているので、「べつにいいかー」と思ってたりすることはメモしてません。
※手を動かして理解したことなど、間違いを含む可能性があります。
※手元の環境は断りがなければ基本は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 初期化ブロック)
- 継承と委譲の使い分け「型定義の共通部のくくりだしが必要な場合のみ拡張継承に」