هل الأنواع البدائية مختلفة في Java و C#؟
-
22-09-2019 - |
سؤال
أقوم بتحويل التعليمات البرمجية يدويًا من Java إلى C# وأكافح مع (ما أسميه) الأنواع البدائية (انظر ، على سبيل المثال هل تتصرف التآكل التلقائي والملابس بشكل مختلف في Java و C#). من الإجابات أفهم ذلك double
(C#) و Double
(ج#) معادلة و double
(C#) يمكن أيضًا استخدامها في الحاويات ، على سبيل المثال كمفتاح في القاموس. لكن، double
(جافا) لا يمكن استخدام Double
(جافا).
- هو
double
(ج#) بدائية أم كائن؟ - إذا كان بدائيًا ما الذي يجعله يتصرف بشكل مختلف عن
double
(جافا)؟
double
(C#) لا يمكن ضبطه على NULL ما لم يتم صنعه nullable
.
- هو
double?
(ج#) يعادلDouble
(جافا)؟ هل يشار إلى كلاهما كأشياء؟
(هل استخدام مصطلح "كائن من الدرجة الأولى" مفيد في هذه المناقشة؟)
المحلول
كل من C# و Java لهما أنواع بدائية (أو "قيمة"): int ، مزدوجة ، تعويم ، إلخ ...
ومع ذلك ، بعد هذا C# و Java يميلان إلى الانقسام.
Java لديها أنواع فئة التفاف ل كل الأنواع البدائية (وهي مجموعة محدودة صغيرة في Java) والتي تسمح لهم بمعاملتها ككائن.double/Double
, int/Integer
, bool/Boolean
, ، إلخ null
هي قيمة صالحة لتعيين هذه التعبيرات/المتغيرات المكتوبة. تضيف الإصدارات الحديثة من Java (1.5/5+) إكراه ضمني من البدائية إلى غلافها المقابل.
// Java
Boolean b = true; // implicit conversion boolean -> Boolean (Java 5+)
Boolean b = null; // okay, can assign null to a reference type
boolean n = null; // WRONG - null is not a boolean!
C# لا يوفر مثل هذا الالتفاف المباشر1 - جزئيًا ، لأن C# يدعم مجموعة لا حصر لها من أنواع القيمة عبر الهياكل; ؛ بدلاً من ذلك ، يتعامل C# Nullable<T>
نوع الغلاف. بالإضافة إلى ذلك C#، مثل Java ، لديه تحويلات ضمنية من نوع القيمة T
ل Nullable<T>
, ، مع التقييد على أن t هو "ليس نوعا لاغية" نفسه.
// C#
Nullable<bool> b = true; // implicit conversion bool -> bool?
bool? b = true; // short type syntax, implicit conversion
bool? b = null; // okay, can assign null as a Nullable-type
bool b = null; // WRONG - null is not a bool
لاحظ أن Nullable<T>
هو أيضًا نوع قيمة ، وبالتالي يتبع قواعد الهيكل القياسي لمتى/إذا كانت القيمة "على المكدس" أو لا.
ردا على التعليق:
من الصحيح تمامًا ، أن كونه من نوع القيمة يسمح له ببصمة ذاكرة أكثر إحكاما في بعض الحالات لأنه يمكن أن يتجنب النفقات العامة للذاكرة من نوع المرجع: ما هي بصمة الذاكرة من قابلية لا لبسu003CT>. ومع ذلك ، فإنه لا يزال يتطلب ذاكرة أكثر من النوع غير القابل للفرق لأنه يجب أن يتذكر ما إذا كانت القيمة ، حسناً ، لاغية ، أم لا. اعتمادًا على مشكلات المحاذاة وتنفيذ VM ، قد يكون هذا أو لا يكون أقل بكثير من كائن "كامل". أيضًا ، نظرًا لأن القيم في C#/CLR يتم إعادة صياغتها ، فكر في أي عمليات رفع يجب تنفيذها:
// C#
object x = null;
x = (bool?)true;
(x as bool?).Value // true
المقالة جافا نصيحة 130: هل تعرف حجم بياناتك؟ يتحدث عن استهلاك ذاكرة النوع المرجعي (في Java). شيء واحد يجب ملاحظة أن JVM لديه إصدارات متخصصة من المصفوفات داخليًا ، واحدة لكل نوع بدائي وللأشياء (ومع ذلك ، يرجى ملاحظة أن هذه المقالة تحتوي على بعض بيانات مضللة). لاحظ كيف أن الكائنات (مقابل البدائية) تتحمل النفقات العامة للذاكرة ومشكلات محاذاة البايت. C# ومع ذلك ، يمكن أن تمدد حالة الجائزة المحسنة ل Nullable<T>
الأنواع مقابل الحالات الخاصة المحدودة التي لدى JVM بسبب Nullable<T>
هو نفسه مجرد نوع بنية (أو "بدائية").
ومع ذلك ، فإن الكائن ، يتطلب فقط حجمًا ثابتًا صغيرًا للحفاظ على "مرجع" له في فتحة متغيرة. فتحة متغيرة من النوع Nullable<LargeStruct>
من ناحية أخرى ، يجب أن يكون لديه مساحة ل LargeStruct+Nullable
(قد تكون الفتحة نفسها على الكومة). يرى C# المفاهيم: القيمة مقابل الأنواع المرجعية. لاحظ كيف يكون مثال "الرفع" أعلاه من النوع object
: object
هو "نوع الجذر" في C# (الوالد من كل من أنواع المرجع وأنواع القيمة) و ليس نوع القيمة المتخصصة.
1 تدعم لغة C# مجموعة ثابتة من اسماء مستعارة بالنسبة للأنواع البدائية/الشائعة التي تسمح بالوصول إلى أسماء الأنواع "الودية الصغيرة". على سبيل المثال، double
هو الاسم المستعار ل System.Double
و int
هو الاسم المستعار ل System.Int32
. ما لم يختلف Double
تم استيراد النوع في النطاق ، double
و Double
سوف تشير إلى نفس النوع في C#. أوصي باستخدام الاسم المستعار ما لم يكن هناك سبب للقيام بخلاف ذلك.
نصائح أخرى
Nullable<double>
(الملقب ب double?
) في C# ليس نفس أ Double
في جافا.
قبل أن يكون لدى Java autoboxing/unboxing ، كان عليك التحويل يدويًا بين البدائية والكائنات من الدرجة الأولى:
Double dblObj = new Double(2.0);
double dblPrim = dblObj.doubleValue();
في Java 1.5 التي تغيرت ، لذلك يمكنك فقط القيام:
Double dblObj = 2.0;
double dblPrim = dblObj;
وسيقوم Java بإدراج رمز لتعكس المثال أعلاه تلقائيًا.
C# مختلف لأن هناك عدد غير محدود من الأنواع "البدائية" (ما يطلق عليه CLR أنواع القيمة). هذه تتصرف في الغالب مثل بدلات جافا ، باستخدام قيمة الدلالات. يمكنك إنشاء أنواع قيمة جديدة باستخدام struct
الكلمة الرئيسية. C# لديه autoboxing/unboxing الكل أنواع القيمة ، ويجعل جميع أنواع القيمة مستمدة من Object
.
حتى تتمكن من استخدام نوع القيمة (مثل double
) حيث يمكنك استخدام أي مرجع كائن (على سبيل المثال كمفتاح في أ Dictionary
) وسيتم تعبئتها إذا لزم الأمر ، أو استخدامها مباشرة. (تنفيذ الأداء الوطني لـ C#جيد بما يكفي لتجنب الملاكمة في معظم الظروف.)
في C#، فإن أفضل طريقة لفصل الكائنات هي "أنواع القيمة" التي تشبه البدائية - int
س، bool
S ، إلخ و "الأنواع المرجعية" - فئات إلخ.