FC2ブログ
HOME   »  Java
Category | Java

[Java]byte型数値を符号なし数値として扱う

byte型は8ビットの整数だが、符号付きの為最上位ビットが符号(+/-)を表し、値の範囲は0~255ではなく-128~127となる。

このbyte型の値を符号なしの値(範囲が0~255)として扱いたい場合は、byte型よりもビット数が多いint型等に変換すればよい。
ただし単純に変換すると、符号拡張で負値は負値のままとなってしまうので注意が必要。

例えば、byte型の-1(16進数表示でFF)を単純にint型に変換(int型変数への代入による暗黙の変換)すると、変換後の値も同じく-1のままとなる。
public class Main {
    public static void main(String[] args) {
        byte byteValue = (byte) 0xFF;
        int intValue1 = byteValue;
        System.out.println(String.format("byte型 byteValue (16進数表示):%X", byteValue));
        System.out.println(String.format("byte型 byteValue (10進数表示):%d", byteValue));
        System.out.println(String.format("int型 intValue1 (16進数表示):%X", intValue1));
        System.out.println(String.format("int型 intValue1 (10進数表示):%d", intValue1));
    }
}
上記の実行結果は以下の通り。


byte型 byteValue (16進数表示):FF
byte型 byteValue (10進数表示):-1
int型 intValue1 (16進数表示):FFFFFFFF
int型 intValue1 (10進数表示):-1


int型変数intValue1への代入の際の符号拡張により、上位24ビットが全て符号ビットと同じ値1で埋められ、その結果負値のままとなっている。

この16進数表示でFFとなる値を正値255として扱いたい場合は、int型の値255(32ビットの16進数表示で000000FF)との論理積演算により上位24ビットを全て0にしてやればよい。
public class Main {
    public static void main(String[] args) {
        byte byteValue = (byte) 0xFF;
        int intValue1 = byteValue;
        int intValue2 = byteValue & 0xFF;
        System.out.println(String.format("byte型 byteValue (16進数表示):%X", byteValue));
        System.out.println(String.format("byte型 byteValue (10進数表示):%d", byteValue));
        System.out.println(String.format("int型 intValue1 (16進数表示):%X", intValue1));
        System.out.println(String.format("int型 intValue1 (10進数表示):%d", intValue1));
        System.out.println(String.format("int型 intValue2 (16進数表示):%08X", intValue2));
        System.out.println(String.format("int型 intValue2 (10進数表示):%d", intValue2));
    }
}
上記の実行結果は以下の通り。


byte型 byteValue (16進数表示):FF
byte型 byteValue (10進数表示):-1
int型 intValue1 (16進数表示):FFFFFFFF
int型 intValue1 (10進数表示):-1
int型 intValue2 (16進数表示):000000FF
int型 intValue2 (10進数表示):255


int型の値255との論理積演算を行った結果のintValue2は正値255となっている。


[Java]InputStreamの読み出しデータを格納した配列型変数の状態

InputStreamクラス(を継承したクラス)のreadメソッドの引数として使用し、読み出したデータを格納した後の配列型変数の状態について。

まず、英大文字の"A"、"B"、"C"の3文字を記したテキストファイル(test.txt)を作成し、以下の様にFileInputStreamクラスを使用してこのファイルからデータを読み出す。
public class Main {
    public static void main(String[] args) {
        File file = new File("/*****/test.txt");
        FileInputStream fileInputStream;
        int readDataLength;
        byte[] buffer = new byte[]{0, 1, 2, 3, 4};
        try {
            fileInputStream = new FileInputStream(file);
            readDataLength = fileInputStream.read(buffer);
            fileInputStream.close();
            System.out.println("読み出したデータ数:" + readDataLength);
            System.out.println("配列型変数bufferの要素数:" + buffer.length);
            for (int i = 0; i < buffer.length; i++) {
                System.out.println("buffer[" + i + "]:" + buffer[i]);
            }
        } catch (Exception e) {
        }
    }
}
上記を実行すると、以下の様に読み出したデータ数readDataLength、読み出したデータを格納した配列型変数bufferの要素数buffer.length、配列型変数bufferの各要素の値がコンソールに表示される。


