20210226のJavaに関する記事は4件です。

先頭から7bitが年、4ビットが月、残り5ビットが日 (Elixir)

はじめに

  • Elixir楽しんでいますか:bangbang::bangbang::bangbang:
  • AndroidでSuicaの履歴をみるというものを作ってみました
  • 「先頭から7bitが年、4ビットが月、残り5ビットが日」、「とある2バイトが残高、ただしリトルエンディアン」こういった処理って地味にけっこうたいへんではないでしょうか
  • Elixirならパターンマッチですっきり書けますのでご紹介します
  • 2021/2/27に開催するautoracex #12というもくもく会の成果とします

Screenshot_20210226-200730.png

  • 以下で紹介するサイトの記事を参考にするとすぐにできました :pray::pray_tone1::pray_tone2::pray_tone3::pray_tone4::pray_tone5:

参考にしたサイト

スクリーンショット 2021-02-26 15.49.26.png

( Felica Library > Wiki > Suica )

先頭から7bitが年、4ビットが月、残り5ビットが日

Java

    public Date getProccessDate(int date, int time) {
        int yy = date >> 9;
        int mm = (date >> 5) & 0xf;
        int dd = date & 0x1f;
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, 2000 + yy);
        c.set(Calendar.MONTH, mm-1);
        c.set(Calendar.DAY_OF_MONTH, dd);

        int hh = time >> 11;
        int min = (time >> 5) & 0x3f;
        c.set(Calendar.HOUR_OF_DAY, hh);
        c.set(Calendar.MINUTE, min);
        return c.getTime();
    }

Elixir

  • "FgEAAilfAlyLByQDAAWHMA=="は冒頭の写真でみせました表示例の最初のデータをBase64エンコードしたものであります
  • これを例に2020年10月31日が簡単に取り出せることを示します
iex> Base.decode64 "FgEAAilfAlyLByQDAAWHMA=="
{:ok, <<22, 1, 0, 2, 41, 95, 2, 92, 139, 7, 36, 3, 0, 5, 135, 48>>}
iex> <<_::32, year::7, month::4, day::5, _::binary>> = <<22, 1, 0, 2, 41, 95, 2, 92, 139, 7, 36, 3, 0, 5, 135, 48>>
<<22, 1, 0, 2, 41, 95, 2, 92, 139, 7, 36, 3, 0, 5, 135, 48>>
iex> year
20
iex> month
10
iex> day
31
  • どうでしょうか、細かい書き方は抜きにして7bitとか4bit5bitを指定することでパターンマッチで値をとれます
  • シフトなどの演算を自分で書く必要はありません

とある2バイトが残高、ただしリトルエンディアン

Java

remain = Long.valueOf((bytesToInt(new byte[]{response[24], response[23]})));

...
    private int bytesToInt(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b));
        }
        return Integer.valueOf(sb.toString(), 16);
    }


  • こちらも冒頭の写真の最初のデータの残高804円が取り出せる様子を示します

Elixir

iex> <<_::80, remain::16-little, _::binary>> = <<22, 1, 0, 2, 41, 95, 2, 92, 139, 7, 36, 3, 0, 5, 135, 48>>  
<<22, 1, 0, 2, 41, 95, 2, 92, 139, 7, 36, 3, 0, 5, 135, 48>>
iex> remain
804
  • どうでしょうか、こちらも16-littleという文法さえ覚えてしまえばパターンマッチ一発で値を取得できます

Wrapping Up :lgtm::lgtm::lgtm::lgtm::lgtm:

  • 他にどういった指定が可能なのかについては、公式にある<<>> の説明をご参照ください
  • ビット数を指定して、パターンマッチができるのいいですよね:bangbang::bangbang::bangbang:
  • Enjoy Elixir :rocket::rocket::rocket:
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

あらためてJavaを学習する(その1)変数

Java学習の備忘録です。
Javaインストールから簡単なクラスの説明などは「あらためてJavaを学習する(その0)」で解説してます。
あらためてJavaを学習する(その0)

変数(variable)

メモリ領域(記憶装置)に名前(識別子)をつけて値を保存すること。
変数を用いることで、データを一定期間記憶し必要なときに利用することができる

  1. メモリの場所に変数名をつける
  2. データ型を指定して、値(value)を代入する
  3. 値を呼び出す際は、変数名 → メモリ番地を参照 → 値を取得 の順になる

変数に入れる値のことをリテラルと呼ぶ。

識別子のルール

  • 予約語以外であれば任意で指定可能
  • 英数字、アンダースコア(_)、ドルマーク($)が利用可能。
  • 数字で始まることはできない

<重要ポイント>
小文字と大文字は区別される

データ型

データ型は2種類ある。

  • 基本データ型(プリミティブ型)
    変数に直接値を入れる
  • 参照型
    参照するメモリの番地(アドレスの値)を保持(文字列や配列など)

基本データ型の一覧

データ型 説明 サイズ
byte 整数( -128 ~ 127 ) 8bit
short 整数( -32,768 ~ 32,767 ) 16bit
int 整数( -2,147,483,648 ~ 2,147,483,647) 32bit
long 整数( -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807) 64bit
float 浮動小数( ±1.40239846 × (10 の- 45 乗) ~ ±3.40282347 × (10 の 38 乗) 32bit
double 浮動小数( ±4.940655645841246544 × (10 の -324乗) ~ ±1.79769313486231570 × (10 の 308乗 ) 64bit
char 1文字(Unicode) 16bit
boolean 真偽値(true/false) 1bit

太字がよく使うデータ型

変数の宣言

// データ型 変数名;
int num;

// 宣言と初期化
// データ型 変数名 = 値;
int num = 1;

※変数の初期化

変数に対して最初に値を代入すること。
値を代入せず変数宣言を行い、変数を利用しようとするとエラーとなる。

int num;
System.out.println(num); // error: variable num might not have been initialized

参照型

クラスから生成したインスタンスや配列などは参照型となる。
ざっくり書くと「基本データ型以外のデータ型」は参照型。

参照 = 「値を指し示すもの(メモリのアドレス)」

参照型には何も参照していないことを示すnullが代入できる。

文字列

データ型はString
文字列は基本データ型ではなく参照型
JavaScriptなどの他の言語では、シングルクォーテーション(')でも代入できるが、Javaの場合はダブルクォーテーション(")のみとなる。

String str1 = "Hello Java";
String str2 = 'Hello Java'; // error: unclosed character literal

配列

同じデータ型で複数データをひとまとめにしたもの。
初期化にはnewを指定する。

宣言と初期化が同時であれば、newを用いず{}の記述を行い、その中に値をカンマ(,)で区切って代入することが可能。
なお、{}を使うことで、宣言と代入を分割して記述することもできるが、その際は[ ]の中に要素数の指定はできない。({ }で指定した要素数で配列の要素が決まるため)

// **** 宣言 ****
// データ型[] 変数名;
// データ型 変数名[];
int[] numbers;

// **** 初期化 ****
// 変数名 = new データ型[データの個数];
numbers = new int[10];

// **** 宣言と初期化 ****
String[] names = {"Java", "PHP", "COBOL"};

// **** 分割 ****
int[] nums;
nums = new int[]{1, 50, 200};

各値はインデックスを指定することで取得することができる。先頭は0となる。
なお、インデックスを指定しない場合はその配列の参照値が取得できる。

System.out.println(names[0]); // Java
System.out.println(numbers); // [I@36baf30c

初期化のデフォルト値

newで要素分の配列を確保した時点で、デフォルト初期値が設定される。

データ型 初期値
boolean[ ] false
int[ ], long[ ], float[ ], double[ ], char[ ], byte[ ] 0
上記以外(String型など) null

多次元配列

配列の中に配列を指定できる。

String[][] progs = new String[2][2];
        progs[0][0] = "Java";
        progs[0][1] = "PHP";
        progs[1][0] = "Oracle";
        progs[1][1] = "The PHP Group";

        System.out.println(progs[0][0]); // Java
        System.out.println(progs[1][0]); // Oracle

変数のスコープ

スコープ = 変数の有効範囲
ブロック{ } 内で宣言した変数は、そのブロック内だけで有効であり外からは参照できない。

Main.java
public class Main {
    int a = 1;

    public static void main(String[] args) {
        // 変数bをここで宣言する
        int b = 10;
        Main mainClass = new Main();
        mainClass.printNum();
    }

    void printNum(){
        int c = 100;
        System.out.println(a);
        // bは宣言されていないためエラーが起きる
        System.out.println(b); // error: cannot find symbol
        System.out.println(c);
    }
}

演算子

演算子自体をオペレータと呼び、値のことをオペランドと呼ぶ。
値と演算子を組み合わせた計算の単位をと呼ぶ。

主な演算子一覧

int a = 1;
int b = 2;

演算子 説明 記述例 結果 備考
+ 加算 10 + 1 11
- 減算 10 - 1 9
* 乗算 10 * 10 100
/ 除算 10 / 2 5
% 剰余 10 % 3 1
+= 加算(a = a + 1) a += 1 2
++ 加算(a = a + 1) a++ または ++a 2 インクリメント(サンプルコード参照)
-= 減算(b = b -1) b -= 1 1
-- 減算(b = b -1) b-- または --b 1 デクリメント(サンプルコード参照)
*= 乗算(b = b * 2) b *= 2 4
/= 除算(b = b / 2) b /= 2 1
%= 剰余(b = b % 2) b %= 2 0
> 比較(aがbより大きい) a > b false
< 比較(aがbより小さい) a < b true
>= 比較(aがb以上) a >= b false
<= 比較(aがb以下) a <= b true
== 比較(aがbと等しい) a == b false 文字列の値比較の場合はString#equalsメソッドを利用(サンプルコード参照)
!= 比較(aとbが異なる) a != b true
& 論理積(AND) a > b & a != b false 左辺がfalseでも右辺も評価を行う
&& 論理積(AND) a > b && a != b false 左辺がfalseの時点で評価を終える(右辺の評価はしない)
| 論理積(OR) a > b | a != b true 左辺がtrueでも評価を行う
|| 論理積(OR) a > b || a != b true 左辺がtrueの時点で評価を終える(右辺の評価はしない)

サンプルコード

Sample1.java
public class Sample1 {
    public static void main(String[] args) {
        // **** インクリメント・デクリメント ****
        int a = 1;
        int b = 2;

        System.out.println(a++); // 1
        // System.out.println(a); 
        // a = a + 1;
        System.out.println(++a); // 3
        // a = a + 1;
        // System.out.println(a);

        System.out.println(a++ + --a + b--); // 8
        System.out.println("a : " + a + " , b : " + b); // a : 3 , b : 1


        // **** 文字列の値比較 ****
        String str1 = "Hello";
        // インスタンス生成
        String str2 =  new String("Hello");

        System.out.println(str1 == str2); // false
        System.out.println(str1.equals("Hello")); // true


        // **** ANDとOR ****
        int x = 10;
        if(false && ++x == 11){ // 右辺は評価されない
            System.out.println(x);
        }
        if(false & ++x == 11){ // 右辺は評価される
            System.out.println(x); 
        }

        System.out.println(x); // 11
    }
}

文字列と数値の連結

数値側は自動的に文字列に変換されて結合される
括弧() で括ることで、演算結果をうまく連結することができる

Sample2.java
public class Sample2 {
    public static void main(String[] args) {
       int num = 1;
       String str = "1";
       System.out.println(str + num); // 11

       System.out.println(str + (num + 3)); // 14
       System.out.println(str + num + 3); // 113
    }
}

キャスト(明示的型変換)

大きい型から小さい型への変換の場合は、明示的に宣言(キャスト)しないとエラーとなる。

型によって保持できる値の範囲があるため、容量越えの値をキャストした場合は桁落ちなどで想定外の結果になる可能性があるので注意。

小数から整数へのキャストの場合は、小数点以下は切り捨てられる。

<キャストが不要な場合の条件>
* 小さい型から大きい型への変換
* 整数から小数への変換

int intNum = 10;

// 小 → 大
long longNum = intNum;

// 大 → 小
// データ型 変数名 = (データ型)変数名;
byte byteNum = (byte)intNum;

System.out.println(longNum); // 10
System.out.println(byteNum); // 10

// 小数 → 整数
double doubleNum = 3.1416;
intNum = (int)doubleNum;
System.out.println(intNum); // 3

最後に

変数についてザックリと学習してみました。
次回は基本構文の学習をザッと行いたいと思います!

参考文献

この記事は以下の情報を参考にして執筆しました。
【サイト】
・Wikipedia:変数(プログラミング)
・苦しんで覚えるC言語:数値を記録する
【書籍】
・「基礎からのJava」SB Creative出版:基礎からのJava 改訂版

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java小テスト② 〜 for 編 〜

これは友達向けのJavaの小テストです。
Java初心者の文法腕試しでお使いくださいー!!

今日はfor文の小テストを作りたいと思います!

問題1:ミスを探しなさい。

public static void main(String[] args) {
    for i = 0; i < 10; i++ {
        System.out.println(i);
    }
}

問題2:出力されるものは何か?

public static void main(String[] args) {
    for(int i = 0; i < 100; i += 10) {
        System.out.print(i);
    }
}

問題3:以下を満たすプログラムを書きなさい。

  • 100回繰り返す。
  • 回数が3の倍数のときは, 「Fizz」を出力する
  • 回数が5の倍数のときは. 「Buzz」を出力する
  • 3と5の公倍数である場合は「FizzBuzz」を出力する
  • それ以外は数字をそのまま出力する。

問題4:以下を満たすプログラムを書きなさい。

  • 1から10を動く変数"i"
  • 10から20を動く変数"j"
  • 各 "i"と"j"に対して, "i + j"が問題3の状態を満たす
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaの機能

クラス定義

class クラス名 {

}

クラス名は英字の大文字で始まる名詞にする。キャメルケースで命名。

mainメソッド

class クラス名 {
    public static void main(String[] args){

    }
}

プログラムの処理を開始する場所。
クラスの中に定義され、JVMはmainメソッドの先頭から処理を実行する。

データ出力

System.out.println("こんにちは");
System.out.println(1);
出力
こんにちは
1

System.out.printlnは出力時、改行される

System.out.print("こんにちは");
System.out.print(1);
出力
こんにちは1

System.out.printは出力時、改行されない

コメントアウト

// 1行

/*
複数行
*/

変数

// データ型 変数名 = データ;で定義

int number = 777; //整数を扱うにはint型
double number2 = 0.14;  //小数を扱うにはdouble型
char message = 'A';  //1文字をを扱うにはchar型
String messages = "ABC";  //文字列を扱うにはString型
boolean flag = false;  //true or falseを扱うにはboolearn型

定義したデータ型と違うデータを代入するとコンパイルエラーが起こる。

定数

final int SP_NUMBER = 777;

再代入不可能の変数。普通の変数の定義の前にfinalを指定するだけ。
すべて大文字で定義。複数の単語を組み合わせるなら_を使用する。

演算子

変数の値に1加算する演算子 == インクリメント演算子 ++変数 or 変数++
変数の値から1を減算する演算子 == デクリメント演算子 --変数 or 変数--

int data1 = 100
int data2 = 100

System.out.println( ++data1 )
System.out.println( data1++ )
出力
11
10

前と後ろどちらに記述しても効果は同じだが処理のタイミングが異なる。

前なら変数の利用前
後ろなら変数の利用後

型変換

  • 自動変換

データ型が異なる変数間で演算を行う際に、サイズの小さいデータ型から大きいデータ型に自動的に変換される。
(サイズとはバイトのこと)

代入演算
int number = 13;
//double型のnumber2にint型のnumberを代入する
double number2 = number; //double型に変換されて代入されている。
算術演算
int number = 13;
double number2 = 7.7;
//int型+double型の演算
double number3 = number + number2; //この場合はnumberがdouble型に変更されて計算されている。
  • キャストによる変換

プログラマが明示的に行う型変換。キャスト演算子を使用する。

大→小
double number = 7.7;
int number2;
//大きいデータ型numberを小さいデータ型のnumber2に代入したい。
number2 = (int)number;
//キャストは成功。しかしint型では小数点は扱えないため、小数点以下が切り捨てられてしまう。
一時的変換
int number = 30;
int number = 7;
//キャストせずに、int型同時の割り算を行うと...
double result = number/number2; //intでは小数を扱えないため、30/7=4となってしまい、resultの値は4を小数点で表した4.0となる。
//キャストを行った場合...
double result = (double)number/number2;  //numberが変換され30.0に、number2は自動変換で7.0となり、resultは4.5となる。

配列

配列の宣言
データ型[] 配列名;
配列の生成
int[] hoge;
hoge = new int[7]; //配列の要素数を決めている。
宣言と生成をまとめて行う
int[] hoge = new int[7];
宣言と生成と初期値を代入
int[] hoge = {1,2,3,4,5,6,7}

equalsメソッド

文字列の比較には比較演算子が使用できない。その代わりequalsメソッド使用する。

"aaa".equals("aaa")

分岐処理

  • if文

条件によって異なる処理を実行する。

public class Sample {
    public static void main(String[] args) {
        int  a = 5;
        if (a < 7) {
            System.out.println("aは7未満です。");
        } else {
            System.out.println("aは7以上です。");
        }
    }
}
出力
aは7未満です
  • swich文
public class Sample {
    public static void main(String[] args) {
        int  a = 5;
          switch(a){
        case 0:
            System.out.println("0ですね~");
            break;
        case 5:
            System.out.println("5ですね~");
            break;
        case 13:
            System.out.println("13ですね~");
            break;
        case default:
            System.out.println("分かりませぬ");
            break;
        }
    }
}
// breakを書かなければ当てはまっても処理を途中で抜けずに以降のケース全てを出力してしまう。

繰り返し処理

  • while文
public class Sample {
    public static void main(String[] args) {
        int  a = 0;
          while(a<5){ //aが5になるまで処理を続ける。
             System.out.println(a++); //aを出力後に+1
    }
  }
}
出力
0
1
2
3
4
  • for文

繰り返したい回数が決まっている時に使用されやすい。

public class Sample {
    public static void main(String[] args) {
        for(int a = 0; a < 5; a++){
             System.out.println(a); //aを出力後に+1
    }
  }
}
出力
0
1
2
3
4
  • 拡張for文
public class Sample {
    public static void main(String[] args) {
       int[] a = {1,2,3,4,5};

       for(int number: a){  //aの配列の要素がなくなるまで繰り返し処理を行う
           System.out.println(number);
    }
  }
}
出力
1
2
3
4
5

インスタンス(オブジェクト)

生成時
Example exam = new Example()
//変数examに生成されインスタンスを参照するための値が入っている。
メソッドの使用時
Example exam = new Example()
exam.power(15)  //参照先のインスタンスのインスタンスメソッドpowerに引数を渡して処理している。

コンストラクタ

インスタンス生成時に呼び出される特殊なメソッド。
オブジェクト生成時にインスタンス変数を任意の値に初期化できる。

定義時にはクラス名と同じ名前で定義する必要がある。

注意点としてコンストラクタがあるのに引数無しのインスタンスを作成しようとするとコンパイルエラーになる。

そのため、コンストラクタ未定義の場合にのみ引数無しのインスタンスを作成できる。
未定義の場合はコンパイル時にデフォルトコンストラクタが補完される。

コンストラクタ定義時
class Example{
  String prefecture; 
  String boss;
  Example(String p, String b){ //同じ名前で定義
    prefecture = p;
    boss = b;
  }
}
コンストラクタ呼び出し
Example exam = new Example("東京都知事","小池百合子")
//インスタンスメソッドにあらかじめ引数を受け取るように設定しておけば、コンストラクタによってインスタンス変数の初期値が引数の値になる。

オーバーロード

1つのクラスに同名のメソッドやコンストラクタがあっても引数の型や数が違えば別のメソッドとみなされる。

メソッドのオーバーロード
class Example{
  int b
    void aaa(){
      b++;
  }

    void aaa(int a){
      b += a;
  }
}
//同じメソッド名aaaでも引数の個数が違うため別のメソッドとして扱われる。

呼び出しの際は、メソッド側の受け取れる引数の型と個数にあわせて呼び出せばOK。

オーバーライド

サブクラスでスーパークラスのメソッドを書き換える機能。
(しかし実際は書き換えているわけではなく、スーパークラスにあったメソッドも残っている。)

残っているスーパークラスのメソッドを使用したいときは、super.メソッド名で使用できる。

メソッド名が同じであり引数も同じでなければならない。

スーパークラス
class EXample
--------------------------------
pubulic void abcd(){
  System.out.println("abcd");
}
サブクラス
class EeampleWord extends Example
--------------------------------
pubulic void abcd(){
  System.out.println("abcd");
  System.out.println("efgh");
}
テストクラス
class TestExample{ 
  public static void main(String[] args){
    ExampleWord a = new ExampleWord();
    a.abcd(); //呼び出されるのはサブクラスのメソッド
  }
}

this

オブジェクト自身を表している。

インスタンス変数とローカル変数の区別、オーバーロードしている別のコンストラクタの呼び出しに使われる。

変数の区別
class Example{
  String prefecture; //インスタンス変数prefectureを定義。
//スコープが違えば同じ名前の変数が使用できる。
  Example(String prefecture ){  //コンストラクタでローカル変数prefectureを定義。
    this.prefecture = prefecture;
    //左辺がインスタンスprefectureを意味している。
  }
}

カプセル化

オブジェクトの中身を外部に対して非公開にすること。

アクセス指定子を使って公開範囲を決めることができる。

指定子 同一クラス 同一パッケージ 別パッケージの子クラス 別パッケージ
public
protected ×
指定なし × ×
private × × ×

※パッケージはフォルダーみたいな解釈でOK

指定の方法
//インスタンス変数
 アクセス指定子 データ型 変数名;
//インスタンスメソッド
アクセス指定子 (void) 変数名()

proivateなインスタンス変数にアクセスるためにはアクセサが必要。
詳しくは検索。

static変数

staticメソッドを修飾子に指定した場合オブジェクト生成を必要としない。

インスタンス変数は、インスタンスが複数生成されてもインスタンスごとに独立していた。

一方static変数では、インスタンスごとではなくクラスに1つしか用意できない変数。

どのインスタンスからでもアクセスすることが出来る。

staticメソッドも存在しており、staticメソッドはstaticメンバ(staticのインスタンス変数など)へのアクセスのみができる。

定義の仕方
static final データ型 変数名 = 初期値;
//複数のインスタンスからアクセスできるため、定数にしなければどのインスタンスからでも書き換えができてしまう。

列挙型

配列とは違い定数を集めて名前を付けたもの。

定義の仕方
enum 列挙型名{
要素,要素,要素...
}
参照の仕方
列挙型名.要素名

列挙型が定義されていた場合は、データ型に指定して変数に代入できる。

列挙型名 変数名 = 列挙型名.要素名

インタフェース

定義
interface インタフェース名 {
// static定数と抽象メソッドが定義できる。
}

抽象メソッドとは定義するだけのメソッドで中身を持たないメソッド。
そのため、インタフェースを実装したクラスには抽象メソッドの中身が存在しなくてはならない。

interface インタフェース名 {
public abstract void abcd(); //abcdメソッドが別に定義されている必要がある。
void efgh(); //修飾子を省略するとpublicメソッドになる。
}
実装
class クラス名 implements インタフェース名{
//インタフェースめ抽象メソッドをオーバーライドする。
}

インタフェースは単体ではインスタンス化をすることはできない。

クラスに実装を行って初めてインスタンス化が行えるようになる。

インスタンス化を行うとインタフェース型変数に代入することも可能。

抽象クラス

定義
abstract クラス名 {
}

インスタンスメソッドも抽象メソッドも定義が可能だがインスタンス化を行えない。

継承を前提としたクラス。インスタンス化も行えないため、継承しなければ使用の意味がない。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む