ラベル Java の投稿を表示しています。 すべての投稿を表示
ラベル Java の投稿を表示しています。 すべての投稿を表示

2012年1月8日日曜日

JavaのComparableの使い方

前回はComparatorを用いたソートを行ったが、今回はComparableインタフェースを用いたソートを実装してみた。

例題として、絶対値の小さい順にソートするということを考える。もし、絶対値が同じ値が複数現れた場合は、先に現れた方を先に配置するようにする。

import java.util.Arrays;

class comparableTest{
 public static void main(String[] args){
  sortByAbs[] data = new sortByAbs[5];
  data[0] = new sortByAbs(3);
  data[1] = new sortByAbs(-3);
  data[2] = new sortByAbs(0);
  data[3] = new sortByAbs(-10);
  data[4] = new sortByAbs(5);
  Arrays.sort(data);
  for( int i=0 ; i<data.length ; i++ ){
   System.out.println(data[i].val);
  }
 }
}

class sortByAbs implements Comparable<sortByAbs>{
 int val;
 public sortByAbs(int val) {
  // TODO 自動生成されたコンストラクター・スタブ
  this.val = val;
 }
 @Override
 public int compareTo(sortByAbs o) {
  // TODO 自動生成されたメソッド・スタブ
  return Math.abs(val)-Math.abs(o.val);
 }
}

このコードを実行すると次の結果が得られる。0に近い順にソートされていることが分かる。

0
3
-3
5
-10

注目すべき点としては、Arrays.sort()に第2引数は不要であるということである。sortByAbs型のソート方法はcompareToメソッドで既に分かっているからである。Comparatorと比較すると、Comparatorはオブジェクトに対し複数のソート方法を用意できるが、Comparableは1種類しか用意できないという違いがある。

また、当初分からないコンパイルエラーのメッセージがあった。上記のコードは既にエラーを取り除いた結果であるが、記録を兼ねて残しておく。

sortByAbs cannot be cast to java.lang.Integer comparable

このコードはComparableの後にintで比較するからということで<Integer>をつけていたのが原因だった。どのような型のオブジェクトを比較するのかを書く必要があり、<sortByAbs>とするのが正しい。

2012年1月7日土曜日

JavaのComparatorの使い方

今までTopCoderで利用してきたソートにArrays.sort(配列)というメソッドがあるのだが、実は第2引数を取ることができる。第2引数ではソートの手法を示すメソッドを含むオブジェクトを渡すことになる。C言語のqsort関数と同様の仕組みがJavaにもあるということである。

サンプルとして、短い文字列から長い文字列になるようなソートを行うことにした。長さが同じものについては、文字の大小の区別をなくした上で、辞書順に並ぶようにする。

まず、比較のメソッドを含むオブジェクトに関するクラスをCompTest.javaに書いた。

import java.util.Comparator;

// 次行のStringは比較する2要素の型を示している。
public class CompTest implements Comparator<String>{ 
 @Override // オーバーライドしている場合につける注釈
 // 関数名のcompareは決まりごとである。
 public int compare(String s1, String s2 ){
  // s1がs2より先に来るなら、s1の特徴量がs2のそれより小さくなるような関数を作成する。
  if( s1.length() > s2.length() ){
   return 1;
  }else if( s1.length() < s2.length() ){ // s1の方がs2より短い文字列になっている場合
   return -1;
  }else{
   return s1.compareToIgnoreCase(s2);
  }
 }

}

テスト用のmain関数を含むクラスがあるファイルはtest.javaとした。

import java.util.Arrays;

public class test {
 public static void main(String args[]){

  String[] lang = {"Java","Lisp","Haskell","C","Go"};
  Arrays.sort(lang, new CompTest() ); // 配列のソートの第2引数にCompTestを渡す
  for( int i=0 ; i<lang.length ; i++ ){
   System.out.println(i + ":" + lang[i]);
  }

 }
}

ソートした結果は次の通りである。

0:C
1:Go
2:Java
3:Lisp
4:Haskell

2011年9月19日月曜日

Javaのthreadの呼び出し方2

複数のスレッドが動いているときに、1つのスレッドがある変数Aをいじっている最中に、スレッドが切り替わって別のスレッドからAを書き換えるようなことが起きると不便なことがある。勝手にスレッドは動作するため、スレッドを制御する方法としてsynchronizedという修飾子を用いた、排他制御の仕組みが用意されている。排他制御はその名の通り、スレッドが実行している間、synchronized修飾子がかかっている箇所にロックをかけて、他のスレッドはロックがかかっているうちはアクセスができないようにすることである。

以下の例では、複数のスレッドが、計算を繰り返し、その結果をBadのvalueに記録するというものである。スレッド1が1を足して、スレッド1が抜ける前にスレッド2が1を足すということになると、エラーで停止してしまう。排他制御を行わないと、スレッド1がadderを実行している最中に、スレッド2がadderを実行してしまうのである。

BadTest.javaの中身

public class BadTest extends Thread{
 Bad test;
 public BadTest(Bad bd){
  this.test = bd;
 }
 public void run(){
  for( int i=0 ; i<10 ; i++ ){
   test.adder(1);
  }
 }
 public static void main(String[] args){
  Bad bd = new Bad();
  new BadTest(bd).start();
  new BadTest(bd).start();
 }
}

Bad.javaの中身

public class Bad{
 private int value = 0;
 public void adder(int v){
  int tmpValue = value;
  System.out.println(Thread.currentThread() + " is at adder");
  value += v;
  if( tmpValue + v != value ){ // 単純に足しただけだが...
   System.out.println(Thread.currentThread() + " conflicted!");
   System.exit(-1); // 異常終了
  }
  System.out.println(Thread.currentThread() + " get out of adder");
 }
}

上のコードをコンパイルして実行すると次のようになり、矛盾が発生していることが分かる。

d:\java>javac BadTest.java Bad.java // ファイルをまたいでいるので、まとめてコンパイル
javac BadTest.java Bad.java

d:\java>java BadTest
java BadTest
Thread[Thread-0,5,main] is at adder
Thread[Thread-1,5,main] is at adder
Thread[Thread-0,5,main] get out of adder
Thread[Thread-1,5,main] conflicted! // ここで矛盾
Thread[Thread-0,5,main] is at adder
Thread[Thread-0,5,main] get out of adder

この矛盾を解決するのがsynchronized修飾子である。synchronizedは以下のようにadder関数に修飾するとよい。

public synchronized void adder(int v)

これによって、一つのスレッドがadder関数を実行している間、同じインスタンスを利用する別スレッドからはadder関数が利用できなくなり、矛盾(=conflicted!の表示)は発生しなくなる。また、synchronized修飾子はメソッドにもブロックにもかけられる。ブロックにsynchronized修飾子をつける場合は、ロックをかけるオブジェクトを指定する必要がある。

public void adder(int v){
 synchronized(this){
  ...
 }
}

2011年9月14日水曜日

Javaのthreadの呼び出し方1

Javaのスレッドの基本的な呼び出し方法についてのまとめ。スレッドというのは複数の動作を平行して行うようにするための仕組みである。呼び出し方は大きく2種類ある。

  1. Threadクラスの拡張
  2. Runnableインタフェースの実装

スレッドというのは、特に指定がないと実行されるタイミングを制御することはできない(synchronizedなどを付けない限り)。例えば、Threadクラスを拡張して作成した次のスレッドを含むプログラムを実行すると、mainと書かれた行とrunと書かれた行はランダムに現れることが確認できる。runとmainが交互に現れることや、runが先に10行現れてmainが10行現れるといったことには必ずしもならない。

class countTen1 extends Thread{
 public static void main(String[] args){
  countTen1 ct = new countTen1(); // スレッドを実行するインスタンスを作成
  ct.start(); // スレッドの実行開始
  for( int i=0 ; i<10 ; i++ ){
   System.out.println("main i = " + i);
  }
 }
 public void run(){
  for( int i=0 ; i<10 ; i++ ){
   System.out.println("run i = " + i);
  }
 }
}

参考までに、手持ちの環境で実行した結果の例は次の通り。最後にmainとrunが連続で発生しており、規則性がないということが分かる。

d:\java>java countTen1
java countTen1
main i = 0
run i = 0
main i = 1
run i = 1
main i = 2
run i = 2
main i = 3
run i = 3
main i = 4
run i = 4
main i = 5
run i = 5
main i = 6
run i = 6
main i = 7
run i = 7
main i = 8
main i = 9
run i = 8
run i = 9

スレッドの実行はスレッドクラスのインスタンスが持つstartメソッドで開始する。また、スレッドの実行内容はrunメソッドに記述する。このとき、呼び出し方は必ずpublic void run()になる。

次にRunnableインタフェースを実装するスレッドの作成方法を示す。上のスレッドを拡張した場合と同じように動作するプログラムである。

class countTen2 implements Runnable{
 public static void main(String[] args){
  countTen2 ct = new countTen2();
  // スレッドインスタンスの生成時にRunnableを実装したインスタンスを渡す
  Thread t = new Thread(ct);
  t.start(); // スレッドの実行開始
  for( int i=0 ; i<10 ; i++ ){
   System.out.println("main i = " + i);
  }
 }
 public void run(){
  for( int i=0 ; i<10 ; i++ ){
   System.out.println("run i = " + i);
  }
 }
}

特徴は、Runnableインタフェースを実装したクラスはスレッドクラスではないので、スレッドクラスのインスタンスを作成するときに引数にクラスを入れてしまうということである。

2種類のスレッドの呼び出し方の使い分け方は、クラスの拡張を繰り返して作成された下の階層に属するようなクラスはRunnableを利用し、手軽にスレッドを利用したいのであれば、Threadを拡張して利用するということになる。

2011年9月4日日曜日

Javaの私的まとめ18

Javaのお勉強その18

  1. NavigableSetとTreeSet

    TreeSetはNavigableSetを実装したものである。TreeSetに格納されるデータは自然順序付けによってソートされている。順序付けのないものにはComparableを実装するか、Comparatorを渡して順序付ける。

  2. NavigableMapとTreeMap

    TreeMapはNavigableMapを実装したものである。TreeMapに格納されるデータは自然順序付けによってソートされている。順序付けのないものにはComparableを実装するか、Comparatorを渡して順序付ける。

  3. ジェネリックス

    以下のコードはすべてコンパイルはできる。

    ArrayList a1 = new ArrayList();
    ArrayList a2 = new ArrayList();
    ArrayList a3 = new ArrayList();
    ArrayList a4 = new ArrayList();
    

    a1は古い書き方、リストに入れるときの型に注意が必要。a2は現在のJavaの書き方。安全。a3は型が定まらないので、String str = (String)a3.get(0);のようなキャストが必要になる。getで戻す型はObjectである。a4はStringとそのサブクラスしか入れられない。

    関数の引数にリストを渡す場合、int method(List list){ ... }のような書き方がある。

    class Super{ ... }
    class Sub extends Super { ... }

    に対して、以下のようにすると、a1にはSuper、Subのどちらのオブジェクトも格納できる。

    ArrayList<super> a1 = new ArrayList<super>;
    Super[] a1 = new Sub[10]; // エラーにならない
    ArrayList<super> a1 = new ArrayList<sub>(); // エラーになる
    // Superかそのサブクラスのコレクションを参照する変数
    // 要素の追加ができない
    ArrayList<? extends Super> a2 = new AraryList<sub>(); // OK
    // Subかそのスーパークラスのコレクションを参照する変数
    // 要素の追加はできる
    ArrayList<? super Sub> a3 = new ArrayList<super>(); // OK
    

Javaの私的まとめ17

Javaのお勉強その17

  1. コンパレータ

    コレクションや配列を自分が決めた順序でソートしたい場合には、Comparatorを実装するクラスを書く。C言語で言うところのqsort関数に渡す関数ポインタみたいなもの。コンパレータは次の形式である。

    public int compare(値1,値2)

    値1が値2より小さい場合は負、等しい場合は0、値1が値2より大きい場合は正の整数を戻すように定義する。

    自分で順序を決めたいものの型をXとするとき、コンパレータは次のようになる。

    class MyComparator implements Comparetor{
     public int compare(X x1, X x2){
      return (x1,x2の比較結果);
     }
    }

    例えば、数値を絶対値の小さい順に並べるコンパレータは次のようになる。このようなコンパレータをArrays.sortの引数や、Collections.sortの引数に与えることで、自分の基準でソートができる。

    class MyComparator implements Comparetor{
     public int compare(Integer x1, Integer x2){
      return Math.abs(x1)-Math.abs(x2);
     }
    }
  2. java.util.comparable

    Comparatorとの違いは、自分自身と引数に与えられた値を比較するという点である。次のような形をしており、引数は1つだけになる。

    public int compareTo(値)

    Xというクラスに自分で定義した順序を与える場合、次のように書く。

    class X implements Comparable{
     public int compareTo(X x1){
      return (自身とx1との比較結果);
     }
    }

    Comparableを実装しているクラスにはラッパークラス、String、DateCalenderなどがある。

    Comparableでは1つのクラスに1つの順序しか与えられないが、Comparatorでは、比較するクラスから独立しており、必要なだけ順序付けを定義することができる。

    Comparableを実装した場合、Arrays.sortなどの第2引数の指定は必要なくなる。

  3. 反復子

    コレクションの要素の繰り返しを扱うためのインタフェース。IteratorやIteratorを実装したクラス、オブジェクトを反復子という。List、Setにはiterator()というIteratorを返すメソッドがある。

    Listの主なメソッド
    boolean hasext() さらに要素がある場合にtrueを返す
    next() 反復子が指している要素を返し、反復子に次の要素を指すようにさせる。
    void remove() 反復子によって最後に返された要素を削除する

    反復子のサンプルプログラム。要素がそのままの順で1行につき1単語ずつ出力される。

    import java.util.*;
    class ite{
     public static void main(String[] args){
      List list = Arrays.asList("This","is","a","pen");
      Iterator it = list.iterator(); // 反復子の設定
      while(it.hasNext()){ // リストに次の要素があるうちは
       System.out.println(it.next()); // 注目している値を表示して、次を指すようにせよ。
      }
     }
    }
  4. Hash関連

    HashMap、Hashtableでは、ハッシュと呼ばれる、値を識別キーに対応させる方法を使う。検索の高速化が目的である。

    キーはObjectのメソッドであるequalsとhashCodeを使う。hashCodeはハッシュコードというint型の値を返すメソッドである。これらを正しく実装しないクラスのオブジェクトはHashtableなどのキーにすることはできない。

    hashCodeはequalsで等しいとされるオブジェクトは同じハッシュコードを戻すようにしなければならない。等しくない場合は任意であるが、異なるハッシュコードにする方が検索等が速くなる。

    import java.util.*;
    class A{
        int weight;
        A(int w){ weight = w; }
        public boolean equals(Object obj){
    	if( (obj instanceof A) && weight == ((A)obj).weight ){
    	    return true;
    	}else{
    	    return false;
    	}
        }
        public int hashCode(){
    	return weight % 10;
        }
    }
    
    class hashtest{
        public static void main(String[] args){
    	Hashtable ht =
    	    new Hashtable();
    	ht.put(new A(3),"hello");
    	ht.put(new A(5),"world");
    	System.out.println(ht.get(new A(5)));
    	System.out.println(ht.get(new A(2)));
        }
    }

    実行結果は次の通り。2に対応するオブジェクトがないので、nullが返ってくる。

    world
    null

Javaの私的まとめ16

Javaのお勉強その16

  1. コレクション

    コレクションクラスのオブジェクトの作成方法は次の通り。昔は<Integer>は不要であったが、今は型を明示するのが一般的。

    ArrayList<Integer> list = new ArrayList<Integer>;
    Listの主なメソッド
    add(値) 値を要素に追加
    add(インデックス,値) リストの指定したインデックスの位置に値を追加
    contains(値) 値がリスト中にあればtrueが返される
    get(インデックス) リストのインデックスの位置にある値を返す
    indexOf(値) 指定した値がある位置を返す(一番最初に現れるものに限られるが)
    remove(インデックス) 指定したインデックスを削除
    remove(値) 指定した値を持つ要素を削除(先頭のみ)
    toArray() リストの全要素を格納する配列を返す(Object[]型で)
    iterator() イレテータを返す
    Mapの主なメソッド
    containsKey(値) Map中にキーがあればtrue
    containsValue(値) Map中に値があればtrue
    get(キー) キーで指定される値を戻す
    put(キー、値) Mapの要素を追加
    remove(キー) キーで指定される要素を破棄
    Set keySet() マップに格納されているキーの一覧を得る
    Setの主なメソッド
    add(値) 値をSetの要素に追加
    contains(値) Set中に値があればtrue
    remove(値) 指定した値を持つ要素を削除
    toArray() すべての値を持つ配列を返す(Object[]型で)
    iterator() イテレータを作成する
    Set keySet() マップに格納されているキーの一覧を得る
    List、Map、Hashの共通メソッド
    clear() 全要素の削除
    isEmpty() 要素が空の場合にtrueを返す
    size() 要素数を返す
    Queueの主なメソッド
    add(値) 値をキューに入れる
    offer(値) 値をキューに入れる。addとの違いはaddは入れられない場合に例外を投げるのに対し、offerはfalseを返すだけである。
    peek() キューの先頭の値を返す。キューが空だとnullが返される。
    poll() キューの先頭の値を返し、先頭の要素を削除する。キューが空だとnullが返される。
  2. CollectionsとArrays
    Collectionsの主なメソッド(全部staticメソッドである)
    binarySearch(リスト,値) リストを2分探索し、値のインデックスを返す
    binarySearch(リスト,値,コンパレータ) リストを2分探索し、値のインデックスを返す。要素の比較はコンパレータに従う。
    reverse() リストを反転させる
    shuffle() リストをランダムに並び変える
    sort(リスト) リストを型にとって自然な順序で昇順にソート、文字列なら辞書順、数値は昇順。
    sort(リスト,コンパレータ) リストをコンパレータに従ってソート
    emptyList()、emptyMap()、emptyHash() 空のリスト、マップ、ハッシュの生成

    java.util.Arraysは配列を扱うためのstaticメソッドを持っている。

    Ararysの主なメソッド
    asList(要素の型... a) リストを生成する。aは可変長引数リストや配列を想定している。
    binarySearch(配列,値) 配列を2分探索し、値の見つかった位置を返す。
    binarySearch(配列,値,コンパレータ) 配列をコンパレータに従って二分探索し、値の見つかった位置を返す。
    equals(配列1、配列2) 二つの配列のデータが一致するとtrueが返される。
    sort(配列) 配列を昇順でソート。
    sort(配列、コンパレータ) 配列をコンパレータに従ってソート。
    toString() 配列の内容の文字列表現を返す。

    ここまでの二分探索メソッドで見つけようとした値がコレクションの中にない場合は負数が返される(-1とも限らない)


Javaの私的まとめ15

Javaのお勉強その15

  1. シリアライズ・デシリアライズ

    オブジェクトのデータを書き込み、読み込みすることをそれぞれシリアライズ、デシリアライズという。

    シリアライズできるクラスはインタフェースSerializeableを実装したものである。インタフェースはメンバを持たないので、特別な実装は不要。

    aというファイルにあるクラスAAのオブジェクトAを書き込む方法はつぎのようになる。

    FileOutputStream fos = new FileOutputStream("a");
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    oos.writeObject(A);
    oos.close();
    

    逆にファイルを読み込む方法は次のようになる。aというファイルからオブジェクトを読み込む。

    FileInputStream fis = new FileInputStream("a");
    ObjectInputStream ois = new ObjectInputtStream(fis);
    AA aa = (AA)ois.readObject(); // Object型で読み込まれるのでキャストする
    ois.close();

    transientなフィールド、staticなフィールドはシリアライズされない。

    DataInputStreamのreadInt、DataOutputStreamのwriteIntなどでも特定の型のデータの読み書きができる。

    スーパークラスがSelializableを実装している場合、そのサブクラスもSelializableを実装していることになる。サブクラスのオブジェクトのシリアライズ・デシリアライズはスーパークラスの部分も対象とする。

    スーパークラスがSerializeを実装していない場合、サブクラスのシリアライズ・デシリアライズではスーパークラスのシリアライズ・デシリアライズは行われない。オブジェクトのスーパークラス部分はスーパークラスの引数を取らないコンストラクタで初期化される。

  2. コンソール

    コンソールはGUIを使わない入出力を簡単・安全にする。次のようにするとConsoleオブジェクトが得られる。

    Console c = system.console();
    printfの書式(フラグ)
    String readLine() キーボードから1行テキストを読みこむ
    String readLine(String format,Object...args) 書式設定したうえで1行読み込む
    char[] readPassword エコーを無効にしたコンソールから1行テキストを読み込む
    char[] readPassword(String fmt,Object ...args) 書式設定したうえで、エコーを無効にしたコンソールから1行テキストを読み込む
    Console format(String fmt,Object... args) 書式付文字列をコンソールに書き込む
    void flush() コンソールをフラッシュして出力を直ちに書き込む
  3. コレクション

    コレクションとは、複数のオブジェクトを格納しておくクラス、インタフェースのことである。java.utilパッケージに属する。

    主なインタフェースの種類
    Collection コレクションのルート。順序も重複も規定されていない
    List 順序づけられたコレクション。任意の位置に対する要素の挿入・削除が速い
    Map キーとデータを対応させたコレクション。キーはユニークになる。
    Set 重複のないコレクション、数学の集合に相当。
    Queue キュー(FIFO)
    主なコレクションクラス
    ArrayList 要素を変えられる配列のようなもの。スレッドセーフでないがVectorより高速。(Listの実装)
    Vector 要素を変えられる配列のようなもの。スレッドセーフ。(Listの実装)
    HashMap ハッシュを使ったマップ。nullが利用できる。(Mapの実装)
    Hashtable ハッシュを使ったマップでnullが使えない。スレッドセーフ。(Mapの実装)
    HashSet ハッシュを使ったセット(Setの実装)

2011年9月2日金曜日

Javaの私的まとめ14

Javaのお勉強その14

  1. 表示
    String a = "small";
    String A = "large";
    System.out.printf("a = %2$s, A = %1$s",A,a);
    とすると、a = small, A = largeと表示される。番号$は省略できるが、その場合は埋め込む文字の順序は変更できない。後ろにつけたものから順に埋められる。

    printfの書式をいくつか示す。

    printfの書式(フラグ)
    - 左揃えにする
    + 符号をつける
    0 空きを0で埋める
    , コンマ区切りを使う
    ( 負の値をかっこで囲む
  2. File

    java.io.Fileはファイルやディレクトリ(!)を表すクラスである。

    Fileオブジェクトはいくつかのコンストラクタを持つ。

    File(String name)
    File(String dir, String name)
    File(File dir, String name)

    Fileオブジェクトを生成してもファイルはすぐに作成できない。createNewFile()でファイルを作成する。ただし、ファイルが生成できない場合はjava.io.IOExceptionがスローされる。

  3. ReaderとWriter

    java.io.Readerとjava.io.Writerは文字の入出力に使うためのクラスである。

    FileReader/Writerはファイルの入出力に使う。

    BufferedReader/Writerはバッファを使い、効率よく入出力を行う。BufferedReader/WriterはReader、Writer(入出力のためのクラス)から生成できる。

    Print.Writerは文字・文字列の入出力に使う。System.outのクラスである。File、Writer、Stringなどから生成できる。

    Reader、Writerのメソッド(失敗時にIOExceptionが投げられる)
    int read() 文字を1文字読みだして戻す
    void write(char c) cを書き込む
    void write(String s) sを書き込む
    void flush() フラッシュする
    void close() 閉じる
    閉じる

    BufferedReaderはString readLine()という文字列を1行読み込んで返すメソッドを持っている。

    BufferedWriterはvoid newLine()という文字列を1行書き込むメソッドを持っている。

    import java.io.*;
    class file{
     // IOExceptionを投げると書かないとコンパイルエラーになるよ。
     // readLineメソッドなどは例外を投げる可能性があるので。
     public static void main(String[] args)throws IOException{
      File f = new File("test.txt");
      PrintWriter pw = new PrintWriter(f);
      pw.write('x'); // 書き込み
      pw.println("hello"); // これも書き込み
      pw.flush();
      pw.close();
      // ReaderからBufferedReaderを生成する。
      BufferedReader br = new BufferedReader(new FileReader(f));
      System.out.println(br.readLine());
     }
    }

2011年8月31日水曜日

Javaの私的まとめ13

Javaのお勉強その13

  1. クラス2

    メソッド内でクラスとオブジェクトの生成を同時に行う。以下の例ではインタフェースをmain内で実装し、オブジェクトを作成している。引数にnewを渡して関数を呼ぶことも無名クラスを利用したことになる。

    interface IF{
     void method();
    }
    
    class mumei{
     public static void main(String[] args){
      IF ifobj = new IF(){
       public void method(){
        System.out.println("Hello,java");
       }
      };
      ifobj.method();
     }
    }
    結果は次の通り。
    Hello,java
  2. Scanner

    java.util.Scannerは入力の読み込みに使われる。

    Scanner sc = new Scanner(入力ファイルパスor入力ストリームor文字列オブジェクト)

    標準入力からの読み込みを行う場合はScannerの引数にSystem.inを与える。

    Scannerには区切りを表す文字(","などのStringまたはPattern)を引数に取り、その結果をScannerに戻すメソッドuseDelimiterというメソッドがある。

    Scannerの検索メソッド
    String findInLine(Pattern p) pで指定されるパターンを検索し、見つけたものを戻す。なければnullを戻す
    String findInLine(Pattern p) pで指定される文字列を検索し、見つけたものを戻す。なければnullを戻す
    boolean hasNext(Pattern p) 次に読み込むべきものがpで指定されるパターンであればtrueを戻す。
    String next(Pattern p) pで指定されるパターンに一致するものを読み込んで戻す。
  3. 正規表現

    正規表現を使うときにはjava.util.regex.*(PatternとMatcher)をimportする必要がある。

    パターンは文字列検索に用いることができる。Patternオブジェクトの作成は次の形式で作成される。Matcherオブジェクトはpで指定した正規表現を検索するためのオブジェクトである。

    Pattern p = Pattern.complile("ABA");
    Matcher m = p.matcher("abcABABAdABA")
    Matcherクラスのメソッドの代表例
    boolean find() 正規表現に一致したものがあればtrueを返す。
    int start() 見つかったパターンの先頭インデックスを返す。
    String group() 見つかったパターンに該当した文字列を返す。
    正規表現の例
    .任意の文字
    \d数字
    \s空白文字
    c?cが1or0回
    \wアルファベット、数字、アンダーバーのいずれか
    c*cが0回以上
    c+cが1回以上

    ScannerクラスのfindInLineによりパターンの検索ができる。

    StringにはString[] split(String s)というメソッドがある。sには正規表現を指定することもできる。

2011年8月26日金曜日

Javaの私的まとめ12

Javaのお勉強その12

  1. 基本パッケージその1

    java.lang.*はJavaの基本的なパッケージであり、このパッケージのクラスを用いるときには、java.langを付ける必要はない。

    すべてのクラスのスーパークラスがObjectになる。

    Objectのequalsは==と同じだが、サブクラスでは異なることがある。例えばStringのequalsはオブジェクトの内容を比較するようになっている。

  2. String

    Stringは変更不可な文字列を表すクラスである。

    同じ文字列のリテラルは、同じオブジェクトが割り当てられる。以下のs1、s2は同じオブジェクトが割り当てられ、s1==s2であり、s1.equals(s2)==trueでもある。

    String s1 = "abc";
    String s2 = "abc";

    StringBuffer、StringBuilderはStringとは違い、変更可能な文字列を扱うクラスである。

    StringBufferとStringBuilderはスレッドセーフか否かという違いのみである。単一スレッドのプログラムであれば、StringBuilderが推奨されている。

    StringBuilderのコンストラクタは次の3種類がある(StringBufferでも同様)。

    StringBuilder(); // 空のオブジェクト生成
    StringBuilder(int num); // バッファサイズがnumの空のオブジェクトを生成
    StringBuilder(String str); // sという文字列を持つオブジェクトを生成

    StringBuilderの役に立つメソッド

    insert(int pos,X s); // posにsを入れる。Xは基本データ型やString、Objectが入れられる。
    delete(int start,int end); // インデックスがstartからend-1までの箇所を削除
    setCharAt(int pos,char c); // posの場所の内容をcで置き換える
    // 文字列の長さをlenにする。lenが現在の文字列長よりも小さいと切り捨て、
    // 長い場合は'\u0000'を後ろに埋める。
    setLength(int len);

    StringBuilder、StringBufferは==とequalsは同じ働きをする。

  3. ラッパークラス

    基本データ型にはラッパークラスが定義されており、値は変更できない。boolean以外のラッパークラスは、Numberという抽象クラスのサブクラスになる。

    ラッパークラスのオブジェクトは、対応する値、変数から生成される。

    Character以外のラッパークラスのオブジェクトは文字列からも生成できる。

    Boolean bl = new Boolean("True"); // 大文字が混じってもOK

    valueOfは値からオブジェクトを生成するのに用いられる。

    Integer i = new Integer.valueOf(1);

    ラッパークラスのtoStringメソッドは保持する値を文字列に変換する。

    ラッパークラスから基本データの値を取り出すのは*Value()というメソッドを用いる。

    char pc = wc.charValue();

    文字列から基本データの値を取り出すにはparse*()というメソッドを用いる。

    double d = Double.parseDouble("1.234");

    Integer、Longクラスにはto{Binary,Octal,Hex}Stringというメソッドがあり、10進数の数値を2進数、8進数、16進数に変換した文字列を得ることができる。

    ラッパークラスの比較はequalsメソッドを用いる。ラッパークラスと基本クラスは比較できる。比較する際に、ボクシング・アンボクシング変換が発生し、比較できるようになる。

    Booleanはif文の条件判定に用いることができる。

    Boolean以外のラッパークラスにはMAX_VALUE、MIN_VALUEというpublic static finalなフィールドがある。基本データの最大、最小の値を示している。

  4. ロケール

    ロケールは言語などで特徴づけられる地域を表す。例えば数値を表すフォーマットは地域によって違うため、ロケールによって処理を変えるといったことをする。java.util.Localeというクラスが用意されている。

    Local ljp = new Locale("ja","JP");

    数値を扱うためにjava.text.NumberFormatというクラスが用意されている。通貨を表すために、Currencyというクラスがある。

    import java.util.*;
    import java.text.*;
    
    class localeTest{
        public static void main(String[] args){
    	Locale lus = new Locale("en","US");
    	NumberFormat nf = NumberFormat.getInstance(lus);
    	System.out.println(nf.format(1000));
    	NumberFormat nfc = NumberFormat.getCurrencyInstance(new Locale("ja","JP"));
    	System.out.println(nfc.getCurrency().toString());
        }
    }

    上のプログラムの出力結果は次のようになる。

    1,000
    JPY

2011年8月21日日曜日

Javaの私的まとめ11

Javaのお勉強その11

  1. スレッドその2

    waitメソッドはスレッドのロックを解放し、通知を受けるまでスレッドを待機状態にする。

    notifyメソッドはロックの解放を通知し、待機状態のスレッドのどれかをロック探索状態(ロック取得を求める状態)にする。

    notifyAllメソッドはすべての待機中のスレッドに通知し、それらをロック探索状態にする。スレッドが多くなるとメソッドの実行時間は大きくなる。

    wait、notify、notifyAllはObjectクラスに属するメソッドである。

    interruptはThreadのメソッドである。そのスレッドがwaitで待機している場合は、それを再開してwaitにInterruptedExceptionをスローさせる。

    holdsLockはObjectを引数に取るThreadのstaticメソッドである。Thread.holdsLock(obj)として、objはロックを取得されていればTrue、そうでなければFalseを返す。

    2スレッドが互いに必要としているオブジェクトをロックするとプログラムが停止する。このことをデッドロックという。

    staticなsynchronizedメソッドはクラスのロックを取得する。

    synchronizedはメソッド全体でも、一部だけにつけることもできる。

  2. クラス1

    クラスの中で定義されるクラスをネストクラスとよび、staticでないネストクラスをインナークラスという。staticでないネストクラスはstaticなメンバや静的初期化子を持つことができない。

    staticでないネストクラスはその側のクラスのオブジェクトを生成してからでないと使えない。

    class Outer{
     class Inner1{ ... }
     static class Inner2{ ... }
    }
    上のようなコードがあったときに、Outerの非staticなメソッドの内部では次のようにする。
    Inner1 inner1 = new Inner1();
    staticなメソッド内では次のようになる。
    Outer outer = new Outer();
    Inner1 inner1 = outer.new Inner1();
    staticなネストクラスの場合はOuterのメソッド内では、
    Inner2 inner2 = new Inner2();
    になる。Outerの外部では次のように呼べる。
    Outer.Inner1 inner1 = new Outer.new Inner1();
    Outer.Inner2 inner2 = new Outer.Inner2();

    メソッドの中でクラスを定義することもできる。ローカルインナークラスと呼ばれ、メソッド内でのみ有効になる。アクセス修飾子は付けられない。

    インナークラスが定義されているメソッド内の変数や引数で、final指定されているものにはローカルインナークラスからアクセスできる。

2011年8月19日金曜日

Javaの私的まとめ10

Javaのお勉強その10

  1. スレッドその1

    1つのプログラム中に複数の処理を同時に走らせることをスレッドという。

    スレッドの作り方は2種類ある。一つはThreadクラスを拡張してrunメソッドを実装する方法

    class myThread extends Thread{ public void run(){ ... }}
    myThread mt = new myThread();mt.start();

    もう一つはRunnableインタフェースを実装するし、runメソッドを実装する方法である。

    class myRunnable implements Runnable{ public void run(){ ... }}
    myRunnable mr = new myRunnable();Thread t = new Thread(mr);t.start();

    runメソッドを実装して、startメソッドでスレッド(中身はrunメソッド)を開始する。

    スレッドには実行中、実行可能、実行不可能、死んでいる(終了状態)の4つの状態がある。

    yieldはThreadのstaticメソッドである。これを実行すると、実行中のメソッドは実行権利を放棄する。実行可能状態のスレッドがほかにあれば、スケジューラにより、それを実行することがある。

    sleepはThreadの実行を一定時間止める役割を持つ。これもThreadのstaticメソッドである(呼ぶときはThread.sleep(1000)などと記述する)。

    joinはThreadの非staticなメソッドで、他のスレッドと同期をとるために、スレッドの終了を待つメソッドである。

    JavaのI/Oメソッドは、時間がかかるとスレッドを実行不可能なブロック状態にし、他のスレッドに実行権利を譲る。状況が変化すると、実行可能状態に遷移する。

    複数のスレッドを制御する共有オブジェクトをモニターという。スレッドの実行順序は不定なので、あるスレッドがもにーたにアクセスしている間に別のスレッドがそれを書き換えて矛盾が起きる可能性がある。

    synchronizedメソッドを利用すると、あるスレッドがメソッドを呼び出している間、他のスレッドはそのメソッドを利用できなくなる。

2011年8月17日水曜日

Javaの私的まとめ9

Javaのお勉強その9

  1. アサーション

    プログラマーがプログラム実行時に常に真にならないとassertする条件式を書き、実行時に条件が満たされているかチェックする仕組みのこと

    アサート文は次の形式になっている。

    assert 式1;
    assert 式1:式2;

    式1はチェックする条件式、1行目ではfalseだとAssetionErrorがスローされる。2行目では式2がAssertionErrorがスローされるだけでなく、式2のメッセージが表示される。式2は値を持たせる必要がある。

    assertを使うと、評価を行う分だけ、実行速度は下がる。

    -source 1.3をつけてコンパイルすると、assert文がコンパイルエラーになる。識別子として使用できるが、警告が表示される。1.4以降の数値をつけてコンパイルするとassertという識別子は利用不可になる。

    assertを利用する場合は、実行時に-eaオプションをつける。次の指定方法がある。

    java -ea Test
    -ea
    -ea:クラス名
    -ea:... (作業ディレクトリの名前のないパッケージ内のassertを有効にする)
    -ea:パッケージ名

    アサーションを無効化する実行オプションは-daである。

    複数の矛盾するオプションを指定した場合は、詳細な設定をした方が優先される。

    assertはエラー処理ではないことに注意。

2011年8月16日火曜日

Javaの私的まとめ8

Javaのお勉強その8

  1. 例外

    配列の添え字が配列の範囲を超えるなどすると、例外が発生する。例外はその場所から「投げられる」という。

    例外を捕捉するにはtry~catch節を用いる。例外が発生する箇所でtry{ }、例外を受け取る場所でcatch(指定した例外){ }と書く。finallyを付けると、例外の発生の有無に関わらず実行される。例えばファイルを閉じるなどの作業をここで行われることがある。

    class exceptionTest{
        static int method(){
    	int[] array = new int[3];
    	try{
    	    array[10] = 5;
    	}catch(ArrayIndexOutOfBoundsException e){
    	    System.out.println(e);
    	    return -1;
    	}finally{
    	    System.out.println("Called finally");
    	}
    	return 0;
        }
        public static void main(String[] args){
    	int x = method();
    	System.out.println(x);
        }
    }
    結果は次のようになる。
    java exceptionTest
    java.lang.ArrayIndexOutOfBoundsException: 10
    Called finally
    -1 // 例外が発生しても、プログラムは最後まで実行される。
    
  2. 例外の種類

    Throwableはスローされるクラスを表す。ThrowableのサブクラスであるErrorは回復不可能なエラーでありキャッチすべきでない状態にある。一方、Throwableのもう一つのサブクラスであるExceptionはさらにRuntimeExceptionと検査例外のサブクラスに分かれる。RuntimeExceptionはコンパイル時にチェックされない。その他の例外はコンパイル時にチェックされる。

    Errorとそのサブクラスもコンパイル時にチェックされない。

    検査例外が発生する場合は、以下のどちらかの方法で処理しなければならない。

    // 1つめの処理方法
    int test(){
     try{
      // 処理1
     }catch(例外){
      // 処理2
     }
    }
    // 2つめの処理方法
    int test() throws 例外{
     // 処理1
    }
    
    2つめの処理方法の場合は、メソッドを呼ぶときに再び、上のどちらかの処理を噛ませる必要がある。

    複数の例外がある場合はtry~catch~catch~finallyのように書く。

    複数の例外が投げられうる候補にある場合、次のように書くことができる。

    int test() throws 例外1, 例外2{
     // 処理
    }

    例外はJVMとプログラムが投げるものの2種類に分けられる。

    オーバーライドされたメソッドのスローする検査例外は、もとのメソッドのスローする例外かそのサブクラスでなければならない。

    RuntimeExceptionとそのサブクラスは検査例外なので自由にスローできる(スーパークラスで何をスローしようともサブクラスでは何をスローしても良い)。また、オーバーライドされたメソッドで例外をスローしなくて良い。

    インタフェースのメソッドもオーバーライドと同様のルールが適用される。

    Exceptionを派生(extends)させることで、独自の例外を定義できる。

2011年8月14日日曜日

Javaの私的まとめ7

Javaのお勉強その7

  1. 型変換

    大きな型へは自動的に変換される。型の大小関係はdouble>float>long>int>short,char>byteになる。

    型が小さくなる方向への型変換は自動的に行われない。ただし、byte、char、shortの変数にint型のリテラルや定数を代入する場合、値が型の扱える値の範囲内であれば、縮小変換が行われる。

    足し算や掛け算を行うと、拡大変換が適用される。例えば、double型+int型の結果はdouble型に変換される。byte、char、shortの演算は計算結果がintになる。

    暗黙的に型変換ができなくても、キャストにより型変換ができることがある。

    参照型の暗黙的な型変換はサブクラスからスーパークラスへの場合、自動的に行われる。

    参照型から基本データ型へのキャストは不可能。

    int i=40000;
    short s = (short)i;
    はコンパイルできるが、shortが扱える範囲を超えた値なので、情報が失われる。iを2進数表示したうち、下位16ビットがsに入り、その結果が表示されることになる。

    参照型データではスーパークラスからサブクラスにキャストすることが可能である。また、サブクラスからスーパークラスへは代入時、暗黙的に変換が行われる。

    スーパークラスからサブクラスへのキャストが許されるのは、スーパークラスの変数がサブクラスのオブジェクトを指しているかもしれないからである。ただし、スーパークラス変数の指すものが実際にスーパークラスのオブジェクトであった場合、サブクラスのオブジェクトとして利用できないので、ClassCastExceptionが投げられる。

2011年8月13日土曜日

Javaの私的まとめ6

Javaのお勉強その6

  1. 抽象クラス

    抽象メソッドを持つクラスを抽象クラスという。抽象メソッドはサブクラスで実装する。

    サブクラスがすべてのメソッドを実装しない場合、そのクラスも抽象クラスになる。

    抽象クラスにはフィールドや抽象でないメソッドを宣言することもできる。

  2. インタフェース

    抽象メソッドと定数のみから構成される。抽象でないメソッドは含められない。

    インタフェースもすべてメソッドを実装しない場合は抽象クラスになる。

    インタフェースのメソッドは自動的にpublicな抽象メソッドになる。

    フィールドは自動的にpublic static finalになる。フィールドは宣言時に初期化する必要がある。

    多重継承に似たことをする場合にはインタフェースを用いる。

    インタフェースを実装するクラスはimplementsを用いる。サブインタフェースを作成する場合はextendsを使う。なお、抽象クラスの実装にはextendsを用いる。

  3. 可変長引数リスト

    int(String ...str)のように...を用いて表す。可変長引数リストは1メソッドに1つだけ許される。

    可変長引数リストは仮引数が複数ある場合は、一番最後に書かなければならない。

    int m(int a,int b)とint m(char ...c)があり、m('A','B')が入力されると可変長引数リストは優先順位が低いため、前者の呼び出し方が利用される。

2011年8月10日水曜日

Javaの私的まとめ5

Javaのお勉強その5

  1. フィールド

    static宣言されたフィールドはクラス変数であり、オブジェクトを生成せずに利用できる。staticがついていないフィールドはオブジェクトに付随する。

    クラス変数は、インスタンス変数よりも先に初期化される。初期値を指定しないと、デフォルトの初期値が与えられる。0(型によっては0.0などになる)やfalseが与えられる。メソッド内の一時変数は初期化されない。

    finalがついたら、コンストラクタが終了するまでに初期化しなければならない。

  2. コンストラクタ

    同じクラスのコンストラクタはthis()で、スーパークラスのコンストラクタはsuper()で呼び出せる。

    クラス定義時にコンストラクタを書かないと、引数なしのコンストラクタがコンパイラによって自動的につけられる。引数をとるコンストラクタを書くと、デフォルトコンストラクタは自動的につかなくなる。引数をとらないコンストラクタが必要なのであれば、プログラマが書く必要がある。

    super()が明示的に呼び出されない場合、最初にsuper()が実行される。したがって、スーパークラスには引数をとらないコンストラクタを書くか、何も書かないでおく必要がある。

  3. メソッド

    インスタンスメソッドを変数.メソッドのように呼び出すと、変数が実際に参照するオブジェクトの型のメソッドが呼び出される。クラスメソッドの場合は、変数の型のメソッドが呼び出される。

  4. オーバーロード

    同じ名前で、仮引数の並びが異なるメソッドを1つのクラス内で宣言すること

  5. オーバーライド

    スーパークラスと同じシグネチャ(メソッド名と仮引数の並び)を持ち、戻り値型が同じ化そのサブタイプであるものを定義すること。

    staticメソッドをオーバーライドして、インスタンスメソッドにすることはできない。

    privateメソッドをオーバーライドするつもりでメソッドを定義しても、サブクラスからは参照できないので、スーパークラスのものとは無関係のメソッドになる。

    final宣言されたメソッドはオーバーライドできない。

2011年8月9日火曜日

Javaの私的まとめ4

Javaのお勉強その4

  1. クラスの書き方

    クラスの修飾子はpublic、abstract、finalの3種類ある

    クラスの書き方は次の通り。5種類あるが、すべてを使う必要はない。

    public class Car{
     int fuel=50; // フィールド
     {...} // インスタンス初期化子
     static {...} // 静的初期化子
     Car(){...} // コンストラクタ
     void run(){...} // メソッド
    }

    静的初期化子は、クラスがJava Virtual Machineにロードされるときに実行される。

    インスタンス初期化子は、オブジェクトが生成されるときに実行される。

    インスタンスを生成するには、Car mycar = new Car();とする。

  2. 継承

    継承によってクラスの機能を拡張できる。基のクラスをスーパークラス、継承して作るクラスをサブクラスという。インタフェースも継承により拡張可能である。

    拡張するにはextendsというキーワードを用いる。以下の例ではCarクラスを継承してpatrolCarクラスを作成している。

    public class patrolCar extends Car{
     // コンストラクタやメソッドを記述
    }
    

    サブクラスでスーパークラスにあるフィールドやメソッドを宣言できる。サブクラスでその名前を使うと、サブクラスで定義されたものになる。スーパークラスのものにアクセスしたい場合は、"super."を付ければよい。

    サブクラスでスーパークラスにあるアクセス可能なメソッドを再定義することをオーバーライドという。

    オブジェクトを参照する変数に対し、変数.フィールドとすると、変数の型のフィールドを意味する。staticがついていないメソッドの場合、変数.メソッドは変数の型ではなく、オブジェクトの型のメソッドが呼ばれる。

  3. final

    finalのついた変数は、1回だけ値を与えることができる。以後変更はできない。クラスや配列でも同様。他のオブジェクトを指すようにする変更はできない。ただし、オブジェクトのデータを変更することは可能である。

    staticのついていないフィールドは、定義の場所で初期化する以外にコンストラクタや、インスタンス初期化子{...}で初期化する方法がある。staticのついたメソッドは、静的初期化子( static {...} )で初期化することもできる。

    finalのついたメソッドのオーバーライドは不可能である。

    finalのついたクラスのサブクラスは作成不可能である。

2011年7月24日日曜日

Javaの私的まとめ3

Javaのお勉強その3

  1. データ型

    基本データ型と、参照型の2種類がある。

    参照型はクラス、インタフェース、配列変数であり、それ以外(int型など)は基本データ型になる。

    String型(参照型)は特殊で、いったん生成すると、内部状態を変更することはできない。以下のようにしても、s2の値自体はabcのままである。

    String s1 = "abc";
    String s2 = s1;
    s1 = "cba";
  2. 配列

    C言語とは異なり、定義する際に左辺に要素数を書くことはない。

    int[] array = new int[5]; // 0で全部初期化される
    int[] array = {1,2,3}; // 要素数3で、内容を1,2,3で初期化
    int array[] = {1,3,4}; // []は後ろに書いてもよい
    int[][] array2d = new int[3][5]; // 2次元配列の定義
    int[][] array2d = {{1,2,3},{4,5},{6,7,8,9,10}}; // 各配列の中身は要素数は一定でなくても良い

    初期化する際に、整数や実数変数は0、boolean型変数はfalse、参照型変数はnullで初期化される。

    整数型配列は参照型であるが、配列の要素自体は基本データ型になる。

    参照型の配列は

    myClass[] myclass = new myClass[5];
    としただけでは、配列オブジェクトが生成されるだけで、各要素はnullのままである。myclass[0] = new myClass();のようにしてから利用可能になる。上で書いたように、変数宣言と、オブジェクトの生成を同時に行うこともできる。
    myClass[] myclass = {new myClass(),new myClass()};
  3. 引数

    メソッドに渡される引数はコピーされるので、呼んだメソッドで値を変更しても、オリジナルの値は変更されない。参照型、基本データ型のどちらの引数でもこの性質は同じ。

    参照型変数は、オブジェクトを指すものであり、コピーされると、同じオブジェクトを指していることになる。したがって、指しているオブジェクトの内容を変更することができる。

    引数にfinalを付けると、その引数はメソッド内でfinalになる。引数が参照型変数であった場合、オブジェクトは変更できないが、オブジェクトの値自体は変更可能である。

  4. ガーベージコレクション

    参照されなくなったオブジェクトは自動的に破棄されるが、このことをガーベージコレクションという。

    System.gc();、Runtime.getRuntime().gc();とすると、ガーベージコレクションを促すことができる。あくまでも促すだけであることに注意。

    Objectクラスにはfinalize()というメソッドが定義されており、このメソッドをオーバーライドすることで、ガーベージコレクションの前に、その内容を実行するようになる。メモリ以外のリソースの回収などに用いられる。

フォロワー

ページビューの合計