Boxing (computer programming)
In computer science, boxing (a.k.a. wrapping) is the transformation of placing a primitive type within an object so that the value can be used as a reference. Unboxing is the reverse transformation of extracting the primitive value from its wrapper object. Autoboxing is the term for automatically applying boxing and/or unboxing transformations as needed.
Boxing
Boxing's most prominent use is in Java where there is a distinction between reference and value types for reasons such as runtime efficiency and syntax and semantic issues. In Java, a LinkedList<T> must be such that T is an instance of Object. One might desire to have a LinkedList<int>, but this is not directly possible. Instead Java defines primitive wrapper classes corresponding to each primitive type: Integer and int, Character and char, Float and float, etc. Using generic parameterized types introduced in Java Platform, Standard Edition (J2SE) 5.0, one can then define a LinkedList<Integer> and insert int values into the list by boxing them as Integer objects.
On the other hand, C# has no primitive wrapper classes, but allows boxing of any value type, returning a generic Object reference. In Objective-C, any primitive value can be prefixed by a @ to make an NSNumber out of it (e.g. @123 or @(123)). This allows for adding them in any of the standard collections, such as an NSArray.
Haskell has little or no notion of reference type, but still uses the term "boxed" for the runtime system's uniform pointer-to-tagged union representation.[1]
The boxed object is always a copy of the value object, and is usually immutable. Unboxing the object also returns a copy of the stored value. Repeated boxing and unboxing of objects can have a severe performance impact, because boxing dynamically allocates new objects and unboxing (if the boxed value is no longer used) then makes them eligible for garbage collection. However, modern garbage collectors such as the default Java HotSpot garbage collector can more efficiently collect short-lived objects, so if the boxed objects are short-lived, the performance impact may not be severe.
في بعض لغات البرمجة، يوجد تكافؤ مباشر بين نوع بيانات أولي غير مُغلّف ومرجع إلى نوع كائن مُغلّف غير قابل للتغيير. في الواقع، يُمكن استبدال جميع أنواع البيانات الأولية في البرنامج بأنواع كائنات مُغلّفة. فبينما يؤدي إسناد قيمة من نوع بيانات أولي إلى آخر إلى نسخ قيمته، فإن إسناد قيمة مرجع إلى كائن مُغلّف إلى آخر يؤدي إلى نسخ قيمة المرجع للإشارة إلى نفس الكائن الذي يشير إليه المرجع الأول. مع ذلك، لن يُسبب هذا أي مشاكل، لأن الكائنات غير قابلة للتغيير، وبالتالي لا يوجد فرق دلالي حقيقي بين مرجعين لنفس الكائن أو لكائنين مختلفين (إلا إذا نظرنا إلى التساوي الفيزيائي). بالنسبة لجميع العمليات الأخرى غير الإسناد، مثل العمليات الحسابية والمقارنة والمعاملات المنطقية، يُمكن فك تغليف النوع المُغلّف، وإجراء العملية، ثم إعادة تغليف النتيجة حسب الحاجة. وبالتالي، يُمكن الاستغناء عن تخزين أنواع البيانات الأولية تمامًا.
نظام الدفع التلقائي
التحويل التلقائي للأنواع هو مصطلح يُستخدم لوصف استخراج نوع مرجعي من نوع قيمة بمجرد تحويل النوع (سواء كان ضمنيًا أو صريحًا). يقوم المترجم تلقائيًا بتوفير الشيفرة المصدرية الإضافية اللازمة لإنشاء الكائن.
على سبيل المثال، في إصدارات جافا السابقة لـ J2SE 5.0، لم يتم تجميع الكود التالي:
Integer i = new Integer ( 9 ); Integer i = 9 ; // خطأ في الإصدارات السابقة للإصدار 5.0!لم تكن المترجمات قبل الإصدار 5.0 تقبل السطر الأخير. هي كائنات مرجعية، لا تختلف ظاهريًا عن و وما إلى ذلك. لتحويل من إلى ، كان يجب إنشاء كائن Integer يدويًا. بدءًا من J2SE 5.0، سيقبل المترجم السطر الأخير، ويحوله تلقائيًا لإنشاء كائن Integer لتخزين القيمة . [ 2 ] هذا يعني أنه بدءًا من J2SE 5.0، سيتم تجميع شيء مثل ، حيث و هما بالفعل - يتم فك تغليف a و b، وجمع قيم الأعداد الصحيحة، ثم يتم تغليف النتيجة تلقائيًا في كائن جديد ، والذي يتم تخزينه أخيرًا داخل المتغير . لا يمكن استخدام عوامل المساواة بهذه الطريقة، لأنها مُعرّفة بالفعل لأنواع المراجع، لمساواة المراجع؛ لاختبار مساواة القيمة في نوع مُغلّف، يجب فك تغليفها يدويًا ومقارنة القيم الأولية، أو استخدام الطريقة .IntegerListObjectintInteger9Integerc=a+babIntegerIntegercObjects.equals
مثال آخر: يسمح J2SE 5.0 للمبرمج بالتعامل مع مجموعة (مثل `<a>` ) كما لو كانت تحتوي على قيم بدلاً من كائنات. هذا لا يتعارض مع ما ذُكر سابقًا: فالمجموعة لا تزال تحتوي فقط على مراجع لكائنات ديناميكية، ولا يمكنها سرد أنواع البيانات الأولية. لا يمكن أن تكون `<a>` ، بل يجب أن تكون `<a>` . مع ذلك، يقوم المُصرّف تلقائيًا بتحويل الكود بحيث تستقبل القائمة `<a>` كائنات "بصمت"، بينما يذكر الكود المصدري القيم الأولية فقط. على سبيل المثال، يمكن للمبرمج الآن كتابة الكود والتفكير كما لو تمت إضافة `<a>` إلى القائمة؛ لكن المُصرّف سيُحوّل السطر فعليًا إلى `<a>` .LinkedListintIntegerLinkedList<int>LinkedList<Integer>list.add(3)int3list.add(newInteger(3))
فتح العلبة تلقائياً
مع خاصية فك التغليف التلقائي، يقوم المترجم تلقائيًا بتوفير التعليمات البرمجية المصدرية الإضافية التي تسترجع القيمة من هذا الكائن، إما عن طريق استدعاء طريقة ما على هذا الكائن، أو بوسائل أخرى.
على سبيل المثال، في إصدارات جافا السابقة لـ J2SE 5.0، لم يتم تجميع الكود التالي:
Integer k = new Integer ( 4 ); int l = k.intValue ( ); // صحيح دائمًا int m = k ; // كان سيُسبب خطأً، لكنه صحيح الآنلا تدعم لغة C# فك التغليف التلقائي بنفس معنى لغة Java، لأنها لا تحتوي على مجموعة منفصلة من الأنواع الأولية وأنواع الكائنات. جميع الأنواع التي لها إصدارات أولية وأخرى كائنية في Java، يتم تنفيذها تلقائيًا بواسطة مُصرّف C# إما كأنواع أولية (قيم) أو كأنواع كائنية (مرجعية).
في كلتا اللغتين، لا يقوم التحويل التلقائي للأنواع بتحويل الأنواع إلى أنواع فرعية تلقائيًا، أي أن الكود التالي لن يتم تجميعه:
سي شارب:
int i = 42 ; object o = i ; // تغليف int j = o ; // فك التغليف (خطأ) Console.WriteLine ( j ) ; // سطر غير قابل للوصول، ربما توقع المؤلف الناتج "42"جافا:
int i = 42 ; Object o = i ; // تغليف int j = o ; // فك التغليف (خطأ) System.out.println ( j ) ; // سطر غير قابل للوصول ، ربما توقع المؤلف الناتج "42 "الملاكمة في الصدأ
يحتوي RustBox على النوع الذي يمثل قيمة مملوكة بشكل فريد ومخصصة في الذاكرة الديناميكية: [ 3 ]
let number : Box < i32 > = Box :: new ( 42 );std::boxed::Boxفي لغة Rust يعادل std::unique_ptrفي لغة C++ ، وهو نوع من المؤشر الذكي .
باستخدام std :: unique_ptr ؛unique_ptr < int > number = std :: make_unique < int > ( 42 );إذا كانت القيمة بحاجة إلى ملكية مشتركة (مثلاً بين الخيوط)، فيمكن استخدام `<input>` Arc، الذي يمثل قيمة مُخصصة في الذاكرة الديناميكية مع عدّ المراجع. [ 4 ] [ 5 ] وهذا مشابه لـ `<input>` std::shared_ptrفي لغة C++.
مساعدو الكتابة
يحتوي Modern Object Pascal على طريقة أخرى لإجراء العمليات على الأنواع البسيطة، قريبة من التغليف، تسمى مساعدي النوع في Free Pascal أو مساعدي السجل في Delphi و Free Pascal في وضع Delphi.
اللهجات المذكورة هي لغات برمجة تعتمد على لغة أوبجكت باسكال وتُترجم إلى لغة أصلية، ولذلك تفتقر إلى بعض الميزات التي يمكن للغة سي شارب وجافا تنفيذها. ومن أبرزها استنتاج نوع البيانات في وقت التشغيل للمتغيرات ذات الأنواع المحددة بدقة .
لكن هذه الخاصية مرتبطة بالملاكمة. فهي تسمح باستخدام تركيبات مثل:
{$ifdef fpc}{$mode delphi}{$endif} uses sysutils ; // تحتوي هذه الوحدة على أغلفة للأنواع البسيطة var x : integer = 100 ; s : string ; begin s := x . ToString ; writeln ( s ) ; end .مراجع
- ↑ "7.2. الأنواع غير المعبأة والعمليات الأولية" . downloads.haskell.org . تم الاطلاع عليه بتاريخ 10 أغسطس 2022 .
- ↑ دليل لغة جافا على موقع أوراكل (oracle.com) حول التغليف التلقائي
- ↑ "std::boxed - Rust" . doc.rust-lang.org . تم الاطلاع عليه في 2 يونيو 2025 .
- ↑ "Arc in std::sync - Rust" . doc.rust-lang.org . تم الاطلاع عليه بتاريخ 18 يناير 2025 .
- ↑ "Arc - Rust By Example" . doc.rust-lang.org . تم الاطلاع عليه بتاريخ 18 يناير 2025 .
- أنواع البيانات
- جافا (لغة برمجة)
- مفاهيم لغة البرمجة
- مقارنات لغات البرمجة
