Javaプログラミングの基礎--変数、定数と定数プール【知識体系構築シリーズ】

8879 ワード

変数#ヘンスウ#
変数はプログラムの基本的な構成部分です.Javaプログラミングでは、宣言された変数ごとにタイプを割り当てる必要があります.Java宣言変数は次のとおりです.
int a;
double b = 1.1;

変数は位置によって異なる性質を持っているので、表で理解してみましょう.
メンバー変数
ローカル変数
せいてきへんすう
場所の定義
クラス内、メソッド外
メソッド内またはメソッドのパラメータ
初期化値
デフォルト初期化値あり
いいえ、使用する前に定義して値を割り当てます.
コールモード
オブジェクト呼び出し
-
きおくいち
スタック
スタック内
ライフサイクル
オブジェクトとの共存
方法と共に存亡する.
別名#ベツメイ#
インスタンス変数
-
定数
プログラム実行中に値を変更できない量を定数(constant)と呼ぶ.定数はfinal修飾メンバー変数で表されます.
定数プール
定数プールとは何ですか?
よく使う定数を一定の領域に格納し、必要に応じて直接取り出すことで使用できます.これと同様の概念は,スレッドプール,データベース接続プールなどである.
定数プールのメリット
定数プールは、頻繁にオブジェクトを作成および破棄することによってシステムのパフォーマンスに影響を及ぼすことを回避するために、オブジェクトの共有を実現します.たとえば、文字列定数プールでは、コンパイルフェーズですべての文字列文字を定数プールに配置します.
  • メモリ領域の節約:定数プール内の同じ文字列定数はすべて統合され、1つの領域しか占有されません.
  • 実行時間の節約:文字列を比較すると、==equals()より速くなります.2つの参照変数については,==のみで参照が等しいか否かを判断し,実際の値が等しいか否かを判断することができる.

  • また、スレッドプール、データベース接続プールには、同じ問題を解決するために存在する同様のメリットがあることがわかります.
    Javaでの定数プール–JVMでの運用
    まず、Classファイルのデータ構造には定数プールという概念があり、魔数「CAFEBABE」、バージョン情報の後に定数プールの情報が格納されます.ここの定数プールにはどんな情報がありますか?文字列、finalとして宣言された定数値など、Java言語レベルの定数の概念に相当する文字列量(Literal)とシンボル参照量(Symbolic References)の2つの定数を格納するのに主に使用され、シンボル参照はコンパイル原理の概要に属し、以下の3つの定数を含む.
  • クラスとインタフェースのフルリミット名
  • フィールド名および記述子
  • メソッド名および記述子
  • また,メソッド領域のランタイムプールには,コンパイル期間に生成された様々な字面量とシンボル参照が格納され,この部分はクラスロード後にメソッド領域に入るランタイムプールに格納される.CLassファイル定数プールに対するランタイムプールのもう1つの重要な特徴は、動的性を備えていることであり、Java言語では定数がコンパイル期間のみ生成される必要はありません.つまり、CLassファイルに予め設定された定数プールの内容がメソッドエリアに入って時々プールをランタイムすることができるわけではありません.ランタイム中に新しい定数をプールに入れることもできます.このような特性が開発者に利用されることが多いのがStringクラスのintern()メソッドである.
    Javaの定数プール–基本タイプのパッケージクラス
    JAvaの基本タイプのパッケージクラスの大部分は、Byte、Short、Integer、Long、Character、Booleanという定数プール技術を実現しています.この5つのパッケージクラスのデフォルトでは、値[-128127]の対応するタイプのキャッシュデータが作成されますが、この範囲を超えても新しいオブジェクトが作成されます.もちろん、新しいオブジェクトでオブジェクトを再インスタンス化すると、キャッシュは使用されません.なぜFloat、Doubleに定数プールがないのでしょうか?もちろんデータ量が大きすぎて、適当な常用データがありません.
    サンプルコードは次のとおりです.
    Integer i1 = 100;
    Integer i2 = 100;
    Integer i3 = new Integer(100);
    Integer i4 = Integer.valueOf(100);
    System.out.println(i1 == i2); //true
    System.out.println(i1 == i3); //false
    System.out.println(i1 == i4); //true
    Integer i5 = 400;
    Integer i6 = 400;
    System.out.println(i5 == i6); //false

    説明:1.Integer i1=40;Javaはコンパイル時に直接コードをInteger i 1=Integerにカプセル化する.valueOf(40);,これにより、定数プール内のオブジェクトが使用されます.2. Integer i1 = new Integer(40);この場合、新しいオブジェクトが作成されます.
    Integer i1 = 40;
    Integer i2 = 40;
    Integer i3 = 0;
    Integer i4 = new Integer(40);
    Integer i5 = new Integer(40);
    Integer i6 = new Integer(0);
    System.out.println("i1=i2 " + (i1 == i2));
    System.out.println("i1=i2+i3 " + (i1 == i2 + i3));
    System.out.println("i1=i4 " + (i1 == i4));
    System.out.println("i4=i5 " + (i4 == i5));
    System.out.println("i4=i5+i6 " + (i4 == i5 + i6));
    System.out.println("40=i5+i6 " + (40 == i5 + i6));

    出力:
    i1=i2 true
    i1=i2+i3 true
    i1=i4 false
    i4=i5 false
    i4=i5+i6 true
    40=i5+i6 true

    説明:文i 4==i 5+i 6、+このオペレータはIntegerオブジェクトに適用されないため、まずi 5とi 6は自動ボックス解除操作を行い、数値加算、すなわちi 4==40を行う.その後Integerオブジェクトは数値と直接比較できないため、i 4は自動的にint値40に、最終的にこの文は40==40に変換して数値比較を行う.
    Javaの定数プール-String
    文字列の割り当ては、他のオブジェクトの割り当てと同様に、時間と空間のコストがかかります.JVMは、パフォーマンスの向上とメモリオーバーヘッドの削減のために、文字列定数をインスタンス化する際にいくつかの最適化を行います.JVMで作成される文字列の数を減らすために、文字列クラスは文字列プールを維持し、コードが文字列定数を作成するたびに、JVMはまず文字列定数プールをチェックします.文字列がすでにプールに存在する場合は、プールのインスタンス参照を返します.文字列がプールにない場合は、文字列がインスタンス化され、プールに配置されます.
    Javaがこのような最適化を行うことができるのは、文字列が可変であるため【ソースコードを表示することができ、Stringは実はfinalの文字配列であり、Stringの修正操作のたびに新しいStringオブジェクトが作成される】ため、データの衝突を心配せずに共有することができる.
    サンプルコード:
    public class Test01 {
        public static void main(String[] args) {
            String str1 = "Hello";
            String str2 = "Hello";
            System.out.println("str1 and str2 are created by using string literal.");
            System.out.println("    str1 == str2 is " + (str1 == str2));
            System.out.println("    str1.equals(str2) is " + str1.equals(str2));
            String str3 = new String("Hello");
            String str4 = new String("Hello");
            System.out.println("str3 and str4 are created by using new operator.");
            System.out.println("    str3 == str4 is " + (str3 == str4));
            System.out.println("    str3.equals(str4) is " + str3.equals(str4));
            String str5 = "Hel" + "lo";
            String str6 = "He" + "llo";
            System.out.println("str5 and str6 are created by using string constant expression.");
            System.out.println("    str5 == str6 is " + (str5 == str6));
            System.out.println("    str5.equals(str6) is " + str5.equals(str6));
            String s = "lo";
            String str7 = "Hel" + s;
            String str8 = "He" + "llo";
            System.out.println("str7 is computed at runtime.");
            System.out.println("str8 is created by using string constant expression.");
            System.out.println("    str7 == str8 is " + (str7 == str8));
            System.out.println("    str7.equals(str8) is " + str7.equals(str8));
        }
    }

    JDK 8バージョン実行出力:
    str1 and str2 are created by using string literal.
        str1 == str2 is true
        str1.equals(str2) is true
    str3 and str4 are created by using new operator.
        str3 == str4 is false
        str3.equals(str4) is true
    str5 and str6 are created by using string constant expression.
        str5 == str6 is true
        str5.equals(str6) is true
    str7 is computed at runtime.
    str8 is created by using string constant expression.
        str7 == str8 is false
        str7.equals(str8) is true
    
    Process finished with exit code 0

    文字列生成の原則:-同じパケットの下にある同じクラスの文字列定数の参照は、同じ文字列オブジェクトを指します.-同じパケットの下にある異なるクラスの文字列定数の参照は、同じ文字列オブジェクトを指します.-異なるパケットの下で異なるクラスの文字列定数の参照は、同じ文字列オブジェクトを指します.-定数式で計算された文字列は、コンパイル時に計算され、定数として扱われます.-実行時に接続によって計算された文字列は新しく作成されたので異なります.-生成された文字列表示internメソッドを呼び出すと,元の同じ内容の文字列定数と同じ結果が得られる.
    参考文献:Java定数プール文字列定数プールとは?