序文
この記事では、主にJavaのIntegerに関する関連コンテンツを紹介し、参照と学習のためにそれを共有しています。以下ではあまり言いません。詳細な紹介を一緒に見てみましょう。
本当の寄生虫
数日前、私は「Java関数のパラメーター伝送メカニズム」という瞬間が共有している記事を見ました。
一部のトリガーはJavaの整数で以前に研究されていたので、この記事を書きました。
交換
まず例を見てみましょう。
Javaを使用して、2つの整数タイプのスワップ機能と交換値を完成させてください。
public static void test()throws Exception {integer a = 1、b = 2;スワップ(a、b); System.out.println( "a =" + a + "、b =" + b);} static void swap(integer A、integer b){//実装する必要がある部分}}初め
Javaオブジェクトがメモリでどのように割り当てられ、メソッドがパラメーターをどのように渡すかを理解していない場合は、次のコードを記述できます。
public static void swapone(integer A、integer B)は例外をスローします{integer atempvalue = a; a = b; b = atempvalue;}実行の結果は、値aとbが交換されないことを示しています。
上記のプログラムが実行されたときに、Javaオブジェクトがメモリでどのように割り当てられるかを見てみましょう。
オブジェクトアドレスの割り当て
これから、2つの方法のローカル変数テーブルには、オブジェクトAおよびbの実際のデータアドレスへの参照があることがわかります。
上記で実装されたスワップ関数は、スワップ関数のローカル変数Aとローカル変数Bへの参照のみを交換し、JVMヒープの実際のデータを交換しません。
したがって、メイン関数のAとBによって参照されるデータは交換されないため、メイン関数の局所変数のAとBは変わりません。
では、メイン関数でデータを交換する際にどのように操作しますか?
二度目
上記の慣行によると、JVMヒープでAとBのデータ値を交換することを検討できますか?
整数オブジェクトについて簡単に学びましょう。オブジェクトの値を表すためのオブジェクトレベルのint値のみがあります。
したがって、リフレクションを使用して値を変更します。コードは次のとおりです。
public static void swaptwo(integer a1、integer b1)は例外{field valuefield = integer.class.getDeclaredfield( "value"); valuefield.setAccessible(true); int tempavalue = valuefield.getint(a1); valueField.setInt(a1、b1.intvalue()); valuefield.setint(b1、tempavalue);}操作結果は期待に沿っています。
驚き
上記のプログラムが実行された後、 Integer c = 1, d = 2;
サンプルプログラムは次のとおりです。
public static void swaptwo(integer a1、integer b1)は例外{field valuefield = integer.class.getDeclaredfield( "value"); valuefield.setAccessible(true); int tempavalue = valuefield.getint(a1); valueField.setInt(a1、b1.intvalue()); ValueField.SetInt(B1、Tempavalue);} public static void testthree()throws Exception {integer a = 1、b = 2; swaptwo(a、b); System.out.println( "a =" + a + "; b =" + b);整数c = 1、d = 2; System.out.println( "c =" + c + "; d =" + d);}出力の結果は次のとおりです。
a = 2; b = 1c = 2; d = 1
驚きかどうか!事故かどうか!刺激的かどうか!
詳細
正確に何が起こったのですか?分解されたコードを見てみましょう。
著者はIDEツールを使用してこの.classファイルを直接逆コンパイルしました
public static void testthree()スロー例外{integer a = integer.valueof(1);整数b = integer.valueof(2); swaptwo(a、b); System.out.println( "a =" + a + "; b =" + b); integer c = integer.valueof(1); integer d = integer.valueof(2); System.out.println( "c =" + c + "; d =" + d);} JavaのプロセスではInteger.valueOf(int)型に自動的にボクシングします。
この方法は、一部の操作を内部的にカプセル化し、 Integer.valueを変更した後にグローバルな影響を与える原因となることであるに違いありません。
これにはすべて、コードのこの部分のコードが一度に接着されます(PS:ドラッグしない著者は良いコーダーです):
public class integer { / ** * @since 1.5 * / public static integer valueof(int i){if(i> = integercache.low && i <= integercache.high)return integercache.cache [i +(-integercache.low)];新しい整数(i)を返します。 } private static class integercache {static final int low = -128;静的な最終int high;静的最終整数キャッシュ[]; static {//高い値は、プロパティint h = 127で構成できます。 string integercachehighpropvalue = sun.misc.vm.getSavedProperty( "java.lang.integer.integercache.high"); if(integercachehighpropvalue!= null){try {int i = parseint(integercachehighpropvalue); i = math.max(i、127); //最大配列サイズはinteger.max_value h = math.min(i、integer.max_value-(-low)-1); } catch(numberformatexception nfe){//プロパティをintに解析できない場合は、無視してください。 }} high = h; cache = new Integer [(high -low) + 1]; int j = low; for(int k = 0; k <cache.length; k ++)cache [k] = new Integer(j ++); //範囲[-128、127]はインターンしなければなりません(JLS7 5.1.7)Assert IntegerCache.high> = 127; } private integercache(){}}上記のように、整数には内部にプライベートな静的クラスの整数があり、 Integer.IntegerCache.lowをjava.lang.Integer.IntegerCache.highに含む整数配列を静的に初期化します。
java.lang.Integer.IntegerCache.highの値範囲は[127~Integer.MAX_VALUE - (-low) -1]の間の間です。
Integer.valueOf(int)関数によって返されるすべてのオブジェクトは、int値に基づいて計算され、配列Integer.IntegerCache.cacheから取得されます。オブジェクトは同じであり、新しいオブジェクトは作成されません。
したがって、 Integer.valueOf(1)の値を変更すると、 Integer.IntegerCache.cache[ 1 - IntegerCache.low ]のすべての戻り値が変更されます。
私はあなたのIQが理解されるべきだと思います。わからない場合は、コメントセクションで10086に電話してください。
わかりました、それで、 [IntegerCache.low~IntegerCache.high)にない部分はどうですか?
明らかに、彼らは幸運であり、integercacheによってキャッシュされていません、そして、彼らが到着するたびに、彼らはJVMに地球(内陸)(分布)を割り当てます。
空想
変換されたパラメーターをタイプに変更した場合はどうなりますか?
public static void testone()スロー例外{int a = 1、b = 2; Swapone(a、b); System.out.println( "a =" + a + "、b =" + b);} static void swapone(int a、int b){//実装する必要がある部分}}著者の現在のスキルでは、解決策はありません。専門家は公式アカウントにメッセージを残すことができます、どうもありがとうございました!
これまでのところ、スワップパーツが終了しました。
1 + 1
まず、コードを見てみましょう。
public static void testone(){int one = 1; int 2 = one + one; System.out.printf( "2 =%d"、2);}出力とは何ですか?
確かに2と言ったら、それを無駄に学んだことがあります。95169に直接電話してください。
[Integer.MIN_VALUE~Integer.MAX_VALUE]間隔の任意の値になる可能性があることを確認できます。
驚きかどうか!事故かどうか!刺激的かどうか!
ローストコードを1つずつストロークしましょう。
著者はIDEツールを使用してこの.classファイルを直接逆コンパイルしました
public static void testone(){int one = 1; int 2 = one + one; System.out.printf( "2 =%d"、2);}ここでの変数2は、 teger.valueOf(int)を呼び出しませんでした。これは私が想像したものとは異なります。これはIDEのポットだと思います。
コンパイルされたバイトコードを決定的に確認してください。以下は、抜粋のバイトコードの一部です。
ldc "2 =%d" iconst_1anewarray java/lang/objectdupiconst_0iload 2invokestatic java/lang/integer.valueof(i)ljava/lang/integer; (ljava/lang/string; [ljava/lang/object;)ljava/io/printstream; pop
それは確かにIDEのポットであることがわかります。 Integer.valueOf(int)が1回呼び出されるだけでなく、オブジェクトの配列も作成されます。
完全なJavaコードは次のようになります。
public static void testone(){int one = 1; int 2 = one + one; object [] params = {integer.valueof(2)}; System.out.printf( "2 =%d"、params);}そのため、メソッドが呼び出される前に、 Integer.IntegerCache.cache[2+128]の値を変更するだけで、クラスの静的初期化部分にコードを追加してください。
public class oneplusone {static {try {class <?> cacheclazz = class.forname( "java.lang.integer $ integercache"); field cachefield = cacheclazz.getDeclaredfield( "Cache"); cachefield.setAccessible(true); integer [] cache =(integer [])cachefield.get(null); //ここで1 + 1 = 3キャッシュ[2 + 128] = new Integer(3)に変更します。 } catch(Exception e){e.printstacktrace(); }} public static void testone(){int one = 1; int 2 = one + one; System.out.printf( "2 =%d"、2); }}2 == 2?
Integer.IntegerCache.cache[2 + 128]の値を変更した後、変数2は2に等しいですか?
public static void testtwo(){int one = 1; int 2 = one + one; System.out.println(2 == 2); System.out.println(integer.valueof(2)== 2);}上記のコード出力は次のとおりです
TrueFalse
2 == 2には整数ボクシングの変換、または元のタイプの比較は含まれないため、元のタイプの2は常に2に等しくなります。
Integer.valueOf(two)==2の実際の形式はInteger.valueOf(two).intValue == 2 、つまり3 == 2、つまりfalseです。
ここでは、nullの値を整数変数と二重の等記号を持つINT変数と比較すると、nullpointExceptionがスローされることがわかります。
ここの方法がSystem.out.println("Two=" + two)に置き換えられた場合、どのような出力が出力されますか?あなたはそれを試すことができます。
ポストスクリプト
xcache
| 親切 | キャッシュはありますか | 最小値 | 最大値 |
|---|---|---|---|
| ブール | なし | - | - |
| バイト | bytecache | -128 | 127(修正) |
| 短い | ショートキャッシュ | -128 | 127(修正) |
| キャラクター | CharacterCache | 0 | 127(修正) |
| 整数 | integercache | -128 | java.lang.integer.integercache.high |
| 長い | longcache | -128 | 127(修正) |
| フロート | なし | - | - |
| ダブル | なし | - | - |
java.lang.integer.integercache.high
integercacheクラスsun.misc.VM.getSavedProperty高くなる方法を読んだ後、次の質問があるかもしれません。 1つの質問1回の方法を遅らせて使用しません。
1.この値をJVMに渡す方法は?
システムプロパティと同様に、JVMが起動すると、 -Djava.lang.Integer.IntegerCache.high=xxx設定して渡されます。
2。この方法とSystem.getPropertyの違いは何ですか?
JVMシステムに必要なパラメーターをユーザーが使用するパラメーターと区別するために、
java.lang.System.initializeSystemClassが開始されると、スタートアップパラメーターは2つの場所で保存されます。
2.1すべてのJVMが受信したシステムパラメーターは、sun.misc.vm.savedpropsで保存されます。
JVMが起動すると、 java.lang.System.initializeSystemClassメソッドを呼び出してプロパティを初期化します。
同時に、 sun.misc.VM.saveAndRemovePropertiesメソッドも呼び出され、 java.lang.System.propsから次のプロパティを削除します。
上記のプロパティはすべて、JVMスタートアップに設定する必要があるシステムパラメーターであるため、セキュリティ上の考慮事項と分離に関する考慮事項については、ユーザーアクセス可能なSystem.Propsから分離します。
2.2 java.lang.system.propsのJVMスタートアップに必要な以下のパラメーターを除き、他のパラメーターを保存します。
PS:著者が使用するJDK 1.8.0_91
Java 9のintegercache
上記のいたずらなゲームプレイがサードパーティの依存関係パッケージに表示されている場合、間違いなく夢中になるプログラマーのグループがあります(このような悪いゲームプレイを試してはいけません。結果は非常に深刻です)。
幸いなことに、Java 9はこれを制限しています。対応するモジュールにモジュールinfo.javaファイルを記述することができます。これは、必要に応じて宣言の後に、反射の使用を制限するメンバーなどを制限することができます。コードは、リフレクションでアクセスできるフィールド、メソッド、およびその他の情報のみにアクセスできます。クラスが同じモジュールにある場合のみ、またはモジュールが反射アクセスのためのパッケージを開いた場合。詳細については、記事を参照してください。
Java 9でintegercacheを変更しますか?
貴重なアドバイスと校正に関する努力をしてくれたLydiaとAsukaに感謝します。
最後に、Javaの整数価値に注意を払わない問題をあなたと共有したいと思います。
まずコードスニペットを見てみましょう:
public static void main(string [] args){integer a1 = integer.valueof(60); // danielinbiti integer b1 = 60; System.out.println( "1:="+(a1 == b1));整数A2 = 60;整数B2 = 60; System.out.println( "2:="+(a2 == b2));整数a3 = new Integer(60);整数B3 = 60; System.out.println( "3:="+(a3 == b3));整数a3 = new Integer(60);整数B3 = 60; System.out.println( "3:="+(a3 == b3));整数A4 = 129;整数B4 = 129; System.out.println( "4:="+(a4 == b4)); }このコードの比較結果が実行されない場合、答えがあなたの心にあるかどうかはわかりません。
この答えを知るために、Javaバッファーとヒープの問題が含まれます。
Javaでは、整数タイプは-128-127の間の数値のバッファーであるため、等号と一致しています。しかし、この範囲ではない数字については、それらはヒープで新しいものです。したがって、アドレス空間は異なるため、等しくありません。
Integer b3=60 、これは梱包プロセスです。つまり、 Integer b3=Integer.valueOf(60)
したがって、将来、整数に遭遇すると、 intValue()を使用して、値が等しいかどうかを比較する必要があります。
ダブルのバッファーはありません。
答え
1:= true
2:= true
3:= false
4:= false
要約します
上記は、この記事のコンテンツ全体です。この記事の内容には、すべての人の研究や仕事に特定の参照値があることを願っています。ご質問がある場合は、メッセージを残してコミュニケーションをとることができます。 wulin.comへのご支援ありがとうございます。