読み出したデータ数:3
配列型変数bufferの要素数:5
buffer[0]:65
buffer[1]:66
buffer[2]:67
buffer[3]:3
buffer[4]:4


上記の結果から、以下の事が分かる。

・読み出したデータは、配列型変数の先頭(インデックス0)から順に読み出したデータ数分だけ格納される。
・配列型変数の要素数は、読み出したデータを格納した後も変化しない(配列型なので当然か)。
・配列型変数の中で読み出したデータが格納されなかった箇所の要素は、読み出し前の値がそのまま保持される。


[Java]スーパークラス型変数へのサブクラスインスタンス代入時の挙動

スーパークラス型の変数にサブクラスのインスタンスを代入した時の挙動について。

以下の様なあるクラス(Superクラス)とそのクラスを継承したクラス(Subクラス)を作成する。

○Superクラス(スーパークラス)
public class Super {
    public Super() {
    }
    
    public void showMessage() {
    	System.out.println("スーパークラスのメソッドが実行されました。");
    }
}
○Subクラス(サブクラス)
public class Sub extends Super {
    public Sub() {
    }

    @Override
    public void showMessage() {
        System.out.println("サブクラスのメソッドが実行されました。");
    }

    public void showMessageOfSub() {
        System.out.println("サブクラス独自のメソッドが実行されました。");
    }
}
そして、以下の様にSuperクラス型変数instanceにSubクラスのインスタンスを代入し、showMessageメソッドを実行するとどうなるか。
public class Main {
    public static void main(String[] args) {
        Super instance = new Sub();
        instance.showMessage();
    }
}
上記を実行すると、コンソールには以下の様にメッセージが表示される。


サブクラスのメソッドが実行されました。


変数instanceはSuperクラス型だが、参照先はSubクラスのインスタンスであり、showMessageメソッドはSubクラスでオーバーライドされている為、Subクラス側のメソッドが実行されることになる。

では、Subクラスでのみ実装されているshowMessageOfSubメソッドはどうか。
public class Main {
    public static void main(String[] args) {
        Super instance = new Sub();
        instance.showMessageOfSub();
    }
}
上記を実行すると、コンパイルエラーとなってしまう。

上述の通り変数instanceはSuperクラス型であり、SuperクラスにはshowMessageOfSubメソッドが存在しない為、実行することができない。

以上の挙動は、メソッドの引数の場合も同様である。

以下の様にSubクラス型変数instanceをtestMethodメソッドの引数として渡してみる。
public class Main {
    public static void main(String[] args) {
        Sub instance = new Sub();
        testMethod(instance);
    }

    public static void testMethod(Super object) {
        object.showMessage();
        //object.showMessageOfSub();
    }
}
上記を実行すると、先の例と同様にコンソールには以下の様にメッセージが表示される。


サブクラスのメソッドが実行されました。


testMethodメソッドの仮引数objectはSuperクラス型、実引数instanceはSubクラス型である為、showMessageメソッドはSubクラス側のメソッドが実行され、showMessageOfSubメソッドは実行することができない(9行目のコメントアウトを解除するとコンパイルエラーとなってしまう)。


[Java]配列やArrayListの要素数の最大値

配列やArrayListには最大いくつの要素を格納できるのか。

配列やArrayListの要素数を取得するlengthメソッドやsizeメソッドの戻り値、あるいは要素の位置を指定するインデックスがintであることから、配列やArrayListの要素数の最大値はintの最大値である

2147483647(2の31乗-1)

となる。

(2011-08-10 追記)
また、インデックスは0から始まるので、インデックスの最大値は

2147483646

となる。


[Java]Singletonパターン

Singletonパターンとはデザインパターンの1つで、あるクラスのインスタンスが1つしか生成されない(できない)ことを確実にするためのデザインパターンである。

Singletonパターンの実装は以下の通り。
public class Hoge {
    private static Hoge instance = new Hoge();

    private Hoge() {
        あれこれ(コンストラクタでの処理)
    }

    public static Hoge getInstance() {
        return instance;
    }

    以降、その他のフィールドやメソッドを実装
}
Singletonパターンのポイントは以下。

