أهلاً! أثناء تقدمك في CodeGym، واجهت أنواعًا بدائية عدة مرات. فيما يلي قائمة قصيرة بما نعرفه عنهم:
- إنها ليست كائنات وتمثل قيمة مخزنة في الذاكرة
- هناك عدة أنواع
- الأعداد الصحيحة: بايت ، قصير ، int ، طويل
- أرقام الفاصلة العائمة (الكسرية) : عائمة ومزدوجة
- القيم المنطقية: منطقية
- القيم الرمزية (لتمثيل الحروف والأرقام): char
-
كل نوع له نطاق خاص به من القيم:
نوع بدائي |
الحجم في الذاكرة |
مدى القيمة |
بايت |
8 بت |
-128 إلى 127 |
قصير |
16 بت |
-32768 إلى 32767 |
شار |
16 بت |
0 إلى 65536 |
كثافة العمليات |
32 بت |
-2147483648 إلى 2147483647 |
طويل |
64 بت |
-9223372036854775808 إلى 9223372036854775807 |
يطفو |
32 بت |
(2 أس -149) إلى ((2 - (2 أس -23)) * 2 أس 127) |
مزدوج |
64 بت |
(-2 للأس 63) إلى ((2 للأس 63) - 1) |
منطقية |
8 (عند استخدامها في المصفوفات)، 32 (إذا لم يتم استخدامها في المصفوفات) |
صحيحة أو خاطئة |
ولكن بالإضافة إلى وجود قيم مختلفة، فإنها تختلف أيضًا في مقدار المساحة التي تشغلها في الذاكرة. يستغرق int أكثر من بايت
. والطويل أكبر من القصير
. يمكن مقارنة حجم الذاكرة التي تشغلها البدائيات بالدمى الروسية:
كل دمية لديها مساحة متاحة بالداخل. كلما كانت دمية التعشيش أكبر، زادت المساحة المتوفرة. دمية تعشيش كبيرة (
طويلة ) سوف تستوعب بسهولة
حجم أصغر . يناسبها بسهولة ولا تحتاج إلى القيام بأي شيء آخر. في Java، عند العمل مع البدائيين، يُسمى هذا بالتحويل الضمني. أو بعبارة أخرى، هذا ما يسمى بالاتساع.
اتساع في جاوة
فيما يلي مثال بسيط لتوسيع التحويل:
public class Main {
public static void main(String[] args) {
int bigNumber = 10000000;
byte littleNumber = 16;
bigNumber = littleNumber;
System.out.println(bigNumber);
}
}
هنا نقوم بتعيين قيمة بايت لمتغير
int . تنجح المهمة دون أي مشاكل: القيمة المخزنة في البايت تشغل ذاكرة أقل مما يمكن أن يستوعبه
int . يمكن وضع دمية التعشيش الصغيرة (قيمة البايت) بسهولة داخل دمية التعشيش الكبيرة ( متغير
int ). الأمر مختلف إذا حاولت القيام بالعكس، أي وضع قيمة كبيرة في متغير لا يمكن أن يستوعب نطاقه مثل هذا النوع من البيانات الضخمة. مع دمى التعشيش الحقيقية، فإن العدد ببساطة لن يكون مناسبًا. مع Java، يمكن ذلك، ولكن مع الفروق الدقيقة. دعونا نحاول وضع
int في متغير
قصير :
public static void main(String[] args) {
int bigNumber = 10000000;
short littleNumber = 1000;
littleNumber = bigNumber;
System.out.println(bigNumber);
}
خطأ! يفهم المترجم أنك تحاول القيام بشيء غير طبيعي عن طريق دفع دمية متداخلة كبيرة (
int ) داخل دمية صغيرة (
short ). في هذه الحالة، خطأ الترجمة هو تحذير من المترجم: "مرحبًا، هل أنت
متأكد تمامًا من أنك تريد القيام بذلك؟" إذا كنت متأكدًا، أخبر المترجم:
"كل شيء على ما يرام. أعرف ما أفعله!" تسمى هذه العملية تحويل النوع الصريح أو التضييق.
تضييق في جاوة
لإجراء تحويل تضييقي، يتعين عليك الإشارة بوضوح إلى النوع الذي تريد تحويل القيمة إليه. بمعنى آخر، أنت بحاجة للإجابة على سؤال المترجم:
"حسنًا، أي من هذه الدمى الصغيرة تريد وضع هذه الدمية الكبيرة فيها؟" في حالتنا، يبدو الأمر كما يلي:
public static void main(String[] args) {
int bigNumber = 10000000;
short littleNumber = 1000;
littleNumber = (short) bigNumber;
System.out.println(littleNumber);
}
نشير بوضوح إلى أننا نريد وضع
int في متغير
قصير وأننا سنتحمل المسؤولية. نظرًا لأنه تمت الإشارة بوضوح إلى نوع أضيق، يقوم المترجم بإجراء التحويل. ما هي النتيجة؟ إخراج وحدة التحكم:
-27008 كان ذلك غير متوقع بعض الشيء. لماذا حصلنا على ذلك بالضبط؟ في الواقع، كل شيء بسيط للغاية. في الأصل، كانت القيمة 10000000 وتم تخزينها في متغير
int ، الذي يشغل 32 بت. وهذا هو تمثيلها الثنائي:
نكتب هذه القيمة في متغير
قصير ، يمكنه تخزين 16 بت فقط! وبناء على ذلك، سيتم نقل أول 16 بت فقط من رقمنا هناك. سيتم التخلص من الباقي. ونتيجة لذلك، يتلقى المتغير القصير القيمة التالية
والتي تساوي -27008 في الشكل العشري، ولهذا السبب يطلب منك المترجم "التأكيد" من خلال الإشارة إلى تحويل تضييق واضح إلى نوع معين. أولاً، هذا يوضح أنك تتحمل مسؤولية النتيجة. وثانيًا، يخبر المترجم بمقدار المساحة التي يجب تخصيصها عند حدوث التحويل. بعد كل شيء، في المثال الأخير، إذا قمنا بتعيين قيمة int لمتغير بايت بدلاً من قيمة قصيرة
، فسيكون لدينا 8 بتات فقط تحت تصرفنا، وليس 16، وستكون النتيجة مختلفة. الأنواع الكسرية (
العائمة والمزدوجة ) لها عملية خاصة بها لتضييق التحويلات
. إذا حاولت إرسال رقم كسري إلى نوع صحيح، فسيتم تجاهل الجزء الكسري.
public static void main(String[] args) {
double d = 2.7;
long x = (int) d;
System.out.println(x);
}
إخراج وحدة التحكم:
2
شار
أنت تعلم بالفعل أنه يتم استخدام
char لعرض الأحرف الفردية.
public static void main(String[] args) {
char c = '!';
char z = 'z';
char i = '8';
}
لكن هذا النوع من البيانات يحتوي على العديد من الميزات التي من المهم فهمها. دعونا ننظر مرة أخرى إلى جدول نطاقات القيمة:
نوع بدائي |
الحجم في الذاكرة |
مدى القيمة |
بايت |
8 بت |
-128 إلى 127 |
قصير |
16 بت |
-32768 إلى 32767 |
شار |
16 بت |
0 إلى 65536 |
كثافة العمليات |
32 بت |
-2147483648 إلى 2147483647 |
طويل |
64 بت |
-9223372036854775808 إلى 9223372036854775807 |
يطفو |
32 بت |
(2 أس -149) إلى ((2 - (2 أس -23)) * 2 أس 127) |
مزدوج |
64 بت |
(-2 للأس 63) إلى ((2 للأس 63) - 1) |
منطقية |
8 (عند استخدامها في المصفوفات)، 32 (إذا لم يتم استخدامها في المصفوفات) |
صحيحة أو خاطئة |
تتم الإشارة إلى النطاق من 0 إلى 65536 لنوع
char . لكن ماذا يعني هذا؟ بعد كل شيء، لا يمثل
الحرف أرقامًا فحسب، بل يمثل أيضًا حروفًا وعلامات ترقيم... الشيء هو أنه في Java يتم تخزين قيم
char بتنسيق Unicode. لقد واجهنا Unicode بالفعل في أحد الدروس السابقة. ربما تتذكر أن Unicode هو معيار لترميز الأحرف يتضمن رموز جميع اللغات المكتوبة في العالم تقريبًا. بمعنى آخر، إنها قائمة من الرموز الخاصة التي تمثل تقريبًا كل حرف في أي لغة. جدول Unicode بأكمله كبير جدًا، وبالطبع ليست هناك حاجة لحفظه عن ظهر قلب. إليك جزء صغير منه:
الشيء الرئيسي هو فهم كيفية تخزين الأحرف، وتذكر أنه إذا كنت تعرف رمز حرف معين، فيمكنك دائمًا إنتاج هذا الحرف في برنامجك. دعونا نحاول مع بعض الأرقام العشوائية:
public static void main(String[] args) {
int x = 32816;
char c = (char) x ;
System.out.println(c);
}
إخراج وحدة التحكم: هذا هو التنسيق المستخدم لتخزين
الأحرف في Java. يتوافق كل رمز مع رقم: رمز رقمي مكون من 16 بت (ثنائي البايت). في Unicode، 32816 يتوافق مع الحرف الصيني 耰. قم بتدوين النقطة التالية. في هذا المثال، استخدمنا متغير
int . إنه يشغل 32 بت في الذاكرة، بينما يشغل
char 16 بت. اخترنا هنا
int ، لأن رقمنا (32816) لن يناسبه لفترة
قصيرة . على الرغم من أن حجم الحرف
( تمامًا مثل
Short ) هو 16 بت، إلا أنه لا توجد أرقام سالبة في نطاق
char ، وبالتالي فإن الجزء "الإيجابي" من نطاق
char يكون أكبر بمرتين (65536 بدلاً من 32767 للنوع
القصير ) . يمكننا استخدام
int طالما ظل الكود الخاص بنا أقل من 65536. ولكن إذا قمت بإنشاء قيمة
int أكبر من 65536، فسوف تشغل أكثر من 16 بت. وهذا سوف يؤدي إلى تضييق التحويل
char c = (char) x;
سيتم التخلص من البتات الإضافية (كما تمت مناقشته أعلاه) وستكون النتيجة غير متوقعة تمامًا.
ميزات خاصة لإضافة الأحرف والأعداد الصحيحة
دعونا نلقي نظرة على مثال غير عادي:
public class Main {
public static void main(String[] args) {
char c = '1';
int i = 1;
System.out.println(i + c);
}
}
إخراج وحدة التحكم:
50 O_О كيف يعقل ذلك؟ 1+1. من أين جاءت الخمسين؟! أنت تعلم بالفعل أنه
char
يتم تخزين القيم في الذاكرة كأرقام في النطاق من 0 إلى 65536، وأن هذه الأرقام هي تمثيل Unicode للحرف.
عندما نضيف
حرفًا ونوعًا من الأرقام الصحيحة، يتم تحويل
الحرف إلى رقم Unicode المقابل. في الكود الخاص بنا، عندما أضفنا 1 و'1'، تم تحويل الرمز '1' إلى الكود الخاص به، وهو 49 (يمكنك التحقق من ذلك في الجدول أعلاه). لذلك، النتيجة هي 50. لنأخذ مرة أخرى صديقنا القديم 耰 كمثال، ونحاول إضافته إلى رقم ما.
public static void main(String[] args) {
char c = '耰';
int x = 200;
System.out.println(c + x);
}
إخراج وحدة التحكم:
33016 لقد اكتشفنا بالفعل أن 耰 يتوافق مع 32816. وعندما نضيف هذا الرقم و200، نحصل على النتيجة: 33016. :) كما ترون، الخوارزمية هنا بسيطة للغاية، لكن لا يجب أن تنساها .
GO TO FULL VERSION