JavaRush /مدونة جافا /Random-AR /Autoboxing وunboxing في جافا
Viacheslav
مستوى

Autoboxing وunboxing في جافا

نشرت في المجموعة
<h2>مقدمة</h2>لغة برمجة، مثل اللغة التي يتحدث بها الناس، يعيشون ويتغيرون، تظهر فيها ظواهر جديدة لجعل اللغة أكثر ملاءمة للاستخدام. وكما نعلم، ينبغي للغة أن تعبر عن أفكارنا بسهولة.
Autoboxing وunboxing في جافا - 1
لذلك، في Java SE 5، تم تقديم آلية الملاكمة/الفتح. ويتم تخصيص برنامج تعليمي منفصل من Oracle لميزات وسيلة التعبير عن الأفكار هذه: Autoboxing و Unboxing . <h2>الملاكمة ذات التعبئة التلقائية</h2>لنلقِ نظرة على مثال للملاكمة ذات التعبئة التلقائية. أولا، دعونا نرى كيف يعمل. دعونا نستخدم موقع Compiljava.net وننشئ فصلًا دراسيًا:
public class App {
    public static void main(String[] args) {
        Integer portNumber = 8080;
        if (args.length != 0) {
            portNumber = Integer.valueOf(args[0]);
        }
        System.out.println("Port number is: " + portNumber);
    }
}
رمز بسيط. يمكننا تحديد معلمة الإدخال وتغيير قيمة المنفذ. كما نرى، لأن نقرأ قيمة المنفذ من Stringالمعلمات، ونحصل Integerعليها عن طريق تمريرها Integer.valueOf. لذلك، نحن مضطرون إلى تحديده ليس كنوع بدائي، ولكن كنوع كائن Integer. وهنا، من ناحية، لدينا متغير كائن، والقيمة الافتراضية هي قيمة أولية. ويعمل. لكننا لا نؤمن بالسحر، أليس كذلك؟ دعونا نلقي نظرة "تحت الغطاء"، كما يقولون. قم بتنزيل الكود المصدري من موقع compiljava.net بالنقر فوق "تنزيل ZIP". بعد ذلك، قم باستخراج الأرشيف الذي تم تنزيله إلى دليل وانتقل إليه. لنقم الآن بما يلي: javap -c -p App.classحيث يكون App.class هو ملف الفصل المترجم لفصلك. سنرى محتوى مثل هذا:
Autoboxing وunboxing في جافا - 2
هذا هو نفس "الرمز الثانوي" سيئ السمعة. لكن ما يهمنا الآن هو ما نراه. أولاً، يتم وضع العنصر الأساسي 8080 على مكدس تنفيذ الطريقة، ثم يتم تنفيذ Integer.valueOf . هذا هو "سحر" الملاكمة. وداخل السحر يبدو كما يلي:
Autoboxing وunboxing في جافا - 3
وهذا يعني أنه سيتم أخذ رقم جديد Integerأو الحصول عليه Integerمن ذاكرة التخزين المؤقت (ذاكرة التخزين المؤقت ليست أكثر من مجرد مجموعة من الأعداد الصحيحة) اعتمادًا على قيمة الرقم. وبطبيعة الحال، Integerلم يكن محظوظا واحدا فقط. توجد قائمة كاملة بالأنواع البدائية ذات الصلة وأغلفتها (الفئات التي تمثل البدائيين في عالم OOP). توجد هذه القائمة في أسفل البرنامج التعليمي من Oracle: " Autoboxing and Unboxing ". تجدر الإشارة على الفور إلى أن المصفوفات المصنوعة من العناصر الأولية لا تحتوي على "غلاف" دون توصيل أي مكتبات تابعة لجهات خارجية. أولئك. Arrays.asListلن يجعل من int[]لنا Listمن Integerالصورة. <h2>فتح العلبة</h2>تسمى العملية العكسية للملاكمة فتح العلبة فتح العلبة. دعونا نلقي نظرة على مثال التفريغ:
public class App {

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Please, enter params");
            return;
        }
      	int value = Math.abs(Integer.valueOf(args[0]));
        System.out.println("Absolute value is: " + value);
    }

}
Math.absيقبل البدائيين فقط. ما يجب القيام به؟ تحتوي فئة المجمع على طريقة خاصة لهذه الحالة تقوم بإرجاع بدائية. على سبيل المثال، هذه هي Integerطريقة intValue . إذا نظرنا إلى رمز البايت، فهو كالتالي:
Autoboxing وunboxing في جافا - 4
على ما يبدو، لا يوجد سحر. كل شيء داخل جافا. إنه يعمل فقط "بنفسه". من أجل راحتنا. <h2>أشعل النار</h2>
Autoboxing وunboxing في جافا - 5
أي أداة، إذا استخدمت بشكل غير صحيح، تصبح سلاحا هائلا ضد نفسها. وآلية الملاكمة/الفتح التلقائية في Java ليست استثناءً. المقارنة الأولى الواضحة تتم من خلال ==. أعتقد أن هذا واضح، ولكن دعونا ننظر إليه مرة أخرى:
public static void main(String[] args) {
    Integer inCacheValue = 127;
    Integer inCacheValue2 = 127;
    Integer notInCache = 128; // new Integer(129)
    Integer notInCache2 = 128; // new Integer(129)
    System.out.println(inCacheValue == inCacheValue2); //true
    System.out.println(notInCache == notInCache2); //false
}
في الحالة الأولى، يتم أخذ القيمة من Integerذاكرة التخزين المؤقت للقيمة (انظر شرح الملاكمة أعلاه)، وفي الحالة الثانية سيتم إنشاء كائن جديد في كل مرة. ولكن هنا يستحق إجراء الحجز. يعتمد هذا السلوك على الحد الأعلى لذاكرة التخزين المؤقت ( java.lang.Integer.IntegerCache.high ). بالإضافة إلى ذلك، قد يتغير هذا الحد بسبب إعدادات أخرى. يمكنك قراءة المناقشة حول هذا الموضوع في stackoverflow: ما حجم ذاكرة التخزين المؤقت الصحيحة؟ وبطبيعة الحال، يجب مقارنة الكائنات باستخدام العناصر المتساوية: System.out.println(notInCache.equals(notInCache2)); المشكلة الثانية المرتبطة بنفس الآلية هي الأداء. أي ملاكمة في Java تعادل إنشاء كائن جديد. إذا لم يتم تضمين الرقم في قيم ذاكرة التخزين المؤقت (أي -128 إلى 127)، فسيتم إنشاء كائن جديد في كل مرة. إذا تم تنفيذ التعبئة والتغليف فجأة (أي الملاكمة) في حلقة، فسيؤدي ذلك إلى زيادة كبيرة في الكائنات غير الضرورية واستهلاك الموارد لعمل جامع البيانات المهملة. لذلك، لا تكن متهورًا جدًا بشأن هذا الأمر. هناك أشعل نار ثالث لا يقل إيلامًا وينبع من نفس الآلية:
public static void check(Integer value) {
    if (value <= 0) {
        throw new IllegalStateException("Value is too small");
    }
}
في هذا الرمز، كان من الواضح أن الشخص يحاول عدم تجاوز الخطأ. ولكن لا يوجد فحص ل null. إذا كان الأمر يتعلق بالإدخال null، فبدلاً من الخطأ المفهوم، سنحصل على خطأ غير مفهوم NullPointerException. لأنه على سبيل المقارنة، ستحاول Java التنفيذ value.intValueوالتعطل، لأن... valueسوف null. <h2>الاستنتاج</h2>تسمح آلية الملاكمة/إلغاء التغليف للمبرمج بكتابة تعليمات برمجية أقل وأحيانًا لا يفكر حتى في التحويل من العناصر الأولية إلى الكائنات والعودة. ولكن هذا لا يعني أنك يجب أن تنسى كيف يعمل. وإلا فقد ترتكب خطأً قد لا يظهر على الفور. لا ينبغي لنا أن نعتمد على أجزاء من النظام ليست تحت سيطرتنا بالكامل (مثل الحدود الصحيحة). لكن لا تنسَ جميع مزايا فئات التغليف (مثل Integer). غالبًا ما تحتوي هذه الفئات المجمعة على مجموعة من الأساليب الثابتة الإضافية التي ستجعل حياتك أفضل ورمزك أكثر تعبيرًا. إليك مثال اللحاق بالركب:
public static void main(String[] args) {
    int first = 1;
    int second = 5;
    System.out.println(Integer.max(first, second));
    System.out.println(Character.toLowerCase('S'));
}
الاستنتاج الصحيح من كل شيء هو أنه لا يوجد سحر، هناك نوع من الإدراك. ولن يكون كل شيء دائمًا كما نتوقعه. على سبيل المثال، لا يوجد تغليف: System.out.println("The number is " + 8); سيتم تحسين المثال أعلاه بواسطة المترجم في سطر واحد. أي كأنك كتبت "الرقم هو 8". وفي المثال أدناه لن يكون هناك أي تغليف أيضًا:
public static void main(String[] args) {
    System.out.println("The number is " + Math.abs(-2));
}
كيف يمكن أن يكون الأمر عندما printlnنأخذ كائنًا كمدخل ونحتاج إلى توصيل الخطوط بطريقة ما. الخطوط... نعم، لهذا السبب لا يوجد تغليف على هذا النحو. هناك Integerطرق ثابتة، ولكن بعضها package. وهذا هو، لا يمكننا استخدامها، ولكن في Java نفسها يمكن استخدامها بنشاط. هذا هو الحال بالضبط هنا. سيتم استدعاء الأسلوب getChars، الذي يقوم بإنشاء مجموعة من الأحرف من الرقم. مرة أخرى، لا يوجد سحر، فقط جافا). لذا، في أي موقف غير واضح، عليك فقط أن تنظر إلى التنفيذ وعلى الأقل سوف يحدث شيء ما في مكانه الصحيح. # فياتشيسلاف
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION