0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Java復習2日目】サンプルコードから学び直すJava入門②

Last updated at Posted at 2021-06-25

サンプルコード(printf)

Printf.java
import java.util.Date;

class Printf {
    public static void main(String[] args) {
        // 九九の表を表示
        for (int i = 1; i <= 9; i++) {
            for (int j = 1; j <= 9; j++) {
                // 
                System.out.printf("%3d", i * j);
            }
            System.out.println();
        }

        System.out.println();

        Date date = new Date();

        // 最小桁幅が3桁の10進整数
        System.out.printf("your balance: $%3d\n", 1);
        // ,(カンマ)区切りの10進整数
        System.out.printf("your deposit: ¥%,d\n", 1234567);
        // 最小桁幅が7桁,小数点第2位までの小数
        System.out.printf("your BMI: %7.2f\n", 19.37593);
        // 足りない桁を"0"で埋めた, 最小桁幅が5桁の10進整数
        System.out.printf("%05d\n", 351);
        // 現在の日付
        System.out.printf("Today is %tF.\n", date);
    }
}
実行結果
  1  2  3  4  5  6  7  8  9
  2  4  6  8 10 12 14 16 18
  3  6  9 12 15 18 21 24 27
  4  8 12 16 20 24 28 32 36
  5 10 15 20 25 30 35 40 45
  6 12 18 24 30 36 42 48 54
  7 14 21 28 35 42 49 56 63
  8 16 24 32 40 48 56 64 72
  9 18 27 36 45 54 63 72 81

your balance: $  1
your deposit: ¥1,234,567
your BMI:   19.38
00351
Today is 2021-06-25.

printf()メソッド

参考1: Format String Syntax
参考2: 日付の表示
PrintStreamクラスで定義される、出力フォーマットを指定して出力ストリームに文字列を書き込む(=コンソールに出力する)メソッド。

出力フォーマットは以下のように記述する。なお、ここではオプション[...]で表すこととする。

%[値に挿入される記号(フラグ)][最小桁幅]変換文字

また、出力する際に改行を行う場合は、出力フォーマットの末尾に改行文字\nを挿入する。

定義

PrintStream PrintStream.printf(String format, Object args)
// パラメータ
// format: 「出力フォーマット」を表す文字列
// args: 参照する値

サンプルコード(キャスト演算子)

Cast.java
import java.util.Scanner;

class Cast {
    public static void main(String[] args) {
        Scanner stdIn = new Scanner(System.in);

        System.out.print("int x: "); int x = stdIn.nextInt();
        System.out.print("int y: "); int y = stdIn.nextInt();

        // 右辺はint型同士の演算 -> 結果はint型
        double ave = (x + y) / 2;
        System.out.println("average without casting: " + ave);
        // 右辺はint型とdouble型の演算 -> 暗黙的な二項数値昇格(=型変換)によって結果がdouble型に変換
        ave = (x + y) / 2.0;
        System.out.println("average with implicitl binary numerical promotion: " + ave);
        // 右辺はdouble型にキャストされたint型同士の演算 -> 結果はdouble型
        ave = (double) (x + y) / 2;
        System.out.println("average with cast operator: " + ave);
    }
}
実行結果
int x: 7
int y: 8
average without casting: 7.0
average with implicitl binary numerical promotion: 7.5
average with cast operator: 7.5

二項数値昇格

表現範囲の異なる型同士の演算時に暗黙的に行われる、表現範囲の狭い型の拡大変換

キャスト演算子

(<T>)で表される、演算結果を指定したに変換する演算子。


サンプルコード(丸め誤差への対策)

CalcError.java
class CalcError {
    public static void main(String[] args) {
        float sum = 0.0F;

        // float型による加算
        for (float x = 0.0F;x <= 1.0F; x += 0.001F) {
            sum += x;
        }
        System.out.println("addition with float: " + sum);

        sum = 0.0F;
        // int型による加算
        for (int y = 0; y <= 1000; y++) {
            float z = (float) y / 1000;
            sum += z;
        }
        System.out.println("addition with int: " + sum);
    }
}
実行結果
addition with float: 500.49667
addition with int: 500.49997    // <- int型を利用した方が誤差が小さい