・自身のインスタンスをprivate且つstaticなフィールドとして保持する。
・コンストラクタをprivateとし、他クラスから呼び出せないようにする。
・コンストラクタとは別に、自身のインスタンスを返すpublic且つstaticなメソッドを実装し、他クラスはこのメソッドを呼び出すことにより本クラスのインスタンスを取得する。

以上の実装により、インスタンスが1つしか生成されないことを確実にすることができる。

(2011-07-26 追記)
ちなみに、このSingletonパターンでインスタンスがいつ生成されるのか(いつコンストラクタが呼び出されるのか)、下記コードで確認してみる。

○Singletonパターンクラス
public class Hoge {
    private static Hoge instance = new Hoge();

    private Hoge() {
        System.out.println("Constructor");
    }

    public static void testMethod() {
        System.out.println("testMethod");
    }

    public static Hoge getInstance() {
        System.out.println("getInstance");
        return instance;
    }
}

○上記クラスの各メソッドを実行
public class Main {
    public static void main(String[] args) {
        System.out.println("Start");
        Hoge.testMethod();
        Hoge hoge = Hoge.getInstance();
    }
}
上記を実行すると、コンソールには以下の様にメッセージが表示される。


Start
Constructor
testMethod
getInstance


上記の結果から、初めてHogeクラスにアクセスしたタイミングでインスタンスが生成される(コンストラクタが呼び出される)ことが分かる。


[Java]Calendarクラスで現在の月を取得する時の注意点

Calendarクラスのgetメソッドを使用して現在の月を取得するには、以下の様にgetメソッドの引数に月を示すフィールド値"MONTH"を指定する。
Calendar calendar = Calendar.getInstance();
int month = calendar.get(Calendar.MONTH);
但し、Calendarクラスでの月は1~12ではなく0~11で表される為、実際の月を取得したい場合は、以下の様にgetメソッドで取得した値に+1する必要がある。
Calendar calendar = Calendar.getInstance();
int month = calendar.get(Calendar.MONTH) + 1;
尚、上記では「現在の」としているが、より正確には「Calendarクラスのインスタンスを取得した時点の」が正しい(取得したインスタンスが取得時点の日時を保持している為)。


[Java]正規表現を使用した文字列抽出 その2

以前の記事「正規表現を使用した文字列抽出」は、丸括弧()で挟まれた文字列を丸括弧含めて抽出する方法だったが、これを少し修正して、今度は丸括弧を省いて挟まれた文字列のみを抽出する方法。

正規表現では、パターン内の一部を丸括弧で挟むことによりグループ化することができる。
前回使用したパターンを表す文字列"\\(.+?\\)"の中で、今回抽出したい「丸括弧で挟まれた文字列」を表す部分".+?"を丸括弧で挟んで以下の様にグループ化する。

"\\((.+?)\\)"

それからもう1ヶ所、パターンにマッチした文字列を取得するMatcherクラスのgroupメソッドの引数で、取得したいグループの番号(1番目のグループを表す"1")を指定する。
String regex = "\\((.+?)\\)";
String target = "(abeshi)and(hidebu)";
List<String> omaewamoshindeiru = new ArrayList<String>();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(target);
while (matcher.find()) {
    omaewamoshindeiru.add(matcher.group(1));
}
これで、omaewamoshindeiruには以下文字列が格納される。

abeshi
hidebu


[Java]メソッドチェーン

あるクラスのメソッドが、戻り値としてそのクラスのインスタンスを返す場合、記述にメソッドチェーンを利用することができる。

AndroidでAlertDialogを表示する時に使用するAlertDialog.Builderクラスもその1つ。
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle("Title")
    .setMessage("Message")
    .setPositiveButton("Yes",
        new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                ごにょごにょ(PositiveButtonが押された時の処理)
            }
        })
    .setNegativeButton("No",
        new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                ごにょごにょ(NegativeButtonが押された時の処理)
            }
        })
    .setCancelable(false)
    .show();
上記は2つのボタン(PositiveButtonとNegativeButton)を持ったAlertDialogを表示する時の例だが、AlertDialogの挙動などの設定を行う各メソッド(setほにゃらら)の戻り値がAlertDialog.Builderクラスのインスタンス(上記例ではalertDialogBuilder)なので、この様にメソッドを続けて記述することができる。

初めてこの記述を見た時は「ん?」となったが、これはこれで便利かもしれない(コードの読みやすさを犠牲にすれば、1行で記述できる)。


[Java]クラスのListを任意の条件でソートする

クラスのListを任意の条件でソートしたい時の方法。

ListのソートはCollectionsクラスのsortメソッドで可能だが、Comparator<T>インタフェースを実装したクラスを作成し、2つの引数を取るsortメソッドの第2引数にこの自作クラスのインスタンスを渡してやることにより、任意の条件でのソートが可能となる。
ソート条件は、自作クラスのcompareメソッドで実装する。

例えば以下の様なHogeクラスがある。
public class Hoge {
    public int index;
    public int value;

    public void method() {
        ごにょごにょ(methodメソッドで行う処理)
    }
}
このHogeクラスのListを、

・indexフィールドの値での昇順
・indexフィールドの値が等しい場合はvalueフィールドの値での降順

という条件でソートしたい。

まず、Comparator<T>インタフェース(Tはソート対象となるHoge)を実装したHogeComparatorクラスを作成する。
public class HogeComparator implements Comparator<Hoge> {
    @Override
    public int compare(Hoge o1, Hoge o2) {
        Integer index_1 = new Integer(o1.index);
        Integer index_2 = new Integer(o2.index);
        Integer value_1 = new Integer(o1.value);
        Integer value_2 = new Integer(o2.value);
        int result;
        result = index_1.compareTo(index_2);
        if (result == 0) {
            result = value_2.compareTo(value_1);
        }
        return result;
    }
}
まず10行目で、2つのHogeクラスのindexフィールド値を比較する。
compareToメソッドは引数の方が小さい場合は正の値、大きい場合は負の値、等しい場合は0を返す。
この自作クラスのcompareメソッドの戻り値が正の値の場合はo2→o1の順、負の値の場合はo1→o2の順にソートされるので、index_1 > index_2の場合はo2→o1の順、index_1 < index_2の場合はo1→o2の順、つまり昇順でソートされる。

index_1 = index_2の場合(12行目が真の場合)は、今度は13行目でvalueフィールド値を比較する。
value_1 > value_2の場合はcompareメソッドの戻り値が負の値になるのでo1→o2の順、value_1 < value_2の場合はcompareメソッドの戻り値が正の値になるのでo2→o1の順、つまり降順でソートされる。

以上の自作クラスを以下の様に使用すれば、希望の条件でソートすることができる。
List<Hoge> hoges = new ArrayList<Hoge>();
HogeComparator comparator = new HogeComparator();
ごにょごにょ(hogesに要素を格納する処理その他)
Collections.sort(hoges, comparator);


[Java]正規表現を使用した文字列抽出

正規表現にはPatternクラスとMatcherクラスを使用する。
import java.util.regex.Pattern;
import java.util.regex.Matcher;
例えば、ある文字列から丸括弧()で挟まれた文字列を抽出する場合は、以下。
String regex = "\\(.+?\\)";
String target = "(abeshi)and(hidebu)";
List<String> omaewamoshindeiru = new ArrayList<String>();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(target);
while (matcher.find()) {
    omaewamoshindeiru.add(matcher.group());
}
正規表現のパターンを表す文字列regexを引数にして、PatternクラスのcompileメソッドでPatternクラスのインスタンスを取得。
続いて文字列抽出の対象となる文字列targetを引数にして、PatternクラスのmatcherメソッドでMatcherクラスのインスタンスを取得。

Matcherクラスのfindメソッドで検索を実施し、正規表現のパターンにマッチする度に、StringのListであるomaewamoshindeiruにそのマッチした文字列を追加していく。

その結果、omaewamoshindeiruには以下文字列が格納される。

(abeshi)
(hidebu)

正規表現のパターンを変えることで、様々な文字列を抽出することができる。


プロフィール

まさお

Author:まさお
プログラミングは趣味レベルなので、お手柔らかに。

ブログランキング
ブログランキング参加中。是非クリックお願いします。


にほんブログ村 IT技術ブログ Androidアプリ開発へ

人気ブログランキングへ

ブログランキング



ブログ王

ブログランキング【ブログの惑星】

プログラム人気ブログランキング
最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム
QRコード
QR