Javaお勉強(3)

Java難しいよJava

Arrays.binarySearchメソッド
  • 検索して見つかった要素の添字を返す
  • 使う前にsortしておく必要あり
ジェネリックの継承型指定
<型パラメータ extends データ型> → データ型かそのサブクラスのみを指定
■ワイルドカード指定
<? extends 型パラメータ> → 型パラメータのデータ型かそのサブクラスのみを指定(上限境界ワイルドカード)
                オブジェクトの追加は出来ない(addとかは型安全でないのでダメ)
<? super 型パラメータ> → 型パラメータのデータ型かそのスーパークラスのみを指定(下限境界ワイルドカード)
               オブジェクトの追加はOK
import java.util.*;
class Foo {
    public void add(List<? extends String> list) {
        list.add("hoge");    //コンパイルエラー(上限境界ワイルドカードなのでオブジェクトの追加が出来そうで出来ない)
        Object obj = list;    //OK
        String str = list.get(0);    //OK
        list = new ArrayList<String>();    //OK
        list = new ArrayList<Object>();    //コンパイルエラー(Object型はString型のサブクラスではない)
    }
}
Setとか
  • 全てのSetがadd出来るとは限らない
    • SortedSetはその設計上addできない
  • TreeSetのsubSetメソッドはSortedSet型を返すので注意
  • HashSetは重複許さない
Comparableインターフェース(自然順序付け)
  • IntegerとかStringとか他たくさん
  • 無条件でArray.sort()できる
  • 無条件でPriorityQueueの順番が自然順序付けになる
newするときに左辺と右辺でクラスが異なるときに、同じ名前の変数とかメソッドが宣言されていたとき

まあ基本的に左辺のメソッドの型、クラス変数になる

  • インスタンス変数は左辺になる
  • メソッドは右辺になる(オーバーライドによる上書き)
class Super {
    public String str = "Super";
    public void method() { System.out.println("Super"); }
}
class Sub extends Super{
    public String str = "Sub";
    public void method() { System.out.println("Sub"); }
}
public class Hoge {
     public static void main(String[] args) {
          Super obj = new Sub();
          obj.method();    //Sub
          System.out.println(obj.str);    //Super     
    }
}
  • じゃあ例外宣言が親と子で違った場合はどーなるの???→左辺
class Super {
    void foo() throws Exception { throw new Exception(); }
}
class Sub extends Super {
     void foo() { System.out.println("Sub"); }
}
public class Hoge2 {
     public static void main(String[] args) {
          Super obj = new Sub();
          obj.foo();    //コンパイラはSuperのfooメソッドをチェックしちゃう→例外処理必要なのでコンパイルエラー
     }
}
インナークラス
  • staticでないインナークラスはアウタークラスのメンバ扱い→アウタークラスのインスタンス化が必要(Outer.Inner in = new Outer().new Inner();)
  • staticなインナークラスはそんなことない
インクリメントしたら参照はどうなるのか

下の例だと、x++のときにオートボクシングでint型でインクリメントされて、Integer x = new Integer(401);と入っている感じじゃないかなと思ってる
結果的に違う参照が入っていることに注目

public class Piyo {
     public static void main(String[] args) {
          Integer x = 400;
          Integer y = x;
          x++;

          StringBuilder sb1 = new StringBuilder("hoge");
          StringBuilder sb2 = sb1;
          sb1.append("fuga");

          System.out.println(x==y);   //false
          System.out.println(sb1==sb2);   //true
     }
}
Javaのキーワードを変数名に使いたいんだけどそんなことって出来るの?
  • Javaで最初から導入されているキーワードは出来ないけど、途中から導入されたものは可能
  • 例えば、assertはJDK1.4から導入されたので、
javac -source 1.3 Hoge.java

とかやるとassertという名の変数を作ってもコンパイルが成功する

abstractなクラスでもコンストラクタは呼べる
  • newは出来ないけどな!!
  • ちゃんと子クラスから呼べます
mainメソッドの作法

これはOK

public class Piyo2 {
    public void main(String...orz) {
        System.out.println(orz[0]);
   }
}

こっちはコンパイルが通る(!)が実行時例外発生(mainメソッドが無いと言われる)

public class Piyo3 {
    public void main(String[]...orz) {
        System.out.println(orz[0]);
   }
}
多重継承

インターフェースの継承はextendsを使うから、implementsみたいに並べてたくさん書けるという話

interface A {}
interface B {}
interface C {}
interface D {}
interface E {}
interface F {}
interface GreatSuperInterface extends A,B,C,D,E,F {

}