拡張表記(escape sequence)

拡張表記 内容 Unicode拡張表記
\b 後退(backspace) \u0008
\f 書式送り(form feed) \u000c
\n 改行(new line) \u000a
\r 復帰(carriage return) \u000d
\t 水平タブ(horizontal tab) \u0009
\<記号> エスケープ文字(escape)
\o 8進数(octal)
\h 16進数(hexadecimal)

サンプルコード(拡張for文, for-in文)

AdvancedFor.java
class AdvancedFor {
    public static void main(String[] args) {
        int[] a = { 1, 2, 3, 4, 5};
        int sum = 0;

        // for-in文
        // -> iはint型配列aの各構成要素の値
        for (int i : a) {
            sum += i;
        }

        System.out.println("sum is " + sum + ".");
    }
}

サンプルコード(スコープ)

Scope.java
class Scope {
    // フィールド
    static int x = 700;

    // フィールドxを出力するメソッド
    static void printX() {
        System.out.println("field x: " + x);
    }
    public static void main(String[] args) {
        // フィールドxの出力
        System.out.println("field x: " + x);

        // 局所変数x
        // <- フィールドと有効範囲(=スコープ)が異なるため同名での宣言が可能
        int x = 800;

        // 局所変数xの出力
        System.out.println("local variable x: " + x);

        // Scopeクラスのフィールドxの明示的出力
        System.out.println("field in class Scope x: " + Scope.x);

        // フィールドxの出力
        printX();
    }
}
実行結果
field x: 700
local variable x: 800
field in class Scope x: 700
field x: 700

サンプルコード(ビット演算)

Bits.java
import java.util.Scanner;

class Bits {
    // int型のビット構成を出力するメソッド
    static void printBits(int x) {
        for (int i = 31; i >= 0; i--) {
            // 大きい位のビットから、1とのビット論理積を求める
            System.out.print( ((x >>> i & 1) == 1) ? '1' : '0' );
        }
    }

    // int型のビット構成に含まれる、"1"であるビットの総数を返却するメソッド
    // <- 複数のアルゴリズムが存在
    static int count1InBits(int x) {
        // "1"であるビットの総数
        int count = 0;

        while (x != 0) {
            // 1とのビット論理積が1である場合の処理
            if ( (x & 1) == 1 ) count++;
            // 計算後は1ビット右方向に論理シフトしたものを再代入
            // ⇔ x = x >>> 1
            x >>>= 1;
        }

        // カウントした総数を返却
        return count;
    }

    public static void main(String[] args) {
        Scanner stdIn = new Scanner(System.in);

        System.out.print("int: "); int x = stdIn.nextInt();
        System.out.print("bit: ");
        printBits(x);
        System.out.println( "\n1 in bit: " + count1InBits(x) );
    }
}
実行結果
int: 93
bit: 00000000000000000000000001011101
1 in bit: 5

ビット計算で用いられる論理演算子

記号 名称 内容
& ビット論理積演算子(bitwise and operator) AND
| ビット論理和演算子(bitwise or operator) OR
^ ビット排他的論理和演算子(bitwise exclusive or operator) EOR(XOR)
~ ビット補数演算子(bitwise complement operator) -

シフト演算子(shift operator)

利用例 内容
x << n 左方向へnビットシフト
x >> n 右方向へnビット算術シフト
x >>> n 右方向へnビット論理シフト

算術シフトと論理シフト

算術シフト(arithmetic shift)は最上位ビットを符号ビットとする。
論理シフト(logical shift)は全ビットをとする。


サンプルコード(アクセス修飾子と静的/動的メソッド)

Accessibility.java
import java.util.Scanner;

