أساسيات جافا

تحويل الأنواع والتحوّل بينها

15 دقيقة الدرس 5 من 14

تحويل الأنواع والتحوّل بينها

في الدروس السابقة صرّحت عن متغيّرات بأنواع محدّدة: int وdouble وlong وغيرها. البرامج الحقيقية تنقل البيانات باستمرار بين هذه الأنواع — تخزين درجة حرارة مقاسة (قيمة double) في حقل صحيح، أو قراءة مدخلات المستخدم (دائمًا String) ومعاملتها كرقم، أو الاحتفاظ بمجموع تراكمي في long رغم أن القيم الفردية من نوع int. يغطّي هذا الدرس كل آليات Java للتعامل مع ذلك بأمان.

اتجاهان: التوسيع والتضييق

تخيّل الأنواع العددية الأساسية مرتّبةً من الأصغر إلى الأكبر:

byte (8-bit) ↓ توسيع (آمن، تلقائي) short (16-bit) ↓ int (32-bit) ↓ long (64-bit) ↓ float (32-bit IEEE 754) ↓ double (64-bit IEEE 754)

التوسيع (Widening) يتجه للأعلى في السلسلة — نوع أصغر يتّسع تمامًا في حاوية أكبر دون فقد بيانات، لذا تُجريه Java تلقائيًا (ضمنيًا). التضييق (Narrowing) يتجه للأسفل — إجبار قيمة كبيرة في حاوية أصغر قد يُفقد بيانات، لذا تطلب Java كتابة تحويل صريح.

التحويل الضمني (التوسيع)

لا تحتاج إلى صياغة تحويل. تقوم Java بالعمل نيابةً عنك:

int score = 95; long big = score; // int → long، تلقائي double exact = score; // int → double، تلقائي float approx = score; // int → float، تلقائي System.out.println(big); // 95 System.out.println(exact); // 95.0
لماذا يعمل التوسيع دائمًا؟ كل قيمة تتّسع في 32 بت تتّسع أيضًا في 64 بت — المساحة أكبر فحسب. الرقم نفسه لا يتغيّر؛ التمثيل فقط يستخدم ذاكرة أكبر.

التحويل الصريح (التضييق)

حين تريد السير في الاتجاه المعاكس تكتب النوع الهدف بين قوسين أمام القيمة:

double temperature = 36.78; int rounded = (int) temperature; // تحويل صريح System.out.println(rounded); // 36 ← الجزء العشري يُقطع، لا يُقرَّب

الصياغة هي (targetType) expression. التحويل لا يقرّب؛ بل يقطع — يُسقط الجزء الكسري ببساطة.

قطع، لا تقريب. (int) 36.99 يُعطي 36 لا 37. إذا احتجت تقريبًا صحيحًا استخدم Math.round() أولًا، التي تُعيد long يمكنك تحويله بعدها إلى int.
double temperature = 36.78; int rounded = (int) Math.round(temperature); System.out.println(rounded); // 37

الفيضان العددي (Integer Overflow)

أخطر جانب في التضييق هو الفيضان (Overflow): حين تكون القيمة أكبر من سعة النوع الهدف، تُقطع الأجزاء الزائدة وينتج رقم خاطئ — لكن بصمت تام:

long bigNumber = 3_000_000_000L; // 3 مليارات — أكبر من نطاق int int overflow = (int) bigNumber; System.out.println(overflow); // -1294967296 ← نتيجة خاطئة!

لا تُلقي Java استثناءً هنا. تلتفّ القيمة بصمت. القاعدة بسيطة: تحقّق دائمًا أن القيمة تتّسع في النوع الهدف قبل التحويل.

استخدم Integer.MAX_VALUE وInteger.MIN_VALUE لمعرفة النطاق الآمن: 2_147_483_647 و-2_147_483_648. كل صنف مُغلِّف للأنواع الأساسية (Long وShort وByte) يحوي ثوابت مكافئة.

char والأنواع العددية

يخزّن char نقطة كود Unicode — عدد صحيح غير منخفض 16 بت. يشارك في التوسيع والتضييق تمامًا كالأنواع العددية:

char letter = 'A'; int code = letter; // توسيع: char → int System.out.println(code); // 65 (نقطة كود Unicode للحرف 'A') int value = 66; char back = (char) value; // تضييق: int → char System.out.println(back); // B

تحليل النصوص إلى أرقام

يُعطيك Scanner نصًا خامًا من نوع String من سطر الأوامر (أو ملف). لإجراء العمليات الحسابية يجب تحليل ذلك النص إلى نوع عددي. كل صنف مُغلِّف يوفّر تابعًا ساكنًا parse*:

String input = "42"; int n = Integer.parseInt(input); System.out.println(n + 10); // 52 String price = "19.99"; double amount = Double.parseDouble(price); System.out.println(amount * 2); // 39.98 String big = "9876543210"; long lValue = Long.parseLong(big); System.out.println(lValue); // 9876543210
المدخلات الخاطئة تُطلق NumberFormatException. إذا لم يكن النص رقمًا صالحًا — مثل "12abc" أو نص فارغ — يتعطّل parseInt في وقت التشغيل. ستتعلّم التعامل مع ذلك بـ try-catch في درس الاستثناءات.

تحويل الأرقام إلى نصوص

السير في الاتجاه المعاكس — تحويل رقم إلى String — آمن دائمًا ولا يستلزم تحويلًا صريحًا. ثلاثة أساليب شائعة:

int count = 100; String s1 = String.valueOf(count); // الأسلوب الموصى به String s2 = Integer.toString(count); // جيّد أيضًا String s3 = "" + count; // يعمل، لكن أقل وضوحًا System.out.println(s1.getClass().getSimpleName()); // String

الخلاصة

تحويلات التوسيع تلقائية وآمنة. تحويلات التضييق تستلزم تحويلًا صريحًا وتقطع الكسور وقد تُفضي إلى فيضان صامت — تحقّق دائمًا أن القيمة تتّسع في النوع الهدف. استخدم Integer.parseInt وDouble.parseDouble وأخواتها لتحويل مدخلات String إلى أرقام، واحرص على الحماية من المدخلات غير الصالحة. هذه الأنماط تظهر في كل برنامج Java تكاد تكتبه.