مقدمة
تقدم هذه المقالة بشكل أساسي المحتوى ذي الصلة حول عدد صحيح في Java ، ويشاركه للرجوع إليه وتعلمك. لن أقول الكثير أدناه ، دعنا نلقي نظرة على المقدمة التفصيلية معًا.
الطفيليات الحقيقية
قبل بضعة أيام ، رأيت مقالًا شاركته لحظاتي "آلية نقل المعلمات لوظائف Java - هل تفهمها حقًا؟》
تمت دراسة بعض المشغلات في عدد صحيح من Java من قبل ، لذلك كتبت هذا المقال ، على أمل أن يكون مفيدًا لك.
تبادل
دعونا نلقي نظرة أولاً على مثال.
يرجى استخدام Java لإكمال وظيفة المبادلة وتبادل قيم نوعين من عدد صحيح.
اختبار الفراغ الثابت العام () يلقي الاستثناء {integer a = 1 ، b = 2 ؛ مبادلة (أ ، ب) ؛ system.out.println ("a =" + a + "، b =" + b) ؛} تبديل الفراغ الثابت (عدد صحيح ، integer b) {// الأجزاء التي يجب تنفيذها} أولاً
إذا كنت لا تفهم كيف يتم تخصيص كائنات Java في الذاكرة وكيف تمرير الأساليب معلمات ، فيمكنك كتابة الكود التالي.
SWAPONE الثابتة العامة (INTEGER A ، INTEGER B) يلقي الاستثناء {Integer atempvalue = a ؛ أ = ب ؛ ب = atempvalue ؛} تظهر نتائج التشغيل أنه لا يتم تبادل القيم A و B.
لذلك دعونا نلقي نظرة على كيفية تخصيص كائنات Java في الذاكرة عند تشغيل البرنامج أعلاه:
تعيين عنوان الكائن
من هذا يمكننا أن نرى أن الجداول المتغيرة المحلية للطريقتين تحمل إشارات إلى عناوين البيانات الفعلية للكائنات A و B.
تعمل وظيفة المبادلة التي تم تنفيذها أعلاه على تبادل الإشارات فقط إلى المتغير المحلي A والمتغير المحلي B في وظيفة المبادلة ، ولا تتبادل البيانات الفعلية في كومة JVM.
لذلك ، لا يتم تبادل البيانات المشار إليها بواسطة A و B في الوظيفة الرئيسية ، وبالتالي فإن A و B للمتغيرات المحلية في الوظيفة الرئيسية لن تتغير.
فكيف تعمل عند تبادل البيانات في الوظيفة الرئيسية؟
المرة الثانية
وفقًا للممارسة أعلاه ، هل يمكننا التفكير في تبادل قيم البيانات A و B على كومة JVM؟
دعنا نتعرف بإيجاز عن كائن عدد صحيح. يحتوي فقط على قيمة نوع int على مستوى الكائن لتمثيل قيمة الكائن.
لذلك نحن نستخدم الانعكاس لتعديل القيمة ، الرمز هو كما يلي:
public static void swaptwo (integer a1 ، integer b1) يلقي الاستثناء {field valuefield = integer.class.getDeclaredfield ("value") ؛ valuefield.setAccible (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.setAccible (true) ؛ int tempavalue = valuefield.getint (a1) ؛ valuefield.setint (a1 ، b1.intvalue ()) ؛ valuefield.setint (b1 ، tempavalue) ؛} اختبار الفراغ الثابت العام () يلقي الاستثناء {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) ؛}نتائج الإخراج هي كما يلي:
أ = 2 ؛ ب = 1C = 2 ؛ د = 1
مفاجأة أم لا! حادث أم لا! محفز أم لا!
متعمق
ماذا حدث بالضبط؟ دعونا نلقي نظرة على الكود المقلوب:
استخدم المؤلف أداة IDE لإزالة توحيد هذا الملف. class مباشرة
اختبار الفراغ الثابت العام () يلقي الاستثناء {integer a = integer.valueof (1) ؛ عدد صحيح B = integer.valueof (2) ؛ swaptwo (a ، b) ؛ system.out.println ("a =" + a + "؛ b =" + b) ؛ عدد صحيح C = integer.valueof (1) ؛ عدد صحيح d = integer.valueof (2) ؛ system.out.println ("c =" + c + "؛ d =" + d) ؛} في عملية Java تلقائيًا ، يتم استخدام طريقة النوع الأصلي لنوع عدد صحيح Integer.valueOf(int) .
يجب أن تكون هذه الطريقة تغلف بعض العمليات داخليًا ، مما يجعلنا يكون لها تأثير عالمي بعد تعديل Integer.value .
كل هذا ينطوي على الكود في هذا الجزء من الكود يتم لصقه مرة واحدة (PS: المؤلف الذي لا يسحب هو مبرمج جيد):
الفئة العامة integer { / ** * since 1.5 * / public static integer valueof (int i) {if (i> = integercache.low && i <= integercache.high) إرجاع integercache.cache إرجاع عدد صحيح جديد (i) ؛ } integercache integercache {static final int low = -128 ؛ ثابت النهائي int عالية. ذاكرة التخزين المؤقت الثابتة النهائية [] ؛ يمكن تكوين القيمة العالية {// عالية القيمة بواسطة الخاصية int h = 127 ؛ سلسلة 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 ، فتجاهلها. }} عالية = h ؛ ذاكرة التخزين المؤقت = عدد صحيح جديد [(ارتفاع - منخفض) + 1] ؛ int j = low ؛ لـ (int k = 0 ؛ k <cache.length ؛ k ++) ذاكرة التخزين المؤقت [k] = عدد صحيح جديد (j ++) ؛ // Range [-128 ، 127] يجب أن يتم تدريبه (JLS7 5.1.7) تأكيد integercache.high> = 127 ؛ } integercache () {}} كما هو موضح أعلاه ، يحتوي Integer على 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 ] .
أعتقد أنه يجب فهم ذكاءك. إذا كنت لا تفهم ، فيرجى الاتصال بـ 10086 في قسم التعليقات.
حسنًا ، ماذا عن الجزء الذي ليس في [IntegerCache.low~IntegerCache.high) ؟
من الواضح أنهم محظوظون ، وليسوا مخبرين عن طريق integercache ، وفي كل مرة يصلون ، سيقومون بتخصيص قطعة من الأرض (الداخلية) (التوزيع) على JVM.
خيالي
ماذا لو قمت بتغيير المعلمة المحولة إلى الكتابة إلى int؟
إلقاء الفراغ الثابتة العامة () استثناء {int a = 1 ، b = 2 ؛ Swapone (A ، B) ؛ system.out.println ("a =" + a + "، b =" + b) ؛} static void swapone (int a ، int b) {// parts التي تحتاج إلى تنفيذها} مع المهارات الحالية للمؤلف ، لا يوجد حل. يمكن للخبراء ترك رسائل على الحساب الرسمي ، شكرًا جزيلاً لك!
حتى الآن ، تم الانتهاء من جزء المبادلة.
1 + 1
أولاً ، دعونا نلقي نظرة على الكود:
public static void testone () {int one = 1 ؛ int اثنين = واحد + واحد ؛ System.out.printf ("Two = ٪ D" ، اثنان) ؛} ما هو الإخراج؟
إذا قلت 2 للتأكد ، فقد تعلمت ذلك عبثا ، يرجى الاتصال 95169 مباشرة.
أستطيع أن أخبرك بالتأكيد أنه يمكن أن يكون أي قيمة في [Integer.MIN_VALUE~Integer.MAX_VALUE] .
مفاجأة أم لا! حادث أم لا! محفز أم لا!
دعنا نضرب رمز الشواء واحدًا تلو الآخر.
استخدم المؤلف أداة IDE لإزالة توحيد هذا الملف. class مباشرة
public static void testone () {int one = 1 ؛ int اثنين = واحد + واحد ؛ System.out.printf ("Two = ٪ D" ، اثنان) ؛} لم يتصل المتغير اثنان هنا في teger.valueOf(int) ، وهو ما يختلف عما تخيلته. أظن أن هذا هو وعاء IDE.
لذلك تحقق من رمز byteced المترجم بشكل حاسم. فيما يلي بعض الأشرطة المقتطفات:
LDC "two = ٪ 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) مرة واحدة ، ولكن يتم إنشاء مجموعة من الكائن أيضًا.
يجب أن يبدو رمز Java الكامل هكذا:
public static void testone () {int one = 1 ؛ int اثنين = واحد + واحد ؛ Object [] params = {integer.valueof (اثنين)} ؛ system.out.printf ("two = ٪ d" ، params) ؛} لذا ، فقط قم بتعديل قيمة Integer.IntegerCache.cache[2+128] قبل استدعاء الطريقة ، لذا أضف بعض التعليمات البرمجية إلى جزء التهيئة الثابتة للفئة.
الفئة العامة OnePlusone {static {try {class <؟> cacheclazz = class.forname ("java.lang.integer $ integercache") ؛ Field cachefield = cacheclazz.getDeclaredField ("cache") ؛ cachefield.setAccessible (صحيح) ؛ integer [] cache = (integer []) cachefield.get (null) ؛ // تغيير هنا إلى 1 + 1 = 3 ذاكرة التخزين المؤقت [2 + 128] = عدد صحيح جديد (3) ؛ } catch (استثناء e) {E.PrintStackTrace () ؛ }} public static void testone () {int one = 1 ؛ int اثنين = واحد + واحد ؛ System.out.printf ("اثنين = ٪ d" ، اثنان) ؛ }}اثنان == 2؟
بعد تعديل قيمة Integer.IntegerCache.cache[2 + 128] ، هل المتغير يساوي 2؟
public static void testtwo () {int one = 1 ؛ int اثنين = واحد + واحد ؛ System.out.println (اثنان == 2) ؛ system.out.println (integer.valueof (اثنين) == 2) ؛}إخراج الرمز أعلاه كما يلي
Truefalse
نظرًا لأن اثنين == 2 لا يتضمن تحويل الملاكمة الصحيح ، أو مقارنة بين النوع الأصلي ، فإن 2 من النوع الأصلي يساوي دائمًا 2.
الشكل الحقيقي من Integer.valueOf(two)==2 Integer.valueOf(two).intValue == 2
هنا يمكننا أن نرى أنه إذا قارنت قيمة فارغة مع متغير عدد صحيح مع متغير int مع علامة مزدوجة متساوية ، فسيتم طرح NullPointException.
أي نوع من الإخراج سيكون إذا تم استبدال الطريقة هنا بـ System.out.println("Two=" + two) ؟ يمكنك تجربته.
PostScript
xcache
| نوع | هل هناك ذاكرة التخزين المؤقت | الحد الأدنى القيمة | القيمة القصوى |
|---|---|---|---|
| منطقية | لا أحد | - | - |
| بايت | Bytecache | -128 | 127 (ثابت) |
| قصير | shortcache | -128 | 127 (ثابت) |
| شخصية | الحرف | 0 | 127 (ثابت) |
| عدد صحيح | integercache | -128 | java.lang.integer.integercache.high |
| طويل | Longcache | -128 | 127 (ثابت) |
| يطفو | لا أحد | - | - |
| مزدوج | لا أحد | - | - |
java.lang.integer.integercache.high
بعد قراءة طريقة الحصول على ارتفاع sun.misc.VM.getSavedProperty فئة integercache ، قد يكون لديك الأسئلة التالية. لن نؤخر ونستخدم طريقة إجابات واحدة.
1. كيف تمر هذه القيمة في JVM؟
مثل خصائص النظام ، عند بدء تشغيل JVM ، يتم تمريره عن طريق الإعداد -Djava.lang.Integer.IntegerCache.high=xxx .
2. ما هو الفرق بين هذه الطريقة و System.getProperty ؟
من أجل التمييز بين المعلمات التي يتطلبها نظام JVM من المعلمات المستخدمة من قبل المستخدم ،
عند بدء تشغيل java.lang.System.initializeSystemClass ، سيتم حفظ معلمات بدء التشغيل في مكانين:
2.1 يتم حفظ معلمات النظام التي تلقاها جميع JVMs في Sun.Misc.vM.SavedProps.
عند بدء تشغيل JVM ، يطلق على طريقة java.lang.System.initializeSystemClass لتهيئة الخاصية.
في الوقت نفسه ، سيتم أيضًا استدعاء طريقة sun.misc.VM.saveAndRemoveProperties لحذف الخصائص التالية من java.lang.System.props :
الخصائص المذكورة أعلاه هي جميع معلمات النظام التي يجب تعيينها لبدء تشغيل JVM ، لذلك لاعتبارات الأمان واعتبارات العزل ، افصلها عن النظام الذي يمكن الوصول إليه من قبل المستخدم.
2.2 حفظ المعلمات الأخرى باستثناء المعلمات التالية المطلوبة لبدء JVM في java.lang.system.props.
ملاحظة: JDK 1.8.0_91 المستخدم من قبل المؤلف
integercache for Java 9
تخيل لو ظهرت لعبة Naughty Gameplay في حزمة تبعية الطرف الثالث ، فستكون هناك بالتأكيد مجموعة من المبرمجين الذين سيصابون بالجنون (من فضلك لا تجرب مثل هذه اللعبة السيئة ، والعواقب خطيرة للغاية).
لحسن الحظ ، قامت Java 9 بتقييد هذا. يمكنك كتابة ملف module-info.java في الوحدة النمطية المقابلة ، والذي يقيد استخدام الانعكاس للوصول إلى الأعضاء ، وما إلى ذلك. بعد الإعلان حسب الحاجة ، يمكن للرمز الوصول فقط إلى حقول وطرق وغيرها من المعلومات التي يمكن الوصول إليها عن طريق التفكير. فقط عندما يكون الفصل في نفس الوحدة ، أو فتحت الوحدة حزمة للوصول إلى الانعكاس. لمزيد من التفاصيل ، يرجى الرجوع إلى المقالة:
تعديل integercache في Java 9؟
بفضل ليديا وأسوكا على نصيحتهما القيمة والعمل الشاق على تصحيح التجارب.
أخيرًا ، أود أن أشارككم مشكلة لا تولي اهتمامًا بقيمة عدد صحيح في Java:
دعونا نلقي نظرة أولاً على مقتطف الرمز:
الفراغ الثابت العام (سلسلة [] 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 = عدد صحيح جديد (60) ؛ عدد صحيح B3 = 60 ؛ System.out.println ("3: ="+(A3 == B3)) ؛ عدد صحيح A3 = عدد صحيح جديد (60) ؛ عدد صحيح B3 = 60 ؛ System.out.println ("3: ="+(A3 == B3)) ؛ عدد صحيح A4 = 129 ؛ عدد صحيح B4 = 129 ؛ System.out.println ("4: ="+(A4 == B4)) ؛ } إذا لم يتم تنفيذ نتيجة المقارنة لهذا الرمز ، فلا أعرف ما هي الإجابات في ذهنك.
لمعرفة هذه الإجابة ، فإنه ينطوي على مشكلات Java Buffer و Cheap.
في Java ، يعد نوع عدد صحيح مخزنًا للأرقام بين -128-127 ، لذلك يتسق مع العلامة المتساوية. ولكن بالنسبة للأرقام ليست في هذا النطاق ، فهي جديدة في الكومة. لذلك ، فإن مساحة العنوان مختلفة ، لذلك ليست متساوية.
Integer b3=60 ، هذه عملية تعبئة ، أي Integer b3=Integer.valueOf(60)
لذلك ، في المستقبل ، عندما تواجه عدد صحيح ، تحتاج إلى استخدام intValue() لمقارنة ما إذا كانت القيم متساوية.
لا يوجد عازلة للمضاعفة.
إجابة
1: = صحيح
2: = صحيح
3: = خطأ
4: = خطأ
لخص
ما سبق هو المحتوى الكامل لهذه المقالة. آمل أن يكون لمحتوى هذه المقالة قيمة مرجعية معينة لدراسة أو عمل الجميع. إذا كان لديك أي أسئلة ، فيمكنك ترك رسالة للتواصل. شكرا لك على دعمك إلى wulin.com.