// publicなクラスはファイル名と同名でなければならないため、publicキーワードは付与しない
class Day {
    // 外部クラスに公開しないprivateなフィールド
    // <- <Dayオブジェクト>.<フィールド>でのアクセス不可
    // => アクセサ(ゲッタ/セッタ)を用いてフィールドにアクセスしなければならない
    private int year;
    private int month;
    private int date;

    // クラスコンストラクタ
    // -> コンストラクタは通常外部クラスから利用するためpublicキーワードを付与
    public Day(int year, int month, int date) {
        // this参照によってフィールドと同名な仮引数を区別
        this.year = year;
        this.month = month;
        this.date = date;
    }

    // ゲッタ(=アクセサ)
    // <- privateなフィールドを外部クラスから間接的に参照
    public int getYear() { return year; }
    public int getMonth() { return month; }
    public int getDate() { return date; }

    // セッタ(=アクセサ)
    // <- privateなフィールドを外部クラスから間接的に設定
    public void setYear(int year) { this.year = year; }
    public void setMonth(int month) { this.month = month; }
    public void setDate(int date) { this.date = date; }

    // 外部クラスから利用可能(public)な静的メソッド(=クラスメソッド)
    // -> 「クラス」が所有するメソッド
    // => 引数によって結果は異なるが、インスタンスによって結果が異なることはない
    public static boolean isLeap(int y) {
        return y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
    }

    // 外部クラスから利用可能(public)な動的メソッド(=インスタンスメソッド)
    // -> 「インスタンス(=オブジェクト)」が所有するメソッド
    // => インスタンスがもつフィールドの値を利用するため、インスタンスによって結果が異なる
    public boolean isLeap() {
        // 同名であるクラスメソッドisLeap(y:)を利用
        return isLeap(year);
    }

    // ツェラーの公式を用いた曜日を算出する動的メソッド(=インスタンスメソッド)
    public int dayOfWeek() {
        int y = year;
        int m = month;
        if (m == 1 || m == 2) {
            y--;
            m += 12;
        }
        return (y + y / 4 - y / 100 + y / 400 + (13 * m + 8) / 5 + date) % 7;
    }
}

// publicなクラスはファイル名と同名でなければならないため、publicキーワードは付与しない
class DayComparator {
    // 外部クラスに公開しないprivateな静的メソッド(=クラスメソッド)
    // -> プログラムの中でDayComparatorインスタンス(=オブジェクト)は生成されないため、 静的メソッドで宣言
    private static boolean compRef(Day d1, Day d2) {
        // 「参照先」が同じであればtrueを返却
        return (d1 == d2);
    }

    // 外部クラスに公開しないprivateな静的メソッド(=クラスメソッド)
    // -> プログラムの中でDayComparatorインスタンス(=オブジェクト)は生成されないため、 静的メソッドで宣言
    private static boolean compVal(Day d1, Day d2) {
        // 「値」が同じであればtrueを返却
        return  d1.getYear() == d2.getYear() &&
                d1.getMonth() == d2.getMonth() &&
                d1.getDate() == d2.getDate();
    }

    public static void main(String[] args) {
        Scanner stdIn = new Scanner(System.in);

        // privateキーワードを付与すると"only final is permitted"とエラーが出力
        // <- main()メソッド内で宣言される局所変数(=ローカル変数)であり、そもそもprivate/publicの概念がないため
        //    局所変数に付与できるキーワードは"final"のみ
        int y, m, d;

        System.out.println("Day A: ");
        System.out.print("Year: "); y = stdIn.nextInt();
        System.out.print("Month: "); m = stdIn.nextInt();
        System.out.print("Date: "); d = stdIn.nextInt();
        Day dayA = new Day(y, m, d);

        System.out.println("Day B: ");
        System.out.print("Year: "); y = stdIn.nextInt();
        System.out.print("Month: "); m = stdIn.nextInt();
        System.out.print("Date: "); d = stdIn.nextInt();
        Day dayB = new Day(y, m, d);

        // 静的メソッド(=クラスメソッド)の呼び出し
        // -> "<クラス名>.~" で呼び出す
        System.out.println("Day B is " + (Day.isLeap(y) ? "" : "not ") + "leap year.");
        // 動的メソッド(=インスタンスメソッド)の呼び出し
        // -> "<クラス型変数(=インスタンス)名>.~" で呼び出す
        System.out.println("Day B is " + (dayB.isLeap() ? "" : "not ") + "leap year.");

        if ( compRef(dayA, dayB) ) {
            System.out.println("Reference is the same.");
        }
        else {
            System.out.println("Reference is different.");
        }

        if ( compVal(dayA, dayB) ) {
            System.out.println("Value is the same.");
        }
        else {
            System.out.println("Value is different.");
        }
    }
}
実行結果
Day A: 
Year: 2021
Month: 6
Date: 25
Day B: 
Year: 2021
Month: 6
Date: 25
Day B is not leap year.
Day B is not leap year.
Reference is different.
Value is the same.

アクセス修飾子

参考: アクセス修飾子

修飾子 同一クラス 同一パッケージ サブクラス すべて
public(公開) o o o o
protected(限定公開) o o o x
(なし)(デフォルト) o o x x
private(非公開) o x x x

動的メソッドと静的メソッド

staticキーワードを付与しない動的メソッドは、個々のインスタンスによって結果が異なる処理。
staticキーワードを付与する静的メソッドは、個々のインスタンスによらない結果をもたらす処理またはクラス全体に関係する処理。

なお、staticキーワードはシグネチャに該当するため、同名での宣言が可能

動的メソッドと静的メソッド
// 外部クラスから利用可能(public)な静的メソッド(=クラスメソッド)
// -> 「クラス」が所有するメソッド
// => 引数によって結果は異なるが、インスタンスによって結果が異なることはない
public static boolean isLeap(int y) {
    return y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
}

// 外部クラスから利用可能(public)な動的メソッド(=インスタンスメソッド)
// -> 「インスタンス(=オブジェクト)」が所有するメソッド
// => インスタンスがもつフィールドの値を利用するため、インスタンスによって結果が異なる
public boolean isLeap() {
    // 同名であるクラスメソッドisLeap(y:)を利用
    return isLeap(year);
}

// 静的メソッド(=クラスメソッド)の呼び出し
// -> "<クラス名>.~" で呼び出す
System.out.println("Day B is " + (Day.isLeap(y) ? "" : "not ") + "leap year.");
// 動的メソッド(=インスタンスメソッド)の呼び出し
// -> "<クラス型変数(=インスタンス)名>.~" で呼び出す
System.out.println("Day B is " + (dayB.isLeap() ? "" : "not ") + "leap year.");

用語集

用語 内容
ビット(bit) binary digit(2進数字)の略称。01で表現される。
2進整数リテラル(binary integer literal) 冒頭に0bまたは0Bを付与して表現する2進整数。
8進整数リテラル(octal integer literal) 冒頭に0を付与して2桁以上で表現する8進整数。
16進整数リテラル(hexadecimal integer literal) 冒頭に0x付与して表現する16進整数。
縮小変換(narrowing primitive conversion) 明示的に行う必要のある、表現範囲の狭い型への変換。
拡大変換(widening primitive conversion) 暗黙的に行われる、表現範囲の広い型への変換。
FP厳密(FP-strict) 演算結果が実行環境に依存しないようにすること。
クラスメソッドstrictfpキーワードを付与する。
※通常の計算では基本的に不要
書式送り 改ページし、次のページの先頭に移動すること。
ガーベジコレクション(garbage collection) 参照先がnullであるオブジェクトを自動的に解放し、
利用可能領域を拡げること。
フィールド(field) クラス内で利用可能な変数。
局所変数(local variable) ローカル変数メソッド内で利用可能な変数。
シグネチャ(signature) 識別子仮引数の個数仮引数の型の3つの組み合わせ。
カプセル化(encapsulation) 非公開であるフィールドフィールドの値を利用するメソッドを連携させること。
ユーティリティクラス(utility class) クラスメソッドクラス変数のみを提供するクラス。
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?