- a l t -

 

محمد سفر العتيبي 06-5-2003 21:47 ارسل دعوة لصديقك لزيارة هذا الموضوعالتوقيت العالمياطبع هذه الصفحه

 

جزى الله الأخ محمد سفر العتيبي كل خير على ما قدمه من جهد في هذا العمل النبيل

 

بسم الله الرحمن الرحيم

أخي الطالب: لا تنسى قبل الاستذكار وبعد البسملة أن تقول اللهم علمنا ما ينفعنا و انفعنا بما علمتنا

السلام عليكم ورحمة الله و بركاته

تمهيد

نواصل معكم سلسلة بعض الدروس حول لغات البرمجة. هناك العديد من اللغات الشهيرة مثل الفورتران والسي و السي++ و الماتلاب و الجافا – و التي تتنوع استخداماتها كثيراً في شتى المجالات و لكن تتفق في شئ واحد و هي أنها صممت لتجعل الحياة أكثر سهولة (في عالمنا العربي ألاحظ العكس! لماذا؟).

طبعاً هذه السلسلة مخصصة للجافا (Java programming language)

ماهي الجافا ؟ ولماذا تستخدم؟ و ماعلاقتها بالإنترنت؟

و أسئلة أخرى كثيرة لن أجيب عليها الأن وقد لا أجيب عليها أبداً (يعني بلاش إحراج) لأنكم و من أنفسكم ستكتشفون أجوبة جميع هذه الأسئلة و عموماً هذه هي طريقة التدريس التي أحبذها و هي وضع الأمثلة و شرحها بعيداً عن فلسفة الأمور و تعقيدها و أعول دوماً و أبداً على ذهن المتلقي و استثارته ليعتمد على نفسه في معرفة أهمية القضية التي أمامه خصوصاً بعد . ........... السياسية . فلنبدأ الرحلة ولكن قبل البدء هل لديك جهاز كمبيوتر و هل لديك برنامج الجافا

إذا لم يكن الجافا محملاً على جهازك فيجب عليك اقتنائه إن وجد بالأسواق – أو يمكنك مراسلتي لإرساله لك مقابل مبلغ رمزي (100 ريال سعودي) هي ثمن الجافا سي دي. و أيضاُ من يريد سي دي الدروس القادمة مثل الماتلاب و الفورتران و السي++ فيمكن إرسالها مقابل رأس مالها.

نبدأ سلسلة هذه الدروس و هو كما قلنا مكرسة للجافا و الهدف الرئيسي للبدء بالجافا رغم صعوبتها نوعاً ما مقارنة باللغات الأخرى هو لإرتباطها الوثيق بالإنترنت من خلال تصميم المواقع الشخصية و جعلها أكثر جاذبية و ذات وظائف أعم.

هل سمعتم بالجافا ابلت (java applet) ) مثلاُ هل رأيتم ساعة أشبة بساعة اليد في أحد المواقع هل رأيتم تمثيلاُ طبيعياً لمرور تيار كهربائي في دائرة معينة في أحد المواقع و رأيتم كيف ينير المصباح في تلك الدائرة باللون الأصفر ثم ينطفي باللون الأبيض و كأنها أمام عينيك. و الكثير الكثير من هذه الأشياء كلها تم تنفيذها غالباً بإستخدام الجافا ابلت – (java applet)) ولايمكن تنفيذ الجافا ابلت الا بعد فهم الجافا نفسها و ماتحتويه (مكتبتها) من (مجلدات) صممت خصيصاً لأداء وظائف كثيرة ولكن لكل وظيفة هدف محدد.

أنت الأن متسمر أمام شاشة الكمبيوتر و تنظر في سطح المكتب (DESKTOP)إذا تمكنت من تحميل الجافا على جهازك فسيكون هناك رابطاً اسمه --> JCreator LE ويمكنك الوصول اليه من خلال

Start--> Programs --> JCreator LE --> JCreator LE

اضغط عليه ستجد نفسك وجهاً لوجه أمام صفحة طباعة أوامر الجافا (Start--> java text editor ) في الشريط الأزرق العلوي ستجد كلمة Jcreator

و في شريط الأدوات الرئيسي ستجد الكلمات التالية

File – Edit –Search – View – Project – Build – Tools

وغيرها

ولكن ركز على أداتي File – Build والتي سنستخدمها بكثرة و التركيز الخاص يجب أن يكون على كلمة Build اذهب الى File ثم اضغط على New ستجد نفسك أمام شاشة صغيرة جديدة باسم New و التي تتألف من ثلاثة أقسام


1. Files
2. Projects
3.Workspaces

إختر Files وفي حقل Filename أمامك في نفس الشاشة الصعيرة إطبع اسم البرنامج متبوعاً ب java مثلاُ نفترض أن اسم الملف LessonOne لذا يجب أن يكتب على الشكل التالي LessonOne.java هل لاحظتم كلمة javaبعد النقطة – إنها كتبت بالأحرف الصغيرة أي صيغة أخرى تعتبر خاطئة فمثلاُ لو كتبنا اسم الملف السابق على الصور الأتية فستواجهنا مشاكل كثيرة

LessonOnejava, LessonOne,LessonOne.JAVA , LessonOne.Java , LessonOne.jav

بعد أن تكتب اسم الملف LessonOne . java اختر المكان ( Location ) الذي تود بقاء (حفظ) هذا الملف( LessonOne. java ) فيه أمامك ستجد حقلاً اسمه ( Location ) يمكنك من خلاله اختيار المكان الذي تود

ولكن إذا لم تختر مكان معين فإن ملفك سيوجد تحت الرابط التالي ( by default )

C:\Program Files\ Xinox Software\ JCreator LE\ MyProjects \

اضغط OKالأن أمامك صفحة بيضاء و في الشريط الأزرق الأعلى يوجد اسم الملف ( LessonOne )

اطبع البرنامج التالي خبط لزق من غير أسئلة زائدة

 

class LessonOne { static void main( String[ ] args ) { System.out.println("Islam Is The Sole Solution!"); } }

حالما تنتهي من الكتابة احفظ الملف ثم اذهب الى Build----> ثم اضغط على Compile Fileبعد الإنتهاء سيعطيك البرنامج مختصراً عن الأخطاء في كتابة البرنامج و السطر الذي يتواجد فيه الخطأ – هذا المختصر سيتكون في أسفل الصفحة أمامك تحت عنوان ( Configuration) في هذا المثال لايوجد أخطاء ولذلك ستجد عبارة ( Prosess Completed. ) لو وجد أخطاء فعليك تصحيحها و إعادة الكرة السابقة

ولكن إذا لم يوجد أخطاء فحينها يمكنك رؤية نتائج البرنامج السابق و الذي لم نشرح محتوياته و معانيها حتى الان .

كيف نرى هذه النتائج.

ببساطة اذهب الى Buildمرة أخرى ولكن هذه المرة اضغط Execute File بعد الضغط على Execute File يمكنك رؤية النتائج فس شاشة سوداء أشبه بشاشة الدوس ( DOS ) وفي هذه الشاة ستجد اسم مكان الملف ( LessonOne.java) في الشريط الأزرق الأعلى

في هذا المثال البسيط نحن أردنا طباعة العبارة التالية

ستجدون هذه العبارة مطبوعة و تحتها عبارة

Press any Key to continue

– أي اضغط أي زر لتواصل اضغط على أي زر ستختفي تلك الشاشة من أمامك وبإمكانك رؤيتها مرة أخرى باتباع الطقوس السابقة – أي الضغط على

Build --> Execute File

غداً نبدأ الشرح للمثال التمهيدي السابق والذي لم يكن هدفنا هذا اليوم و إنما كان الهدف هو إزالة الوحشة و كيفية التعامل مع الأدوات الضرورية قبل مواصلة رحلة الإبحار مع هذه اللغة الفريدة. فإلى الغد يا رفاق .

لاتنسوا أن تقرأو ديباجة التشجيع المعتمدة لدي في هذا الموضوع على الرابط التالي:

محمد سفر العتيبي "تعلم لغة الهوتميل (Learn HTML ) على الطريقة البدوية السهلة" 04/05/03 17:50




 
 

 

  محمد سفر العتيبي 21-6-2003 11:2043.  

الدرس السابع و الثلاثون (37)
Handling input/Output I/O Data
كيفية تغذية البرنامج بالمعلومات و عرض الناتج النهائي
Reading Data from External Files
قراءة المعلومات من ملف خارجي مستقل معد مسبقاً

في هذ الدرس نتطرق لكيفية قراءة المعلومات من ملف خارجي معد مسبقاً و يحتوي على جميع المعلومات المطلوبة. هذا الدرس بطبيعة الحال من أحب الدروس الى نفسي ببساطة لأنه يجعلك تفهم أهمية البرمجة أكثر كما سترى إن شاء الله تعالى.

و كما هو بديهي من العنوان --- سيقفز الى ذهنك كتابة المعلومات التي يحتاجها البرنامج من خلال اي برنامج تحرير نصوص مثل المفكرة "Notpad" او محرر النصوص الشهير "Microsoft Word"

في هذه السلسة التعليمية سنستخدم المفكرة كمحرر للمعلومات التي يحتاجها البرنامج. وعند حفظ الملفات يجب ان ينتهي اسم الملف بالإمتداد txt ---- فمثلاُ تخيل أن اسم الملف الذي كتبت فيه المعلومات inputdata---- سيحفظ هذا الملف على هذا النحو: inputdata.txt

مارأيكم أن نتفق على هذا الاسم "inputdata.txt" كاسم للملف الذي يحتوي على المعلومات "المداخيل" التي يحتاجها البرنامج؟ سأفترض أننا اتفقنا ولكن انت حر في اختيار اسم تريد ولكن المهم أن تضع في نص "كود" برنامج الجافا الذي ستكتبه اسم الملف الذي يحتوي المعلومات كما اخترته.

من الجملة الأخيرة واضح أن هناك أوامر ربط بين ملف المعلومات و برنامج الجافا الذي يستخدم تلك المعلومات. كيف يتم هذا؟ هذا هو هدف درس هذا اليوم.

انسخ المعلومات داخل الصندوق الأبيض التالي و انقلها للمفكرة و احفظ الملف باسم "inputdata.txt"

أيضاً انسخ البرنامج التالي الى محرر الجافا و احفظ الملف باسم price.java

01 import java.io.*; 02 import java.util.*; 03 import java.text.*; 04 public class Lesson37a 05 { 06 public static void main( String[ ] args) throws IOException 07 { 08 String line; 09 FileReader xyz = new FileReader("inputdata.txt"); 10 BufferedReader x = new BufferedReader(xyz); 11 12 String BookName; 13 double price; 14 int quantity; 15 16 line = x.readLine(); 17 StringTokenizer data = new StringTokenizer(line); 18 19 BookName = data.nextToken(); 20 quantity = Integer.parseInt( data.nextToken()); 21 price = Double.parseDouble( data.nextToken()); 22 23 System.out.println( BookName + "\t" + quantity + "\t" + price); 24 25 x.close(); 26 } 27 }

السطر الأول و الثاني و الثالث:

import java.io.*; import java.util.*; import java.text.*;

كما قلنا سابقاً يوجد في مكتبة الجافا العديد من الباقات المصممة لتساعد على تأدية وظيفة ما -- في درس اليوم قراءة المعلومات التي يحتاجها البرنامج من ملف خارجي لابد من وجود الباقات "الحزم" الثلاث أعلاه. وكما قلنا سيأتي التفصيل فيها لاحقاً تحت عنوان Packages --- الحزمة أو الباقة الأخيرة *.java.textقد تستغني عنها في مثالنا السابق. علامة النجمة * تعني "كل" --- أي استفد من كل محتويات أحد أرفف مكتبة الجافا مثل io أو util أو text

اأسطر من 4 و حتى 7: أعتقد أنكم تعرفون ماذا تعني.

السطر الثامن:

String line;

عرفنا متغيراً من نوع String ---- اسم هذا المتغير هنا line ---- و طبعاً تستطيع ان تغير line الى أي اسم تشاء فللمستخدم الحرية في اختيار اسماء المتغيرات. هذا المتغير سنستخدمه استخداماً خاصاً فيما بعد.

السطران التاسع و العاشر:

FileReader xyz = new FileReader("inputdata.txt"); BufferedReader x = new BufferedReader(xyz);

هذان السطران هما سطري التهئية لقراءة المعلومات "input data" من ملف خارجي. اسم هذا الملف الخارجي هو inputdata.txt .

FileReader هو أمر يستخدم لتحديد اسم الملف كما هو واضح من المثال وتخزينه في متغير اسمه xyz ---- و من خلال أمر BufferedReader سنرجع لهذا الملف من خلال المتغير x -- أي أننا كلما أردنا القراءة من هذا الملف فمن خلال المتغير x --- انظر شزراً الان للسطر 16 ---- فهناك يوجد أمر القراءة readLine والذي مر علينا سابقاً. هل رأيت كيفية ارتباطه بالمتغير x والذي نعرف أنه مرجع لاسم الملف الذي سنقرأ منه. ولكي لاتعتفس الأمور عليك لاتكترث الان لهذا الشرح --- فكما ذكرت في درس سابق سنعود لهذه المصطلحات فيما بعد و في الوقت المناسب. كل ماعليك الان هو تعويد اناملك من خلال التطبيقات المكثفة على كتابة برامج تحتوي هذين السطرين.

الأسطر 12 و 13 و 14:

String BookName; double price; int quantity;

ثلاثة تعاريف مختلفة لثلاثة متغيرات. فقد تم تعريف المتغير BookName كنوع String و تعريف المتغير price ك double و تعريف المتغير quantity ك int. و هذه المتغيرات سنستخدمها فيما سيأتي لذلك و كما قلنا سابقاً أي متغير في البرنامج يجب أن يعرف أولاً. سأعيدها مرة أخرى "أي متغير في البرنامج يجب أن يعرف أولاً"

السطر 16:

line = x.readLine();

هذا الأمر هو أمر القراءة ---- readLine تعني "اقرأ كامل هذا السطر" من الملف الذي نرجع اليه من خلال المتغير x. هذا الملف الذي نرجع له من خلال x هو "inputdata.txt" ---- سيقرأ البرنامج كامل السطر بما فيه من قيم أو فراغات و سيعتبرها و كأنها كلمة واحدة ويخزنها في المتغير line والذي عرفنا نوعه سابقاً ليكون String

هل تذكرون عندما قلت لكم في هذا الدرس "انسخ المعلومات داخل الصندوق لأبيض التالي و انقلها للمفكرة و احفظ الملف باسم "inputdata.txt" --- ألم تكن هذه المعلومات هي:

فمن الواضح للعين المجردة أن هذا السطر يحتوي على 3 معلومات مختلفة النوع. المعلومة الأولى هي IslamicWorld و هي من نوع String و المعلومة الثانية هي 150 و هي من نوع int و المعلومة الثالثة هي 33.56 و هي من نوع double

سطر المعلومات هذا بأكمله سيعتبره البرنامج و حتى هذه اللحظة و كأنه كلمة واحدة أو معلومة واحدة بدءاً من حرف I في IslamicWorld و حتى رقم 6 في الرقم 33.56 --- و طبعاً الكلمة تعرف بإستخدام نوع String --- لذلك تم تخزينه في المتغير line المتلائم مع هذا النوع.

إذن كيف نُفَهِم نحن البرنامج ليميز عدد المعلومات في هذا السطر؟ و مانوع هذه المعلومات؟

أولاً يجب أن يعرف عدد هذه المعلومات. فكيف؟ الجواب في السطر 17

السطر 17:

StringTokenizer data = new StringTokenizer(line);

أمر StringTokenizer هو الأمر المستخدم لفرز أو معرفة عدد هذه المعلومات. فهذا الأمر سيمر عبر قيمة المتغير line و هي التي أصبحت على النحو التالي:

line = "IslamicWorld 150 33.56"

وسيعرف عدد الفراغات بين اجزاء هذه القيمة --- سيجد أن هناك فراغين --- الفراغ الأول بين المعلومة أو القيمة IslamicWorld و المعلومة 150 و الفراغ الثاني بين 150 و 33.56

و معنى أن هناك فراغين فهذا يقتضي أن قيمة line يمكن تفكيكها الى 3 قيم. أي أن هذا الأمر سيجزئ قيمة المتغير line الى ثلاثة قيم. ويخزن هذه القيم الثلاثة في متغير جديد اسمه data الذي عرف بإستخدام StringTokenizer --- طبعاً data بأمكانك تغييرها الى أي اسم تريد --- فللمستخدم الحرية في اختيار مايشاء كأسماء للمتغيرات.

أجبنا على سؤالنا حول عدد المعلومات في السطر الذي قراناه من الملف الذي حفظنا فيه المعلومات وهو inputdata.txt

ولكن حتى هذه اللحظة لم نميز نوعها و كنهها و لذلك لايمكننا الاستفادة منها --- فكيف يتم فرز نوع كل معلومة من المعلومات الثلاثة؟ الجواب في الأسطر 19 و 20 و 21

الأسطر 19 و 20 و 21:

BookName = data.nextToken(); quantity = Integer.parseInt( data.nextToken()); price = Double.parseDouble( data.nextToken());

nextToken هو امر يستخدم للإنتقال من معلومة الى المعلومة التي تليها مباشرة.

وبما أنك أنت الذي كتبت البرنامج فأنت تعرف أن المعلومة الأولى من نوع String لذلك خزن هذه القيمة في متغير من نوع String. فالسطر الأول هنا وهو:

BookName = data.nextToken();

يخزن القيمة "IslamicWorld" في المتغير BookName والذي سبق تعريفه في السطر 12 ك String ----- بينما السطر الثاني هنا و هو:

quantity = Integer.parseInt( data.nextToken());

سيخزن القيمة 150 في المتغير quantity والذي سبق تعريفه ك int ----- سينتقل البرنامج من القيمة IslamicWorld الى هذه القيمة وهي 150 بإستخدام أمر nextToken و هاتين القيمتين مخزنتين في المتغير data لذلك استخدمنا data.nextToken ---------- في السطر الثالث وهو:

price = Double.parseDouble(data.nextToken());

سيتم تخزين القيمة أو المعلومة 33.56 داخل المتغير price والذي سبق تعريفه ك double ---- طبعاً الوصول لهذه القيمة سيتم من خلال data.nextToken و غني عن القول أن نوقل أننا استخدمنا parseDouble لأن هذه القيمة من نوع double

السطر 23:

System.out.println( BookName + "\t" + quantity + "\t" + price);

هذا السطر ببساطة سيطبع قيم المتغيرات BookName و quantity و price ----- ووضعناه هنا لنتأكد انت و أنا من صحة الشرح السابق ---- فبعد ترجمة "تصحيح" البرنامج ثم تنفيذه فنحن نتوقع ان يكون الناتج على الشكل التالي: في الحقيقة يجب أن يكون هكذا

IslamicWorld 150 33.56 Press any key to continue...

السطر 25:

x.close();

هذا المر عدم وجوده يسبب الكوارث --- فهذا الأمر يعني "أغلق الملف الذي نرجع اليه ونستخدمه من خلال المتغير x --- أعتقد أن كلمة close و تعني "أغلق" توضح هذا المعنى. أه لقد تذكرت شيئاً وهو اسم الملف الذي نرجع له من خلال المتغير x -- هذا الملف قلنا أنه اسمه "inputdata.txt" ---- وبما أننا فتحناه وهو "ملف خارجي" فعلينا إغلاقه قبل المغادرة لكي نتحاشى الكوارث. و كما يقول المثل باب يجيك منه ريح سده و استريح و قد فعلنا مايجب أن نفعله.

ملحوظة مهمة: الجملة الأخيرة ليست سياسية op op oop

الى اللقاء مع الجزء الثاني من هذا الدرس وهو أهم و لكن أسهل كثيراً من درس اليوم وسيكون بعده الجزء الثالث بإذن الله عز و جل و هو أمثلة تطبيقية مكثفة على درس اليوم والغد. فإلى الغد يارفاق. نقصد بكلمة الغد "الدرس القادم"

 



 
 
 

 

  محمد سفر العتيبي 22-6-2003 03:1744.  

الدرس السابع و الثلاثون (37-2)
Handling input/Output I/O Data
كيفية تغذية البرنامج بالمعلومات و عرض الناتج النهائي
Reading Data from External Files
قراءة المعلومات من ملف خارجي مستقل معد مسبقاً

درس الأمس كان فقط بهدف معرفة ألأوامر و الجمل التي تستخدم من أجل تمكين البرنامج من القراءة من ملف خارجي.

طريقتنا التقليدية السابقة قد تكون اجدى من طريقتنا في درس الأمس لسبب بسيط وهو أن عدد المعلومات كان محدوداً. فمثال الأمس يكافئ البرنامج التالي:

public class Lesson37b

   {

 public static void main( String[ ] args)

                {

                        String BookName = "IslamicWorld";

                        double price =33.56;

                         int quantity = 150;

                       System.out.println( BookName + "\t" + quantity + "\t" + price);

              }

 }

فكلا البرنامجين يقرأ نفس المعلومات و يطبع نفس الناتج النهائي.

إذن لماذا هذا التعقيد؟

في الحقيقة لو عرفت أهمية درس الأمس لأدركت  انه قمة التسهيل للكثير من المسائل التطبيقية.

تخيل أن لدينا ملف المعلومات التالي و هو كشف حول النسبة المئوية لطلبة أحد الفصول الدراسية في نهاية الفصل الدراسي في مدارس المملكة الأهلية. .وهو ملف يحتوي كل سطر فيه معلومات حول أحد الطلبة: اسمه و رقمه التسلسلي في الفصل و درجته النهائية في نهاية الفصل الدراسي:

من ملف المعلومات هذا لدينا 14 طالباً. تساءل الأن مع نفسك السؤال التالي: أيهما أكثر فعالية قراءة هذه المعلومات كما فعلنا في درس الأمس و ذلك من خلال ملف خارجي أم تضمينها في البرنامج كما في البرنامج Lesson37b أعلاه؟

نعم كلا الطريقتين من وجهة نظر برمجية ستعطي الجواب. ولكن لو كان عدد الطلبة مثلاُ عدة عشرات أو مئات أو الاف. هل ستدخل معلوماتهم جميعاً ضمن البرنامج؟ ياللحماقة !!!

أعتقد أنك في هذه الحالة تحتاج الى عدة سنين لكتابة هذا البرنامج.

لاشك أن طريقة الاستزادة بالمعلومات من ملف خارجي هي الأنجع و لا تقارن أبداً بالطريقة البليدة الأخرى. لذا يكفيك فقط أن تكتب بضعة أسطر لتفي بالمهمة و تقرأ جميع المعلومات من ملف المعلومات أو ال input data file

وقبل مواصلة الشرح --- انسخ المعلومات أعلاه الى المفكرة و احفظ الملف تحت اسم inputdata.txt كما اتفقنا بالأمس. نقصد بكلمة الأمس "الدرس السابق" و البرنامج التالي مطابق لدرس الأمس مع بعض التعديلات الطفيفة المناسبة لكي تتلائم مع ملف المعلومات:

01 import java.io.*; 02 import java.util.*; 03 import java.text.*; 04 public class Lesson37c 05 { 06 public static void main( String[ ] args) throws IOException 07 { 08 String line; 09 FileReader xyz = new FileReader("inputdata.txt"); 10 BufferedReader x = new BufferedReader(xyz); 11 12 String studName; 13 double grade; 14 int serialNum; 15 16 line = x.readLine(); 17 18 19 StringTokenizer data = new StringTokenizer(line); 20 21 studName = data.nextToken(); 22 serialNum = Integer.parseInt( data.nextToken()); 23 grade = Double.parseDouble( data.nextToken()); 24 25 System.out.println( serialNum + "\t" + StudName + "\t" + grade); 26 27 28 x.close(); 29 } 30 } ناتج هذا البرنامج هو 1 Al-Shehri 87.0 Press any key to continue...

وكما نلاحظ من الناتج النهائي فهذا البرنامج للأسف لم يقرأ سوى السطر الأول وهو المعلومات المتعلقة بالطالب "الشهري" ---- لماذا؟

السبب لأن أمر readLine لم يستخدم سوى مرة واحدة ---- و معنى هذا أن البرنامج سيقرأ سطراً واحداً فقط ثم يتوقف. ولكن لو وجد أمر readLine مرة ثانية فسيقرأ المعلومات حول الطالب الثاني وهو "العنزي" ولو وجدها مرة ثالثة سيقرأ المعلومات حول الطالب الثالث و هكذا. فما العمل؟

علينا أن نستخدم أداة التكرار while ---- ففي السطر 17 اكتب هذا الأمر مع الشرط المناسب كما سيتضح لاحقاً

وفي السطر 18 ضع قوس البدء } ل while

وفي السطر 27 ضع قوس الإغلاق المتعلق بجملة while

والأهم من كل ذلك أن تضع أمر القراءة في المكان المناسب ---- بعد أمر الطباعة ---- فنحن بعد أن نطبع المعلومات حول طالب معين سنذهب و نقرأ المعلومات حول الطالب الذي يليه مباشرة و هكذا. إذن سنضع أمر القراءة x.readLine في السطر 26

سيصبح البرنامج بعد التعديل على الشكل التالي: فقط سنقتبس الأجزاء التي تمكننا من القراءة من أجل التوضيح:

16 line = x.readLine(); 17 while ( ضع هنا جملة شرطية تخبرك هل وصلت القراءة الى اخر سطر أم لازالت؟) 18 { 19 StringTokenizer data = new StringTokenizer(line); 20 21 studName = data.nextToken(); 22 serialNum = Integer.parseInt(data.nextToken()); 23 grade = Double.parseDouble(data.nextToken()); 24 25 System.out.println(serialNum + "\t" + StudName + "\t" + grade); 26 line = x.readLine(); 27 }

السطر السابع عشر:

while ( ضع هنا جملة شرطية تخبرك هل وصلت القراءة الى اخر سطر أم لازالت؟)

هذا السطر يجب أن يكتب على الشكل التالي:

while ( line != null)

ففي السطر 16 قرأ البرنامج السطر الأول وخزن القيمة في line و أصبحت line تساوي:

line = "Al-Shehri 01 87.00"

يقارن البرنامج هذه القيمة مع null و هي إحدى الكلمات الرئيسية keywords في لغة الجافا و تعني فراغ أو لاشئ أو "فاي" --- تتم المقارنة من خلال علامة عدم التساوي =! . طبعاً قيمة line في هذه الحالة لاتساوي null --- لذلك الشرط صحيح --- وبالتالي سينفذ البرنامج مابداخل أقواس while كما شرحناها بالأمس --- سيفكك line أولاً ثم يخزن القيم في data و بعد ذلك يتم توزيعها على المتغيرات studName و نقصد بها هنا اسم الطالب و serialNum و نقصد بها رقم الطالب التسلسلي و grade ونقصد بها درجة الطالب النهائية --- ثم سيطبع البرنامج المعلومات حول هذا الطالب.

بعد أمر الطباعة سيجد البرنامج أمر القراءة x.readLine ---- سيقرأ السطر الثاني في السلسلة وستصبح قيمة line الان على النحو التالي:

line = "Al-Anzi 02 91.75"

يجد قوس الإغلاق { المتعلق ب while والذي يعيده الى السطر 17 ---- سطر جملة while ويقارن معلومات line مرة أخرى "هل هي لاتساوي null أم لا؟" سيجد أن الشرط صحيح --- لذلك سيفعل نفس الشئ كما سبق ثم سيقرأ معلومات السطر الثالث و الرابع و الخامس و حتى السطر 14 وفي كل مرة و بعد أن يقرأ يقارن ثم يفكك ثم يميز و يطبع الجواب.

وبعد أن ينتهي من طباعة المعلومات حول الطالب الرابع عشر و الأخير وهو "الزهراني" سيقرأ البرنامج السطر الخامس عشر --- ولكنه لن يجد فيه أي قيم ----- بل عبارة عن فراغ كما ترى أعينكم ---- في هذه الحالة ستصبح قيمة المتغير line على النحو التالي:

line = null

أي "لاشئ" أو "لم أجد شيئاً" --- يعود و يقارنها في السطر 17 و يجد أن الشرط غير صحيح و بالتالي يعلن انتهاء القراءة و يخرج البرنامج من أقواس while نهائياً. ويتفاجأ بوجود أمر إغلاق الملف x.colse في السطر 28 وهذا الأمر ضروري فأي ملف خارجي نستخدمه يجب أن نغلقه بعد الانتهاء من استخدامه. دائماً يحبذ وضع أمر إغلاق الملف في السطر الأخير قبل أقواس الإغلاق التي تعودنا عليها --- كما في حالتنا هذه.

و الان البرنامج السابق سأعيد كتابته هنا و لكن من غير رقم الأسطر والتي وضعت هنا للتوضيح لكي يتسنى لك نسخه لمحرر الجافا و تنفيذه.

import java.io.*; import java.util.*; import java.text.*; public class Lesson37c { public static void main( String[ ] args) throws IOException { String line; FileReader xyz = new FileReader("inputdata.txt"); BufferedReader x = new BufferedReader(xyz); String studName; double grade; int serialNum; line = x.readLine(); while ( line != null) { StringTokenizer data = new StringTokenizer(line); studName = data.nextToken(); serialNum = Integer.parseInt(data.nextToken()); grade = Double.parseDouble(data.nextToken()); System.out.println(serialNum + "\t" + studName + "\t" + grade); line = x.readLine(); } x.close(); } }

بعد ترجمة "تصحيح" ثم تنفيذ هذا البرنامج سيعرض التالي على ال console window

1 Al-Shehri 87.0 2 Al-Anzi 91.75 3 Al-Qahtani 81.31 4 Al-Saud 89.57 5 Al-Dhafiri 95.09 6 Al-Asiri 91.07 7 Al-Shammari 89.47 8 Al-Hajri 83.25 9 Al-Mustakawi 99.56 10 Al-Humood 93.12 11 Al-Shahrani 98.73 10 Al-Matrood 84.43 11 Al-Utaibi 88.25 12 Al-Yami 86.74 13 Al-Ghamdi 92.88 14 Al-Zahrani 85.31 Press any key to continue...

ملحوطة مهمة: ملف المعلومات inputdata.txt و برنامج الجافا Lesson37c.java يجب أن تكون في نفس الدليل "Directory" ---- أي شئ عدا ذلك أمر غير مقبول البتة ! ! ! !

الى اللقاء مع الجزء الثالث 37 -3  من هذا الدرس و هو أمثلة تطبيقية مكثفة على هذا الردس.

الدرس 38 : سيكون حول كيفية عرض الناتج النهائي على console window كما تعودنا ولكن مع إضافة أشياء جميلة ستعجبكم و تجعلكم تحبون هذه اللغة أكثر. كلي ثقة أنها ستعجبكم و أراهن على ذلك بكل ثقلي ---- انتظرووووووووووو

 



 
 

 

  محمد سفر العتيبي 22-6-2003 11:00 45.  

الدرس السابع و الثلاثون (37-3)
Handling input/Output I/O Data
كيفية تغذية البرنامج بالمعلومات و عرض الناتج النهائي
Reading Data from External Files
قراءة المعلومات من ملف خارجي مستقل معد مسبقاً

أمثلة تطبيقية مكثفة

المثال الأول:

الملف التالي يحتوي على معلومات حول كشف الرصيد السنوي لعملاء أحد البنوك --- حيث يحتوي العمود الأول على اسماء العملاء الأولى --- فكل حرف أبجدي يني اسم عميل -- و العمود الثاني يشتمل على الرصيد الحالي بالريال السعودي في البنك و المطلوب هو حساب الزكاة المقابلة لكل رصيد شخص ثم حساب مجموع ماتم جمعه من أموال الزكاة من هؤلاء الأشخاص. وكم يتبقى في رصيد كل شخص بعد حسم زكاة المال. علماً أن معادلة زكاة المال الرياضية شرعاُ هي2.5 ريال سعودي مقابل كل 100 ريال سعودي أي 2.5% من مجموع المال. احفظ هذ الملف كما اتفقنا فيما سلف باسم inputdata.txt

خطوات الحل:

1. قراءة المعلومة من الملف الخارجي حول الشخص الأول

2. حساب الزكاة لكل شخص ثم جمعها على ماسبق وحساب كم يتبقى في رصيد الشخص.

3. طباعة الجواب

4. العودة لقراءة المعلومات حول الشخص الثاني و تنفيذ الخطوات الثلاثة السابقة و هكذا لبقية الأشخاص حتى الوصول لنهاية الملف.

سيكون البرنامج على الشكل التالي:

و الان البرنامج السابق سأعيد كتابته هنا و لكن من غير رقم الأسطر والتي وضعت هنا للتوضيح لكي يتسنى لك نسخه لمحرر الجافا و تنفيذه.

import java.io.*; import java.util.*; import java.text.*; public class Lesson37d { public static void main( String[ ] args) throws IOException { String line; FileReader xyz = new FileReader("inputdata.txt"); BufferedReader x = new BufferedReader(xyz); String costumerName; int personDeposit, zakatMoney, remainMoney, total= 0; line = x.readLine(); System.out.println("Name\t\tDeposit\t\tzakat\t\tRemain"); System.out.println("--------------------------------------------------"); while ( line != null) { StringTokenizer data = new StringTokenizer(line); costumerName = data.nextToken(); personDeposit = Integer.parseInt(data.nextToken()); zakatMoney = (25*personDeposit)/1000; remainMoney = personDeposit - zakatMoney; total = total + zakatMoney; System.out.println(costumerName + "\t" + personDeposit + "\t" + zakatMoney+ "\t" + remainMoney); line = x.readLine(); } System.out.println("\n\nTotal = " + total + " SR\n\n"); x.close(); } }

بعد ترجمة "تصحيح" ثم تنفيذ هذا البرنامج سيعرض التالي على ال console window

Name Deposit zakat Remain ------------------------------------------------------ A 165000 4125 160875 B 311037 7775 303262 C 103100 2577 100523 D 650010 16250 633760 E 131037 3275 127762 F 3120100 78002 3042098 G 165000 4125 160875 H 551037 13775 537262 I 10990 274 10716 G 765500 19137 746363 K 45334 1133 44201 L 65342 1633 63709 M 213460 5336 208124 N 21000 525 20475 O 40000 1000 39000 P 65000 1625 63375 Q 70650 1766 68884 R 237680 5942 231738 S 210055 5251 204804 T 76100 1902 74198 U 2210100 55252 2154848 V 265000 6625 258375 W 431037 10775 420262 X 410100 10252 399848 Y 365000 9125 355875 Z 391037 9775 381262 - Total = 277232 SR - Press any key to continue...

طبعاً لو استخدمت الورقة و القلم ستجد ان مجموع الزكاة هو 277232 ريال سعودي للأرصدة المذكورة وهو مايتفق مع الجواب أعلاه ---- هذا سيستغرق منك حوالي نصف ساعة --- و بإستخدام الألة الحاسبة قد يستغرق 10 دقائق ولكن عن طريق البرمجة سيستغرق الحساب أقل من 5 ثواني. تخيل أن عدد عملاء البنك عدة الاف ---- أيضاً سيستغرق أقل من خمس ثواني لكي تعرف مجموع زكاة أموال هؤلاء الألاف.

الشرح الأخير موجه على وجه الخصوص لمن ليس لديهم أي خلفية عن البرمجة و أهميتها.

المثال الثاني:

الأن المطلوب منك أن تكتب برنامجاً يفتح ملفاً معينا و يعرف عدد الكلمات فيه فقط --- لاشك أنكم تتذكرون عندما قلنا أن مهمة StringTokenizer هي لفرز عدد المعلومات في ملف معين --- فقط المطلوب هو عدد الكلمات في هذه الملف. هذا الملف هو الصندوق الأبيض التالي ويحتوي بداخله على الترجمة الإنجليزية لمعنى الأية الكريمة "وجعلناكم شعوباً و قبائل لتعارفوا , إن أكرمكم عند الله أتقاكم" ---- انسخ هذا الملف الى المفكرة و احفظه تحت اسم ayah.txt

خطوات الحل:

1. قراءة جميع محتويات هذا الملف مرة واحدة.

2. إحصاء عدد المعلومات "الكلمات" في هذا الملف من خلال أمر StringTokenizer فهذا الأمر سيفرز الكلمات والتي تستطيع ان تعرفها أنت من خلال أمر جديد ينتمي الى ال StringTokenizer --- هذا الأمر الجديد هو () countTokens والذي يعطيك العدد الدقيق لكل سطر تتم قراءته.

ملحوظة: في الدرسين السابقين عرفنا nextToken و ماهي وظيفتها و مثلها مثل countToken --- أي انهما تنتميان ل StringTokenizer --- وسيتم التوقف عندها و بقية أوامر القراءة التي أجلنا شرحها في الدرس 41 إن شاء الله.

import java.io.*; import java.util.*; public class Lesson37e { public static void main( String[] args) throws IOException { FileReader mohammed = new FileReader("ayah.txt"); BufferedReader ahmed = new BufferedReader(mohammed); String line; int number, numberOfWords = 0; line = ahmed.readLine(); while (line != null) { StringTokenizer data = new StringTokenizer(line); number = data.countTokens (); numberOfWords = numberOfWords + number; line = ahmed.readLine(); } System.out.println("There are " + numberOfWords + " words"); ahmed.close(); } }

بعد ترجمة "تصحيح" ثم تنفيذ هذا البرنامج سيعرض التالي على ال console window

There are 34 words Press any key to continue...

و كما هو واضح من ال output فهناك 34 كلمة في النص السابق. هل عددتها قبل تنفيذ البرنامج؟ لو فعلت ستجد أن هناك 34 كلمة.

سؤال منزلي: في البرنامج الأخير Lesson37e.java أدخل نصاً تعبيرياً في ملف القراءة -- ثم أعد تنفيذ البرنامج. هل سيعطيك الجواب الصحيح حول عدد الكلمات التي كتبتها في النص التعبيري؟

 



 
 

 

  محمد سفر العتيبي 24-6-2003 12:57 46.  

الدرس السابع و الثلاثون (38)
Handling input/Output I/O Data
كيفية تغذية البرنامج بالمعلومات و عرض الناتج النهائي
Displaying Output Data on I/O Console Window
كيفية عرض الناتج على الشاشة

عبارة أمر الطباعة التي نعرفها و استخدمناها بكثرة هي:

System.out.println( هنا ماتود طباعته );

لاشك ان المقطع System.out.println طويل نوعاً ما كتابة --- ولكن لغة الجافا تمكنك من اختصاره الى أقل مايمكن ---- فيمكنك حذف المقطع System.out وكتابة متغير من حرف واحد أو عدة أحرف مكانه. افترض ان هذا المتغير هو a سيصبح أمر الطباعة على النحو التالي:

a.println( هنا ماتود طباعته );

معنى هذا أن برنامج الجافا يجب أن يفهم أن المتغير a هو:

a تساوي System.out

ولكن كيف سيتم هذا؟ يجب علينا أن نعرف و كعادتنا المتغير أولاً فالبرنامج لن يفهم أي متغير نختاره الى بعد تعريفه ---- ففي حالتنا هذه يجب تعريف المتغير a من خلال أمر تعريف الطباعة أو العرض ---- هذا الأمر يجب ان يكون على النحو التالي:

static PrintWriter a = new PrintWriter( System.out, true);

فبرنامج الجافا سيفهم أن المتغير a ببساطة انه يعادل System.out و هذا السطر نتعامل معه تماماً كما تعاملنا مع سطر التهئية للقراءة من ال console window في الدرس 36 -2 و هو:

static BufferedReader g = new BufferedReader( new InputStreamReader( System.in));

ففي حقيقة الأمر كلاهما وجهان لعملة واحدة. ولكن أحدهما لتعريف العرض "أي عرض الجواب النهائي على الشاشة السوداء" و الأخر لتعريف القراءة "أي قراءة المداخيل من خلال تلك الشاشة "

و نقصد أنهما يعاملنا بالمثل أمرين على وجه التحديد وهو ضرورة اشتمال البرنامج على رابط مكتبة القراءة و العرض التالي و التي توضع في مقدمة البرنامج:

import java.io.*;

والأمر الثاني هو أنهما يوضعان بعد تعريف ال class و قبل ال main method --- بعبارة أخرى يجب أن يكونا خارج كتلة main

سنضع السطرين تحت بعضهما هنا للتوضيح للعين المجردة:

static BufferedReader g = new BufferedReader( new InputStreamReader( System.in)); static PrintWriter a = new PrintWriter ( System.out, true);

فكلاهما يبدأ ب كلمة static وسيأتي شرح معناها بعد أن ننتهي من هذه الأساسيات وذلك في الدرس 41.

و بعدها يأتي أمر التعريف الخاص -- BufferedReader للقراءة و PrintWriter للعرض --- دعونا نعتبر هذين الأمرين وجهين لعملة واحدة --

ثم بعد ذلك اسم المتغير الذي يضعه المستخدم للرجوع لهذين الأمر و الارتباط بمكتبة الجافا للاستفادة من أحد رفوف مكتبتها المخصصة لأوامر الطباعة أو القراءة. في مثالنا هذا اخترت المتغير g للقراءة والمتغير a للطباعة.

ثم علامة المساواة "ليس التساوي" و بعدها أمر new و تعني مجازياً و فهماً "اخلق أو إصنع شئ جديد". لست مرتاحاً نفسياً و لأسباب عقائدية لإستخدام لفظة "اخلق" رغم أنها أكثر دقة للتعبير عما سيحدث. سأستخدم كلمة "اصنع" لتعبر عن نفس المعنى بعد ذلك رغم أن لفظة "اخلق" هي التي على طرف لساني.

System.in و System.out أيضاً اعتبرهما وجهين لعلمة واحدة. الأولى تتعلق بالقراءة و الثانية للطباعة أو العرض. لاحظ in و هي مختصر input وتعني المداخيل و out و هي اختصار output و تعني المخارج أو الجواب النهائي.

ملحوظة: لست مقتنعاً بتسميتي "المداخيل" و "المخارج" ---- هل تستطيع مراسلتي و إسعافي لكلمات أكثر دقة و يفهمها الغير --- فللأسف أكثر تراجم مجمعات اللغة العربية لم اقتنع بها و تحتاج الى من يترجمها مرة أخرى.

مثال 1:

import java.io.*; public class Lesson38a { static PrintWriter x = new PrintWriter( System.out, true); public static void main (String[] args) throws IOException { x.print("int: "); int n1 = 55; x.println(n1); x.print("double: "); double n2 = 77.098; x.println(n2); x.print("float: "); float n3 = 13.34f; x.println(n3); x.print("byte: "); byte n4 = 127; x.println(n4); x.print("short: "); short n5 = 67; x.println(n5); x.print("long: "); long n6 = 14; x.println(n6); x.print( "boolean: " ); boolean n7 = true; x.println(n7); x.print("String: "); String n8 = "Je suis Arabite Saoudite" ; x.println(n8); } }

في مثالنا هذا استخدمنا المتغير x هنا لكي يكون "واساطتنا" لدى مكتبة الجافا "ما اسم هذه المكتبة؟" لنستفيد من خدماتها وتسهيلاتها من أجل عرض الجواب النهائي. نفذ البرنامج سيكون جوابك على الشكل التالي:

int: 55 double: 77.098 float: 13.34 byte: 127 short: 67 long: 14 boolean: true String: Je suis Arabite Saoudite Press any key to continue...

سؤال منزلي 1: عدل قيمة المتغير n4 والذي عرف من خلال أمر التعريف byte من 127 كما هو في البرنامج السابق الى 128 ---- ما الذي سيحدث بعد ترجمة "compile" البرنامج؟

تنويه: لاتنفذ "execute" البرنامج إذا كان هناك اخطاء بعد الترجمة"compile" ولكن إذا فعلت سيظهر معك الجواب السابق قبل التعديل --- وهو ليس الجواب المطلوب.

------------------------------------------------------------------

ننتقل الأن الى نقطة أخرى وهو عند استخدام أمري القراءة و الكتابة معاً في نفس البرنامج ---- تقريباً لايتغير أي شئ و لكن يحبذ "يجب" أن نستخدم السطر التالي ليفصل بين أمر الطباعة println و أمر القراءة ( )readLine

x.flush();

طبعاً المتغير x هو الاسم الذي اختاره المستخدم " أنت " ليحل محل System.out و ()flush هي إحدى الأدوات المتوفرة في مكتبة الجافا java.io لتؤدي وظيفة ما. فما هي هذه الوظيفة؟

قبل الاسترسال في الشرح --- دعونا نفهم البرنامج التالي وهو برنامج كتب ليطلب منك شيئين: اسمك ثم رقمك السري ---- و بعد ذلك يقارن القيم التي أدخلتها هل هي تتطابق مع مايفترض أن تدخله أم لا --- فالمفروض أن يكون اسمك "khalid" ورقمك السري "yx1234" ----- إن تطابقت سيعرض البرنامج عبارة ترحيبية "Welcome" ---- و إن لم تتطابق بياناتك مع البيانات الموجودة سيقول لك أسف أنت غير مسموح لك بالدخول "Sorry, you are not allowed"

import java.io.*; public class Password4 { static BufferedReader keyboard = new BufferedReader( new InputStreamReader( System.in)); static PrintWriter screen = new PrintWriter( System.out, true); public static void main (String[] args) throws IOException { String name, password; screen.print( "What is your name? "); screen.flush(); name = keyboard.readLine(); screen.print( "What is your password? "); screen.flush(); password = keyboard.readLine(); if (name.equals( "Khalid") && password.equals( "yx1234" )) screen.println( "Welcome " + name); else screen.println( "Sorry, you are not allowed" ); } }

سنقتبس الأسطر التالية من البرنامج:

screen.print( "What is your name? "); screen.flush(); name = keyboard.readLine();

السطر الأول هو أمر الطباعة حيث سيطبع البرنامج "What is your name" أي "ما اسمك"و السطر الثالث هو أمر إدخال "قراءة" الاسم ----- نريد القول أننا استخدمنا أمري الطباعة و القراءة عبر ال console window "الشاشة السوداء" ----- في هذه الحالة لابد من وجود فاصل بين الأمرين و هذا الفاصل هو ()flush في السطر الثاني والذي يرتبط بمتغير الطباعة -- screen في حالتنا هذه -- و ليس متغير أمر القراءة و الذي اخترنا اسمه ليكون keyboard--- لماذا؟ وماذا سيحدث لو لم نستخدم هذا الأمر screen للفصل بين أمر الطباعة و القراءة؟ الجواب سيكون في نهاية هذا الدرس ولكن أكرر أنه لايستخدم الا للفصل بين الأمرين -- ففي البرنامج السابق و في الأسطر الأخيرة هناك أوامر طباعة لم نستخدم بعدها أمر ()flush لعدم وجود أوامر قراءة أخرى خلف أوامر الطباعة تلك.

ناتج البرنامج السابق بعد تنفيذه سيكون: أدخل كلمة khalid عندما يطلب منك الاسم و أدخل xy1234 عندما يطلب منك الرقم السري

What's your ID? khalid What's the password? xy1234 Welcome khalid Press any key to continue...

القيم "المعلومات" باللون الأخضر هي ماتغذيه أنت للبرنامج و المعلومات باللون الأصفر هي محصلة البرنامج --- و استخدمت الألوان هنا لغرض الشرح فقط.

و الأن في عدم وجود أمر ()flush --- أي لو مسحنا جميع أسطر ()screen.flush كيف سيكون عرض محصلة البرنامج بعد ترجمته و تنفيذه. سيكون على النحو التالي:

khalid xy1234 What's your ID? What's the password? Welcome khalid Press any key to continue.

هل أدركتكم من كيفية عرض الجوابين ماهي وظيفة ()flush ---- ففي حالة عدم وجود هذا الأمر سيتجاهل البرنامج وجود أمر أي طباعة حتى ينتهي من جميع أوامر القراءة ---- بعد ذلك يعود لأوامر الطباعة التي تجاوزها سابقاً ثم يطبعها على التوالي --- و هذا ليس أمر جيد. المزيد من التعليق في الدرس 41

---------------------------------------------------

في البرنامج السابق ورد أمر جديد لم نستخدمه من قبل هذا الأمر هو equals ---- ففي درس أدوات المقارنة الذي سبق و مر علينا في الدرس 18 ناقشنا جميع أدوات المقارنة الرمزية مثل و > و < و => و = < و == و = ! وتعمدت أن أتجاهل ذكر شئ خاص حول أدوات المقارنة. فجميع هذه الأدوات تستخدم مع جميع الأنواع التعريفية مثل int و double و String الا في حالات خاصة و هي مقارنة المعلومات من نوع String --- أي أن استخدام == لمقارنة هذا النوع مرفوض تماماً و لا معنى له البتة. بل يجب استخدام الأمر equals في هذه الحالة --- ففي جملة if في البرنامج السابق و نعيدها هنا:

if (name.equals("Khalid") && password.equals("yx1234"))

تم استخدام الأمر equals وذلك مع المتغير name و الذي عرفنا نوعه ليكون String --- و المقانة هنا ستتم بين قيمة name و القيمة داخل الأقواس و هي "khalid" --- فإن تطابقت ستكون قيمة المقارنة true و إن اختلفت ستكون قيمة المقارنة false ---- هذه هي الصورة الصحيحة لمقارنة التساوي و ذلك من خلال أمر equals و ليس = = ----- فالصورة التالية مرفوضة تماماً:

if (name == "Khalid" && password == "yx1234")

أيضاً بعض أدوات المقارنة الأخرى لايمكن استخدامها مع المتغيرات من نوع String و سيكون لها درس مستقل في Tips#7 إن شاء الله بالإضافة لمواضيع متفرقة تتعلق بنوع String

المعذرة على الإطالة و إلى اللقاء في الدرس 39 حول كيفية عرض محصلة البرنامج في ملف مستقل بدلاً من عرضه على ال console window --- ففي الدرس القادم سنتعلم كيف سيفتح برنامج الجافا الذي كتبناه ملفاً لم يكن على جهازك من قبل ثم يضع فيه النتائج بدلاً من عرضها على ال console window ---

الى اللقاء و باقي من الزمن 7 دروس قبل أن نبدأ معاً الإحتراف. احتراف ماذا؟ أبداً لاشئ لاشئ

الى اللقاء - صار وداع سودانيين ! ! ! ! ! ! ! ! ! ! !

 



 

 

  محمد سفر العتيبي 02-7-2003 17:44 48.  

الدرس و الأربعون(40-1)
Mathemetical Intrensic Functions
كيفية التعامل مع الدوال الرياضية الداخلية من خلال لغة الجافا

يوجد هناك بعض الدوال الرياضية الخاصة و التي على الأقل كلنا يعرف بعضها - فهناك الدوال الهندسية و هناك بعض الثوابت الرياضية الشهيرة مثل الأساس اللوغاريثمي الطبيعي و هناك ط وهو الثابت الذي يستخدم في حساب محيط الدائرة أو مساحتها و هناك أشياء غيرها. أطلقنا عليها كلمة "خاصة" لأنها تعامل معاملة خاصة في لغة الجافا تختلف عن معاملتها في اللغات المتطورة الأخرى مثل الفورتران مثلاُ.

فإحدى مكتبات الجافا و اسمها:

java.lang.Math

يوجد بها أكثر من 20 دالة رياضية معرفة بداخلها ---لذلك عند استخدام هذه الدوال يجب أن يشتمل برنامجنا على السطر أعلاه كما تعاملنا مع مكتبة I/O من قبل. سنبدأ بالثوابت أولاُ:

الثابتان الرياضيان الشهيران : PI  و  E

يوجد هناك الثابتان الشهيران في علم الرياضيات وهما ط الذي يستخدم في حساب مساحة أو محيط الدائرة ورمزه "PI" --- تنطق باي --- و  أساس اللوغاريثمات الطبيعية "natural logarithems" ورمزه حرف E ---- حيث أن:

E = 2.7182818284590452353602874713527 PI = 3.1415926535897932384626433832795

الدوال الهندسية: Trigonometric Functions

هناك دوال كثيرة ولكن إذا اتى بعدها كلمة "هندسية" فتذكر على الفور دوال الجيب "sine" و اختصارها على حاسبتك اليدوية sin و جيب التمام "cosine" و اختصارها  cos و الظل "tangent" و  اختصارها tan

هذه الإختصارات تستخدم في لغة الجافا كما هي في التك الحاسبة على النحو التالي:

cos(60o) = 1/2 sin(90o) = 1 tan(45o) = 1

في الأمثلة السابقة تم استخدام النظام الستيني ولكن في لغة الجافا فيجب استخدام النظام الاخر المكافئ له وهو نظام الراديان فبدلاً من 180 درجة استخدم مكافيها و هو PI و 90 درجة مكافئها PI/2 و هطاذ

وهي دوال يتم دراستها في المرحلة الثانوية --- فإن كنت لم تصل الى هذه المرحلة - فلاتكمل قراءة هذا الجزء و اذهب للجزء الذي بعده

الأمثلة الثالثة السابقة ستكون على النحو التالي:

cos(60o) = cos(PI/3) = 1/2 sin(90o) = sin(PI/2) = 1 tan(45o) = tan(PI/4) = 1

معكوس الدوال الهندسية: Inverse Trigonometric Functions

هي نفس الدوال السابقة ولكن بالعكس أي أن الجواب في الأمثلة السابقة سيكون داخل الأقواس و مابداخل الأقواس هو الجواب المفترض ---- أي عملية عكسية. فلو أعطيت الزواية فأنت ستستخدم الأمثلة السابقة ولكن لو أعطيت قيم الدوال الهندسية فأنت في هذه الحالة مطالب بإيجاد الزاوية--- سيكون ذلك على النحو التالي:

هذه الإختصارات تستخدم في لغة الجافا كما هي في التك الحاسبة على النحو التالي:

cos-1(1/2) = 60o= PI/3 sin-1(1) = 90o= PI/2 tan-1(1) = 45o= PI/4

في لغة الجافا سيكون الجواب بالراديان و ليس بنظام الدرجات الستيني و تكتب تلك الدوال على النحو التالي:

acos(1/2) = PI/3 asin(1) = PI/2 atan(1) = PI/4

و قيمة PI هي القيمة التي ذكرت سابقاً

القيمة المطلقة: absolute value

القيمة المطلقة لأي عدد سواءً كان سالباً أو موجباً هي القيمة الموجبة لذلك العدد ----  رياضياً يرمز للقيمة المطلقة للعد س بهذا الرمز | س | و الأمثلة التالية توضح كيفية عمل القيمة المطلقة:

|3.2|= 3.2 |-3.2| = 3.2

وتقريباً في كل لغات البرمجة بالإضافة الى الجافا نحصل على القيمة المطلقة لأي عدد بإستخدام أمر ()abs على النحو التالي:

abs(2.3) = 2.3 abs(-2.3) = 2.3

القيمة الأكبر و الأصغر: Maximum & minimum value

لو كان لدينا رقمين مختلفين فإن الجافا تمكنك من تحديد الأكبر منهما بإستخدام الأمر max ---- بينما لو كنت تريد أن تعرف أيهما أصغر فاختر أمر min -- سيكون ذلك على النحو التالي:

max(19.7 , 12.5) = 19.7 min(200 , 301) = 200

فبين القوسين نضع الرقمين و بينهما فاصلة ---- لاتنسى الفاصلة ----- و دالة max تعطينا أي الرقمين بين القوسين أكبر و الدال min تحدد أيهما أصغر

الجذر التربيعي : square-root

الجذر التربيعي للعدد 16 هو 4 و الجذر التربيعي للعدد 169 مثلاُ يساوي 13 و هكذا ---- في لغة الجافا نستحدم اختصار كلمة square-root لإيجاد الجذر التربيعي لأي عدد موجب. وكما قلنا سابقاً أن الجذر التربيعي للأعداد السالبة هو إحد "الكبائر الأربعة" في علم الرياضيات. لذا يجب الحذر --- الاختصار هو ()sqrt --- وسيكون على النحو التالي:

sqrt(16) = 4 sqrt(21) = 4.5825757 sqrt(169) = 13

يتبقى لدينا النقطة الأهم وهو أن كل دالة من الدوال السابقة أو في درس الغد يجب أن تسبق بكلمة Math و يفصل بينهما نقطة. هذه النقطة و التي ترجمناها من قبل الى "ابنة". و تعني أن جميع هذه الدوال بنات لمكتبة الرياضيات في الجافا و اسم هذه المكتبة هو و كما ذكرنا سابقاً:

java.lang.Math

الأمثلة التالية للتوضيح:

Math.PI = 3.14159265359 Math.E = 2.71828182846 Math.cos(PI/3) = 0.5 Math.sin(PI/6) = 0.5 Math.tan(PI/4) = 1 Math.acos(0.5) = PI/3 = 1.0471975511966 Math.asin(0.5) = PI/6 = 0.5235987755983 Math.atan(1.0) = PI/4 = 0.7853981633974 Math.abs(-100) = 100 Math.max(5,9) = 9 Math.min(5,9) = 5 Math.sqrt(196) = 13

فتعالوا معاً نثبت القيم "باللون الاحمر" من خلال البرنامج التالي:

import java.lang.Math; class lesson40a { static void main (String[] args) { System.out.println("PI = " + Math.PI); System.out.println("E = " + Math.E); System.out.println("SQRT(169) = " + Math.sqrt(169)); System.out.println("cos(60) = " + Math.cos(Math.PI/3)); System.out.println("sin(30) = " + Math.sin(Math.PI/6)); System.out.println("tan(45) = " + Math.tan(Math.PI/4)); System.out.println("acos(0.5) = " + Math.acos(0.5)); System.out.println("asin(0.5) = " + Math.asin(0.5)); System.out.println("atan(1.0) = " + Math.atan(1.0)); System.out.println("|-100| = " + Math.abs(-100)); System.out.println("max(5,9) = " + Math.max(5,9)); System.out.println("min(5,9) = " + Math.min(5,9)); } }

إلى اللقاء مع الجزء الثاني 40-2



ـ ــ أشلاءــ ـو مـ الكلمةـ ـاجاورها

 

  محمد سفر العتيبي 03-7-2003 21:20 49.  

الدرس الأربعون(40-2)
Mathemetical Intrensic Functions
كيفية التعامل مع الدوال الرياضية الداخلية من خلال لغة الجافا

اليوم نتطرق الى خسمة دوال اخرى توجد في مكتبة الجافا المسماة

java.lang.Math

الجزء الصحيح من عدد عشري: سقفه الأعلى وحده الأدنى: ceil & floor

يوجد هناك 4 أدوات لإشتقاق جزء العدد الصحيح من العدد العشري أو الكسري. و لفهم أفضل افترض أن ادينا العدد 2.345 ----- هذا العدد يعتبر عدداً عشرياً أو كسرياً ولكن يمكن حصره بين رقمين صحيحين وهما 3 و 2 بحكم انه يقع بينهما.

من خلال لغة الجافا نستطيع أن نشتق الحد الصحيح الأعلى للرقم السابق بإستخدام أمر ceil و تعني سقف ---- و يقصد بها هنا سقف ذلك الرقم --- و كما نعلم السقف هو الحد الأعلى لأي شئ. سقف الرقم السابق هو 3.

ولكن لو أردنا الحد الأدنى للرقم السابق فإننا نستخدم أمر floor و تعني "أرضية" و الأرضية هي الحد الأدنى للشئ. أرضية الرقم السابق تساوي 2.

بعبارة أخرى أمر ceil و floor تستخدم للتعامل مع الأعداد الحقيقية غير الصحيحة ويعطينا أمر ceil أقرب عدد صحيح فوق العدد المعطى و أمر floor يعطينا أقرب أصغر عدد صحيح تحت ذلك الرقم. و هذان الأمران يوجدان في لغات البرمجة الأخرى أيضاً من أجل الغرض نفسه. مع الأمثلة التالية:

floor(2.343) = 2 floor(-2.343) = -3 floor(12.99999) = 12 floor(-20.0000001) = -21 floor(15.0) = 15 ceil(2.343) = 3 ceil(-2.343) = -2 ceil(12.003) = 13 ceil(-20.0000001) = -20 ceil(15.0) = 15 ceil(sqrt(2)) = 2 // سقف الجذر التربيعي ل 2

قلنا أن هناك 4 أدوات لاشتقاق العدد الصحيح --- ذكرنا اثنتين فماهي الأداة الثالثة؟

الجزء الصحيح الأقرب من عدد عشري:round

هذا هو الأمر الثالث الذي يستخدم لتقريب العدد الصحيح الى أقرب عدد من الرقم العشري المعطي. فمثلاُ الرقم 4.7 يقع بين العددين الصحيحين 4 و 5 و لكنه أقرب الى الرقم 5 ---- إذن محصلة هذا الأمر ستكون 5. لو كان الرقم المعطى 4.48 فإن المحصلة في هذه الحالة ستكون 4. لأن رقم 4 أقرب الى هذا الرقم من رقم 5.

المشكلة تحدث عندما يكون الرقم في المنتصف تماماً ---- في هذه الحالة ماذا سيكون جواب أمر round لو كان الرقم 4.5؟

جواب: في هذه الحالة سيأخذ الحد الصحيح الأعلى---- أي أن الجواب سيكون الرقم الصحيح 5 --- أي سيتم التعامل معه و كأن الأمر ceil الذي ورد سابقاً. مع الأمثلة التالية:

round(2.4) = 2 round(2.6) = 3 round(2.5) = 3 round(-2.4) = -2 round(-2.5) = -2 round(-2.6) = -3 round(2.49999999) = 2 round(-2.4999999) = -2 round(-2.50000000001) = -3

الجزء الصحيح من عدد عشري بإستخدام أمر rint

هذا هو الأمر الرابع الذي يستخدم لتقريب العدد الصحيح الى أقرب عدد من الرقم العشري المعطي وهو مثل أمر round و لكنه يعطينا الجواب بصورته العشرية --- فمثلاُ تقريب العدد العشري 2.333 هو 2 بصورته الصحيحة و 2.0 بصورته العشرية. فهما نطقاً نفس الشئ و كتابة يختلفان. ويختلف عن أمر round عندما يكون الرقم العشري في المنتصف تماماً بين رقمين صحيحين مثل 3.5 أو 4.5 و هكذا

فبإستخدام أمر round فإن 3.5 تصبح 4 و 4.5 تصبح 5

ولكن بإستخدام أمر rint فإن البرنامج يسأل نفسه عن نوع الجزء الصحيح من العدد العشري لدينا--- هل هو عدد زوجي أو فردي؟ ----- إن كان زوجياً فإن الجواب سيكون الحد الأدنى من الرقم العشري و إن كان فردياً سيكون الجواب الحد الأعلى. فمثلاُ الجزء الصحيح من العدد 3.5 هو 3 وهو عدد فردي --- إذن الجواب سيكون 4.0 الحد الصحيح العلى للرقم 3.5

ولكن 2.5 جزءه الصحيح هو 2 وهو عدد زوجي --- إذن الجواب سيكون الحد الأدنى للعدد 2.5 وهو 2.0 ----- لاحظوا أنني كتبت 4.0 و 2.0 ولم أكتب 2 و 4 و إذا عرفنا ماذا يعني المختصر rint لزال عجبنا

rintهي اختصار لكلمتي real integer و تعني العدد الصحيح ولكن بصورة عشرية ----- فالعدد 2 عدد صحيح بصورة صحيحة بينما العدد 2.0 عدد صحيح أو كلي و لكن بصورة عشرية. مع الأمثلة التالية:

rint(2.4) = 2.0 rint(2.5) = 2.0 rint(2.6) = 3.0 rint(-2.4) = -2.0 rint(-2.5) = -2.0 rint(-2.6) = -3.0 rint(3.4) = 3.0 rint(3.5) = 4.0 rint(3.6) = 4.0 rint(-3.4) = -3.0 rint(-3.5) = -4.0 rint(-3.6) = -4.0

أمر إيجاد باقي القسمة الصحيح IEEEremainder

أداة أيجاد باقي قسمة عددين صحيحن هي % والأمثلة التالية توضح عمل هذه الأداة:

17 % 11 = 6 // باقي قسمة العدد 17 على العدد 11 هو 6 17 % 12 = 5 // باقي قسمة العدد 17 على العدد 12 هو 5

أمر IEEEremainder تقريباً يكافي الأداة % فهذا الأمر يأخذ رقمين ثم يعطينا باقي قسمة الرقم الأول على الرقم الثاني كما في المثالين التاليين وهما نفس المثالين السابقين:

IEEEremander(17,11) = -5 // باقي قسمة العدد 17 على العدد 11 هو 5- ب IEEEremainder(17,12) = 5 // باقي قسمة العدد 17 على العدد 12 هو 5

لماذا جواب (17,11) IEEEremainder كان 5- و ليس 6؟

جواب: 17 لاتقبل القسمة على 11 ---- بل سيكون لهذه القسمة باقي. أقرب عددين من 17 يقبلان القسمة على 11 هما 22 ; القيمة الأكبر من 17 و 11 القيمة الأصغر من 17

هنا سيسأل هذا الأمر نفسه سؤالاً وهو: ماهو العدد الأقرب منهما الى 17 هل هو 22 أم 11 ---- في حالتنا هذه سيكون الجواب 22 هو الأقرب الى الرقم 17 فالمسافة "الفرق" العددية بين الرقم 22 و 17 تساوي 5 بينما المسافة العددية بين 17 و 11 تساوي 6 ---- فالبرنامج أمام جوابين لسؤال واحد وهو:

هل باقي القسمة هنا هو (17-11 ) أم ( 17 -22 ) ----- 22 هي الأقرب الى 17 ------- إذن باقي السقمة سيكون 17 - 22 = 5-

نفس التعليل ينطبق على المثال الثاني وهو لماذا جواب (17,12) IEEEremainder كان 5؟

جواب: 17 لاتقبل القسمة على 12---- بل سيكون لهذه القسمة باقي. أقرب عددين من 17 يقبلان القسمة على 12 هما 24 القيمة الأكبر من 17 و 12 القيمة الأصغر من 17

هنا سيسأل هذا الأمر نفسه سؤالاً وهو: ماهو العدد الأقرب منهما الى 17 هل هو 24 أم 12 ---- في حالتنا هذه سيكون الجواب 12 هو الأقرب الى الرقم 17 فالمسافة "الفرق" العددية بين الرقم 24 و 17 تساوي 7 بينما المسافة العددية بين 17 و 12 تساوي 6 ---- فالبرنامج أمام جوابين لسؤال واحد هو:

هل باقي القسمة هنا هو (17-12) أم ( 17 -24) ----- 12 هو الأقرب الى 17 ------- إذن باقي القسمة سيكون 17 - 12=5

لاحظ أن المثال الثاني يكافئ أداة باقي القسمة % في كيفية عملها  ----- مع الأمثلة الإضافية التالية:

IEEEremainder(53,8)= -3 IEEEremainder(53,9)= -1 IEEEremainder(53,10)= 3 IEEEremainder(53,11)= -2 IEEEremainder(53,12)= 5 IEEEremainder(53,13)= 1 IEEEremainder(53,14)= -3 IEEEremainder(53,15)= -7 IEEEremainder(53,16)= 5 IEEEremainder(53,17)= 2 IEEEremainder(53,18)= -1 IEEEremainder(53,19)= -4 IEEEremainder(53,20)= -7

يتبقى لدينا حتى هذه اللحظة خمسة اوامر توجد في مكتبة الجافا قسم الرياضيات "java.Math" و لم نتطرق لها حتى هذه اللحظة و هي random ---- atan2 ---- exp --- log ---- pow

ستكون هذه الأوامر هي موضوع الجزء الثالث من الدرس 40 بإذن الله تعالى. و قبل الوداع علينا تطبيق هذه الأوامر من خلال لغة الجافا ---- انسخ البرنامج التالي الى محرر الجافا ثم ترجمه و نفذه لترى الأجوبة. لا تنسوا أن الأوامر الرياضية يجب أن تسبق بكلمة Math و يفصل بينهما نقطة ---- كما هو جلي في البرنامج التالي:

import java.lang.Math; class lesson40b { static void main (String[] args) { System.out.println("Floor(8.50) = "+ Math.floor(8.5)); System.out.println("Ceil(8.500) = "+ Math.ceil(8.5)); System.out.println("round(3.49) = "+ Math.round(3.49)); System.out.println("round(3.50) = "+ Math.round(3.5)); System.out.println("round(3.51) = "+ Math.round(3.51)); System.out.println("rint(4.600) = "+ Math.rint(4.6)) ; System.out.println("IEEEremainder(25,7)= "+Math.IEEEremainder(25,7)); } }

سؤال منزلي1: غير الأرقام بداخل أقواس الأوامر في البرنامج ثم اعد ترجمة و تنفيذ البرنامج لترى التغيرات. افعل ذلك عدة مرات لترسيخ وظيفة هذه الأدوات في ذهنك.

سؤال منزلي2: هل أمري ceil و floor ينتجان رقماً صحيحاً بصورة عددية صحيحية مثل 2 أم صورة عددية عشرية مثل 2.0 ؟

إلى اللقاء مع الجزء الثالث و قبل الأخير من هذا الدرس.

الجزء الرابع و الأخير من هذا الدرس سيكون تصميماً مبسطاً للعبة الحظ ---- أرجو ان تنال إعجابكم و خصوصاً أننا سنبني مستقبلاً على هذا التصميم البسيط في الجزء الثاني من هذه السلسلة و المتعلق ب java applets

 



 

 

  محمد سفر العتيبي 11-7-2003 00:55 50.  

الدرس الأربعون(40-4 )
Mathemetical intrensic Functions
كيفية التعامل مع الدوال الرياضية الداخلية من خلال لغة الجافا

اليوم هو الجزء الرابع و الأخير من الدوال الرياضية حيث سنتطرق الى اخر دالتين في مكتبة الجافا و هما atan2 و random

إيجاد الزاوية بين الوتر و المجاور : atan2

هذا الدالة tatn2 تأخذ قيمتين و هما قيمة س على المحور السيني و قيمة ص على المحور الصادي لوتر معين وتعطيك زاوية الميل المحصورة بين الوتر و المحور السيني و تكتب على النحو التالي:

atan(x,y) = زاوية الميلان بالراديان

عندما س = ص فإن الزاوية ستكون 45 درجة أي PI/4 راديان فمع الأمثلة التالية:

import java.lang.Math; class Lesson40e { static void main (String[] args) { double y= 180.0/Math.PI; System.out.println(y*Math.atan2(1.0,1.0)); System.out.println(y*Math.atan2(3.0,1.0)); System.out.println(y*Math.atan2(3.0,0.0)); System.out.println(y*Math.atan2(1.0,0.0)); System.out.println(y*Math.atan2(0.0,2.0)); } } ---------------------------- 45.0 71.56505117707799 90.0 90.0 0.0 Press any key to continue...

الرقم العشوائي :random

هذا الأمر يولد رقماً عشوائياً بين الصفر 0.0 و الواحد 1.0 -- بطبيعة الحال سيكون نوعه double- ويكتب على الشكل التالي:

random()

في البرنامج التالي سنضع هذا الأمر داخل جملة التكرار for لتولد عشوائياً 5 أرقام:

import java.lang.Math; class lesson40f { static void main (String[] args) { int i; double y; for(i=0;i<5;i++) { y= Math.random(); System.out.println(y); } } } // 0.5201718001671531 0.8210485925434656 0.914191925497535 0.6341724731170199 0.5342133356326922 Press any key to continue...

و لو تم تنفيذ البرنامج مرة أخرى سيولد عشوائياً الأرقام التالية:

0.10506412638275975 0.27432580854959343 0.07000337164324777 0.1599578323013987 0.47420020271567676 Press any key to continue...

تخيل أنك مهندس أو باحث في مجال معين و طلب منك مشروع يحتاج الى معلومات جاهزة ولكن هذه المعلومات لاتتوفر لديك --- الحل يكمن في استخدام امر random الذي يولد هذه المعلومات -- فمثلاُ لو كان من المتعارف عليه أن مجال بحثك يعتمد على قيم بين الواحد و 100 مثلاُ فإنك ستستخدم أمر random الذي سيعطيك عدداً موجباً أقل من الواحد --- ثم تضربه أنت في 100 في هذه الحالة سيصبح الرقم لديك بين 100 و الصفر ---- انظر للسطر التالي:

x = 100 * Math.random();

القيمة التي ستتكون لديك ستكون من نوع double -- ولكن إذا أردنا أن نحولها int فقد نستخدم أحد الدوال الرياضية السابقة مثل ceil أو floor أو نستخدم فكرة جديدة تسمى casting و تعني التحويل من نوع عددي الى نوع عددي اخر فلو كان لدينا العدد 5.657 وهو من نوع double فبإمكاننا تحويله الى 5 وهو من نوع int بإستخدام تقنية ال casting تتم هذه التقنية على النحو التالي:

(int)(5.657)

سيكون جواب هذه العبارة 5 و ليس 5.000 أو 5.657 --- أي أن ال casting هنا سيعطينا الجزء الصحيح من العدد ---- في لغة الجافا نقصد بال casting وضع التعريف int قبل العدد ولكن بين قوسين و العدد الذي نريد تحويله أيضاً بين قوسين كما هو مكتوب في الصورة السابقة: البرنامج التالي كتبناه ليولد 5 أرقام عشوائية ثم يطبع هذه الأرقام بعد ضربها في 100 ولكن بالصورة الصحيحة و ذلك بإستخدام تقنية ال casting

class randomNum { public static void main(String[] args) { int x,i; for(i=0;i<5;i++) { x =(int)(100*Math.random()); System.out.println(x); } } } 58 25 99 50 82 Press any key to continue...

الان بإستخدام أمر random و تقنية ال casting سنصمم لعبة بسيطة و سنطورها فيما بعد عندما ندرس ال GUI و ال APPLETS

فكرة هذه اللعبة تقوم على اختيار الكمبيوتر لرقم عشوائي بين 1 و 100 وبعد أن يتم ذلك سيعطى المستخدم 6 فرص من أجل تخمين ماهو هذا العدد العشوائي --- لقد رأيت هذه المسابقة على تلفزيون ابوظبي أو عجمان -- حيث كانت المذيعة تسأل المتصل فيقول 78 تقول له أقل فيقول 34 تقول له أكبر فيقول 50 حتى يصل الى الرقم المطلوب أو يفشل بعد انتهاء الفرص --- هنا سنصمم برنامجنا بحيث يخبرك هل اختيارك أكبر من الرقم أو أصغر منه

إذا قال لك أن اختيارك أصغر "low" فعليك إختيار رقم أكبر من الرقم الذي اخترته أما إذا قال لك أن إختيارك أعلى "high" فعليك اختيار رقم أصغر وهكذا حتى تنجح في المهمة قبل أو اثناء الفرصة الأخيرة أو تفشل بعد المحاولة الأخيرة

لو نجحت في إحدى المحاولات الستة سيتوقف البرنامج و يقول لك "Congratulations, You did it successfuly" -- أي "مبروك لقد أنجزت المهمة بنجاح"

إذا فشلت بعد المحاولة السادسة سيخبرك أنك فشلت و يقول "Sorry, you failed" -- أي -- "معليش لقد فشلت"

الحل: نحتاج الى متغير نخزن فيه القيمة التي سيختارها الكمبيوتر عشوائياً سنسمي هذا المتغير compNumber --- سيكون التعريف وتخزين القيمة من خلال أمر random على النحو التالي:

int compNumber; compNumber = (int)(100 * Math.random()) + 1;

لاحظ أننا ضربنا الرقم العشوائي في 100 ثم استخدمنا ال casting لكي نحوله من عدد عشري الى عدد صحيح ثم أضفنا عليه واحد لنضمن أن يكون الرقم بين 1 و 100 و ليس 0 و 99

الأن الكمبيوتر اختار رقماً عشوائياً لاندري ماهو ---- الخطوة التالية هي أن نمكن المستخدم من معرفة هذا الرقم من خلال ست محاولات --- اللعبة قائمة على هذا الأمر --- فكيف يتم ذلك؟

بادئ ذي بدء واضح أن المستخدم سيدخل الرقم الذي يختاره من خلال ال console window و في هذه الحالة يجب أن يتبادر الى الذهن كيفية قراءة القيم من خلال ال console window --- لقد فعلناها من قبل على النحو التالي:

static BufferedReader x = new BufferedReader( new InputStreamReader( System.in));

هذا السطر اسميناه مجازياً سطر التهئية للقراءة من خلال الشاشة السوداء ويجب أن يوضع خارج كتلة main وقبلها وبما أننا استخدمناه فنحن نحتاج الى استيراد مكتبة الجافا التالية التي يجب أن توضع قبل class:

import java.io.*;

الأن نريد أن نعرف شيئين و هما "الرقم الذي سيدخله المستخدم" و "رقم المحاولة" لذا سنعرف متغيراً صحيحاً اسمه userNumber ليمثل الرقم الذي سيستخدمه المستخدم و متغيراً صحيحاً اخر اسمه guessNumber ليمثل رقم المحاولة والتي قد تكون 1 أو 2 أو 3 أو 4 أو 5 وأخيراً 6 سيكون ذلك على النحو التالي:

int userNumber; int guessNumber;

الأن بما أن أقصى حد هو 6 محاولات فسنستخدم إحدى أدوات التكرار ---- اختيار for قد يبدو مناسباً --- إذن دعونا نختار for على النحو التالي:

for(guessNumber=0; guessNumber<6; guessNumber++) { . . . . }

بداخل كتلة for سنضع أمر قراءة الرقم الذي سيدخله المستخدم من خلال الشاشة السوداء ثم نقارن هل هو يساوي الرقم العشوائي السابق الذي اختاره الكمبيوتر أم لا --- سيكون أمر القراءة على النحو التالي:

userNumber=Integer.parseInt(x.readLine());

وطبعاً المقارنة بديهياً ستتم من خلال أمر الشرط if --- سنقارن بين compNumber و userNumber فإن تحققت المساواة ستتلقى التهنئية و يتوقف البرنامج عن إكمال بقية التكرار و ذلك بإستخدام أمر break أما إذا لم تتحقق المساواة سيقول لك حاول مرة أخرى "Try again" و في نفس الوقت سينبئك كنوع من المساعدة هل الرقم الذي اخترته أصغر من "low" أو أكبر من "high" رقم الكمبيوتر العشوائي.

for(guessNumber=0; guessNumber<6; guessNumber++) { userNumber=Integer.parseInt(x.readLine()); if (userNumber == compNumber) { System.out.println("Congratulations, You did it successfuly in " +guessNumber+" trials"); break; } if (userNumber < compNumber) System.out.println("low"); else if (userNumber > compNumber) System.out.println("high"); } if (guessNumber == 6) { System.out.print("Sorry, you failed"); System.out.println(" Computer number was: " + compNumber); }

فقط هذا هو كل شئ و سيصبح برنامجنا ككل على النحو التالي:

import java.io.*; class game { static BufferedReader x = new BufferedReader( new InputStreamReader( System.in)); public static void main(String[] args) throws IOException { System.out.println("Game of Luck"); System.out.println("Insert a number between 1 and 100"); int compNumber; int userNumber; int guessNumber; compNumber = (int)(100 * Math.random()) + 1; for(guessNumber=0; guessNumber<6; guessNumber++) { userNumber=Integer.parseInt(x.readLine()); if (userNumber == compNumber) { System.out.println("Congratulations, You did it successfuly in " +guessNumber+" trials"); break; } if (userNumber < compNumber) System.out.println("low "); else if (userNumber > compNumber) System.out.println("high "); } if (guessNumber == 6) { System.out.print("\n\nSorry, you failed"); System.out.println(" Computer number was: " + compNumber); } } } Game of Luck Insert a number between 1 and 100 89 high 22 low 55 high 44 low 50 high 48 low Sorry, you failed Computer number was: 49 Press any key to continue...

و نفذنا البرنامج مرة اخرى و استطعنا الحصول على الرقم وهو 89 بعد 4 محاولات

Game of Luck Insert a number between 1 and 100 66 low 77 low 88 low 90 high 89 Congratulations, You did it successfuly in 4 trials Press any key to continue...

سؤال منزلي: البرنامج السابق يتطلب ان تنفذ البرنامج في كل مرة تريد فيها اللعب --- طور البرنامج السابق قليلاً بحيث يتيح لك فرصة اللعب عدة مرات من غير ان تنفذ البرنامج في كل مرة كما في البرنامج السابق؟
سؤال منزلي 2: طور البرنامج في سؤال منزلي1 بحيث يخبرك قبل ان تغلق اللعبة كم مرة تمكنت من الفوز بعد عدة مرات من اعادة اللعبة؟

إلى اللقاء مع الدرس القادم

 



 

 

  محمد سفر العتيبي 23-7-2003 22:51 51.  

الدرس الواحد و الأربعون(41 )
مراجعة لبعض ماسبق دراسته

-------------------------1-------------------------

FileReader var1 = new FileReader("inputdata.txt"); BufferedReader var2 = new BufferedReader(var1); /////////////////////////////////// FileWriter var1 = new FileWriter("outputdata.txt"); PrintWriter var2 = new PrintWriter(var1); ///////////////// static BufferedReader var = new BufferedReader(new InputStreamReader(System.in)); static PrintWriter var = new PrintWriter(System.out,true );

جميع الجمل السابقة تتقاسم خاصية برمجية  مشتركة وهي أنها تبدأ بأمر التعريف الخاص ثم المتغير ثم علامة المساواة ثم أمر new ثم أمر التعريف مرة أخرى متبوعاً ب () وبينها قيمة المتغير أو المتغير نفسه وفي هذه الحالة لاتسمى امر تعريف بل constructor أي شئ مشيد أو مبني من شئ اخر و سيكون التوضيح حول هذه النقطة في الدرس 47 بإذن الله - وما سبق عموماً فهي تكتب للتوضيح على الشكل التالي:

declaration_type variable = new declararation_type (variable or value);

هذه القاعدة "إن جازت تسميتها بقاعدة" مررنا عليها سابقاً --- انظر للمثال التالي:

String[] StudentName = new String[40];

طبعاً الجملة الأخيرة هي تعريف المتغير StudentName ليكون مصفوفة من نوع String وتحتوي 40 عنصراً أو خلية.

لاحظ أنها على نفس نمط الأمثلة السابقة المختصة بالقراءة و الكتابة في مطلع هذا الدرس فقد بدأت بأمر التعريف وهو String ثم المتغير ثم علامة المساواة ثم أمر new ثم أمر التعريف مرة أخرى

وأنواع التعريف المختلفة عموماً هي مجرد أصناف موجودة في مكتبة الجافا المختصة فمثلاُ BufferefReader موجود في io و String موجودة في مكتبة الجافا القياسية --- و أطلقنا عليها وصف قياسية لأن البرنامج بديهة سيتعرف اليها و يفهمها من غير كتابة اسم المكتبة في أعلى البرنامج من خلال أمر import.

في المكتبة القياسية يوجد أيضاً أدوات التعريف الأساسية مثل int و double و البقية ---- أيضاً يوجد بها أوامر التحكم في سير البرنامج مثل for  و while  و do-while --- أيضاً يوجد بها الجمل الشرطية هذه الجمل التي تجعل البرنامج يتخذ قراراً ما بناءً على تحقق شرط ما - مثل if و switch و غيرها ---- أيضاً يوجد بالمكتبة الرئيسية أمر الطابعة println  وماشابهه. كل ذلك سيتم مناقشته في درس قادم ولكن فكرة هذا الجزء من الدرس هو كيفية انشاء أو خلق كائن جديد "new object" بإستخدام أمر new --- هذا الشئ لايستحدث من العدم بل يستنسخ من كائن "object" جاهز في أحد الأصناف "classes" في مكتبة الجافا. انظر للسطر التالي:

FileWriter var1 = new FileWriter("outputdata.txt");

var1 متغير اختاره المستخدم --- أنا في هذه الحالة ---  هذا المتغير يعتبر كائن جديد "new object" و أستنسخنا هذا الكائن من فئة أو صنف FileWriter ---- صنعنا هذا الكائن لكي نستفيد منه في بناء البرنامج و تركيبه ليؤدي وظيفة محددة. مصنعي الإطارات يصنعونها من أجل تزويد شركات صناعة السيارات بهذه الإطارات لكي تؤدي وظيفة ما و بالتالي تتحقق الفائدة من السيارة. لاشك أن وظيفة الإطار المحددة مفهومة لك. السيارة بدون كفرات أو إطارت لافائدة لها --- الإطارت لوحدها لاتفعل شيئاً --- ولكن تركيب و تصنيع السيارة من عدة اشياء مختلفة الوظائف أو متشابهة الوظائف ينتج لنا شيئاً مفيداً.

في مثالنا هذا نفس الشئ يحدث --- فنحن سننشئ شيئاُ أو كائناً جديداً وعملية الإنشاء ستتم بإستخدام أمر new --- هذا الشئ الجديد لوحده لايفعل شيئاً ولكن داخل برنامج متكامل فإنه يؤدي إحدى الوظائف المطلوبة لتنفيذ البرنامج -- ماهي هذه الوظيفة؟ في حالتنا هذه ننظر لنوع التعريف وهو هنا FileWriter ووظيفته الكتابة الى ملف خارجي -- أي كتابة ناتج البرنامج الى ملف خارجي. البرنامج ككل يعتبر class وله اسم كما مر علينا سابقاً وفي جميع الأمثلة.

إذن نستطيع القول أن class يتألف من عدة objects ---- و كل object داخل class له وظيفة محدة. و هذه الوظائف عندما تتحد معاً تؤدي الى شئ مفيد. هذه ببساطة هي نظرية ال OOP -Object Oriented -Programming --- ويترجمها البعض الى اللغة العربية باسم "البرامج كائنية المنحنى" --- أرجو أن لاتصاب بالرعب من الترجمة ولكن إن حدث المحذور فانظر للبرنامج كما تنظر الى أي شئ حولك. دعونا منذ هذه اللحظة نستبدل كلمة "شئ"  بكلمة "كائن" فنحن في علم الأحياء مثلاُ نقول الكائنات الحية ولانقول "الأشياء الحية" --- الإنسان كائن حي و الطير كائن حي و السيارة كائن ميت و الموتورسايكل كائن ميت. كلها كائنات -- لأنها تتكون أو تصنع أو تخلق أو تنشأ من أجزاء أو كائنات أخرى.

الكائنات يتم تصنيفها وتقسيمها الى أصناف أخرى. الطير كائن ولكن الصقر كائن أيضاً ولكن العلاقة بين هذين الكائنين هي أن الصقر كائن ينتمي الى صنف أو فئة الطيور.

من هذه اللحظة أيضاً دعونا نتفق أن  class تعني "فئة"

-------------------------2-------------------------

في أحد الدروس السابقة وعدنا بشرح وظيفة كلمة static إذا أتت مع أوامر القراءة و ماذا تعني --- انظر للسطرين التاليين:

static BufferedReader g = new BufferedReader( new InputStreamReader( System.in)); static PrintWriter a = new PrintWriter ( System.out, true);

جميع البرامج التي كتبناها فهي أحادية -- أي تتلف من جزء واحد اسمه main --- فحتى هذه اللحظة لم نكتب برنامجاً يتألف من عدة فروع برمجية صغيرة أخرى. static تكتب هنا و تعني مجازياً أن جميع البرامج الجزئية يمكنها الاستفادة من هذا الأمر عن طريق المتغير g أو a و هما متغيران من اختارك انت ايها القارئ ----- ولكن لو وجد جزء واحد فقط كما في البرنامج التالي:

import java.io.*; public class Password1 { static BufferedReader keyboard = new BufferedReader( new InputStreamReader( System.in)); static PrintWriter screen = new PrintWriter( System.out, true); public static void main (String[] args) throws IOException { String name, password; screen.print( "What is your name? "); screen.flush(); name = keyboard.readLine(); screen.print( "What is your password? "); screen.flush(); password = keyboard.readLine(); if (name.equals( "Khalid") && password.equals( "yx1234" )) screen.println( "Welcome " + name); else screen.println( "Sorry, you are not allowed" ); } }

هذا البرنامج يتألف من منهج main فقط. --- إذن لايوجد هنا سوى جزء واحد ---- إذن بإمكاننا كتابتها داخل هذا الجزء ولكن من غير static على النحو التالي: 

import java.io.*; public class Password2 { public static void main (String[] args) throws IOException { BufferedReader keyboard = new BufferedReader( new InputStreamReader( System.in));

PrintWriter screen = new PrintWriter( System.out, true);

String name, password; screen.print( "What is your name? "); screen.flush(); name = keyboard.readLine(); screen.print( "What is your password? "); screen.flush(); password = keyboard.readLine(); if (name.equals( "Khalid") && password.equals( "yx1234" )) screen.println( "Welcome " + name); else screen.println( "Sorry, you are not allowed" ); } }

لاشك أنك لاحظت الفرق بين البرنامج password1 و البرنامج password2

جرب كتابة البرنامج الأخير بإضافة static قبل سطر التهئية للقراءة BufferedReader --- هل ستحصل على الخطأ التالي اثناء compile

لاحظ وجود 3 أخطاء بسبب وجود  static قبل فئة BufferedReader داخل منهج main --- منهج main نقصد به جزء main --- في اخر درس في الجزء الأول --- الدرس 47 --- سيكون حول تركيب البرامج من عدة برامج جزئية أو فرعية --- هذه الأجزاء المكونة للبرنامج يطلق عليها عموماً Subroutines وتعني أجزاء فرعية وتستخدم كلمة Subroutnines تقريباً في كل اللغات ولكن في لغة الجافا فهناك لفظ بديل غطى على هذه الكلمة رغم انهما يعنيان نفس الشئ --- هذا اللفظ هو كلمة method و تعني طريقة عمل شئ ما أو منهجه العملي --- إذن أيضاً دعونا نتفق على ترجمة كلمة main الى "منهج" و نقصد بها جزء من البرنامج يعمل وفق الية و منهج ما.  -- فعندما يتكون البرنامج من ثلاثة أجزاء سنقول أنه يتكون من 3 methods أو subroutines وكل منهج يؤدي وظيفة معينة ------ سنستخدم الكلمة الأولى method لأننا ندرس لغة الجافا ---- هذا هو السبب الوحيد لذلك. هذا الدرس قريب لبعض المصطلحات والتي طلبت منكم سباقاً عدم التدقير عندها كثيراً -- قلنا تقريب و ليس معنى دقيق --- أرجو أن يكون حالياً المعنى وصل بنسبة 40% -- ومع نهاية الدروس الستة المتبقية من هذا الجزء ستجد نفسك متمكناً من أساسيات هذه اللغة و فهم كيفية عملها قبل ان ننتقل للجزء الثاني و قبل الاخير وهو حول Java Applets & GUI

الجزء الثالث لمن لديهم الفضول لمعرفة ماهي محتوياته سيكون موضوعه Advanced Java Programming Language و سيكون حول مواضيع متفرقة مثل Data structure programming  واستخدامات الجافا في ال Networking و غيرها من المواضيع الأخرى.

 



 

 

  محمد سفر العتيبي 30-7-2003 19:30 52.  

الدرس الرابع و الأربعون(44)
Tips-7
- More about Strings - 1


 الفرق بين readline و(Type.parseType(readline

س1:عندما نقرأ قيمة من نوع String من خلال ال console window فإننا نستخدم الأمر التالي:

x.readline()

بينما لو قرأنا قيمة من نوع int مثلاُ فإننا نضيف كلمة parse و التي تعني ميز نوع هذه القيمة مع الأمر السابق على النحو التالي:

Integer.parseInt(x.readline())

لماذا لانستخدم parse في قراءة المعلومات من نوع String بينما نستخدمها مع القيم من نوع int أو double مثلاُ؟

ج1: لأن القيم التي يتم إدخالها من خلال الشاشة السوداء "Console Window" هي بطبيعتها من نوع String لذلك لانحتاج أن نميز نوعها لأن البرنامج بداهة سيفهم أنها String ---- ولكن لو أدخلنا قيمة مثل 135 والتي تبدو للعين المجردة عدد صحيح من نوع int ولكن عين البرنامج المجردة لن تفهم هذا الشئ --- بل ستفهما أنها من نوع String فالكمبوتر ليس له عقل بشري لكي يميز بينabcd أو 1234 ---- لذلك نحتاج أن نستخدم أمر parseInt لكي يحول القيمة 135 مثلاُ من String الى int كما نرغب نحن.


تحويل strings الى قيم عددية : Converting Strings to Numbers

مر علينا أدوات تعريف مثل int و double و float و char و byte و long و short و boolean --- هذه الأدوات التعريفية تسمى primitive types --- هناك نوع اخر مشابه لها و مرت علينا سابقاً مثل Integer و Double و Float و Boolean و Character و Long وShort و Byte --- هذه التعاريف تسمى wrapper types

أربعة من ال wrapper types و هي Integer و Double و Floatو Long تستخدم لتحويل قيم من نوع String الى قيم عددية وذلك من خلال أمر valueOf و الذي يحول قيمة مثل "123" الى قيمة عددية هي 123 لاحظ الفرق بين القمتين الأولى من نوع String و الأخرى من نوع int ولكن تم تحويلها الى int من خلال Integer على النحو التالي:

String a = "123"; Integer b = Integer.valueOf(a)

فالمتغير a من نوع String و قيمته هي "123" --- تم تحويله الى قيمة من نوع int بإستخدام Integer.valueOf على النحو الموضح بعاليه وتم تخزين القيمة في متغير اسمه b.

الأنواع الثالثة الأخرى تعامل نفس نفس الشئ كمت في الأمثلة التالية على التوالي:

String a1 = "1.233"; Float b1 = Float.valueOf(a1) String a2 = "3.141595433452434"; Double b2 = Double.valueOf(a2) String a3 = "12354"; Long b3 = Long.valueOf(a3);


تحويل قيمة عددية الى String بإستخدام أمر toString ااااا Converting Numbers to Strings

على عكس الجزء السابق هنا ستم التحويل عكسياً من نوع عددي الى String

int x = 47; String x =Integer.toString(a);

لاحظ أن intستخدم في التعريف و ليس Integer ---- Integer و جميع ال wrapper types فقط تستخدم في التحويل. جرب الكود الاسبق بتضمينه في برنامج --- جرب الأنواع الأخرى Double و Float و Long


StringBuffer

عندما تستخدم "+" مع Strings فإنها ببساطة شديدة تجمع القيم من هذا النوع معاً و حسب الترتيب من اليسار الى اليمين --- ذكرنا أن هذا يسمى Concatenation أي إلحاق كلمة بكلمة اخرى لتكوين كلمة أو جملة جديدة. دعونا نسمي "+" مع String أداة الحاق فقط و ليس جمع.

انظر للمثال التالي:

String x = "postal Code"; String s ="His" + x + "is" + Integer.toString(47);

قيمة المتغير s في هذه الحالة هي:

s = "Hispostal Codeis47"

عادة لايستخدم المبرمجين هذه الطريقة بجع القيم من نوع String --- ففي مكتبة الجافا يوجد فئة "صنف" تسمى StringBuffer و بداخلها يوجد أمر اسمه append و يعني "ألحِق بِ" -- أي أضف هذه القيم على القيمة الموجودة - مثالنا السابق وهو:

String x = "postal Code"; String s ="His" + x + "is" + Integer.toString(47);

يمكن كتابته على النحو التالي:

StringBuffer x = new StringBuffer("postal Code"); s.append(x); s.append("is"); s.append(Integer.toString(47)); System.out.println(s); } }

ففي كل مرة نلحق قيمة جديدة بما هو موجود من قبل و طبعاً قيمة s النهائية هي نفسها التي حصلنا عليها سابقاً و هي:

s ="Hispostal Codeis47"


toTileCase, toUpperCase, toLowerCase, ignoreCase

ونختتم درس اليوم بزبدته الحقيقية. يوجد هناك ثلاثة أمور تتعامل مع تغيير شكل الحروف من أحرف صغيرة الى أحرف كبيرة بإستخدام أمر toUpperCase و تعني "حول حروف جميع الكلمة الى احرف كبيرة --- وهناك الأمر المعاكس له وهو toLowerCase و تعني حول حروف الكلمة لدينا الى الأحرف الصغيرة.

بالإضافة الى ذلك هناك أمر جميل وهو أمر ignoreCase ويعني تجاهل حالة الحرف و من فوائده الكثيرة انك مثلاُ لو ادخل رقمك السري بالأحرف الصغيرة وهو اصلاً كتب بالأحرف الكبيرة فإنك ستتمكن من دخول النظام --- نفس الكلام ينطبق على اسم المستخدم مثلاُ --- فهو لن يكترث لشكل الحرف بل سيعتبر a تشابه A رغم أن لغة الجافا أصلاً تميز بينهما و تعتبرهما حرفين مختلفين لأنها case-sensitive -- أي لغة حساسة.

مع الأمثلة التالية:

الكلمة الى"نوع عددي الى String

class Stringer { static void main(String[] args) { String a = "The History of Saudi Arabia"; String b,c; b=a.toUpperCase(); c=a.toLowerCase(); System.out.println(a); // "The History of Saudi Arabia"; سيطبع System.out.println(b); // "THE HISTORY OF SAUDI ARABIA"; سيطبع System.out.println(c); // "the history of saudi arabia"; سيطبع } }

يتم دمج هذا الأمر مع المتغير الذي يراد تحويل شكل حروفه من خلال النقطة كما هو موضح في المثال السابق. و لكن لو كان التحويل سيكون لقيمة مباشرة مثل "aBcDeF" و ليس متغيرأ فإننا سنضع هذه القيمة الصريحة داخل أقواس toUpperCase أو toLowerCase و مكان المتغير سنضع أمر التعريف String كما في الأمثلة التالية:

b=String.toUpperCase("aBcDeF");// "ABCDEF"; سيطبع c=String.toLowerCase("aBcDeF"); // "abcdef"; سيطبع

جربها من خلال البرنامج التالي:

class Stringer { static void main(String[] args) { String b,c; b=String.toUpperCase("aBcDeF"); c=String.toLowerCase("aBcDeF"); System.out.println(b); // "ABCDEF"; سيطبع System.out.println(c); // "abcdef"; سيطبع } }

مثال: : في الدرس-38 كان هناك مثال حول كتابة برنامج يطلب من المستخدم اسمه و رقمه السري هذا المثال نعيد كتابته هنا:

import java.io.*; public class Password { static BufferedReader keyboard = new BufferedReader( new InputStreamReader( System.in)); static PrintWriter screen = new PrintWriter( System.out, true); public static void main (String[] args) throws IOException { String name, password; screen.print( "What is your name? "); screen.flush(); name = keyboard.readLine(); screen.print( "What is your password? "); screen.flush(); password = keyboard.readLine(); if (name.equals( "Khalid") && password.equals( "yx1234" )) screen.println( "Welcome " + name); else screen.println( "Sorry, you are not allowed" ); } }

في هذا المثال الإسم يجب أن يكون Khalid و الرقم السري yx1234 -- لاحظ أن حرف K حرف كبير و ليس k فهناك فرق. ولكن إذا أردنا أن نتجاهل الفرق بين الحرف الكبير و الصغير فهناك أمر اسمه equalsIgnoreCase و تعني تجاهل حالة الحرف اثناء المساواة في المقارنة ووجوده سيجعل الجافا تعتبر KHALID و Khalid و khalid و kHaLiD نفس الشئ --- فبعد تعديل بسيط في البرنامج السابق سيسمح النظام للشخص الذي اسمه Khalid و رقمه السري yx1234 بالدخول--- هذه التعديل سيكون في داخل جملة if فقط حيث أن:

if (name.equals ( "Khalid") && password.equals ( "yx1234" ))

ستصبح

if (name.equalsIgnoreCase("Khalid") && password.equalsIgnoreCase("xy1234" ))

أعتقد أنها هكذا أفضل وكل الذي فعلناه أننا استبدلنا أمر المقارنة equals بأمر يكافئه وهو equalsIgnoreCase غير أنه يتجاهل وضع الأحرف --- أعتقد هكذا أفضل لمصممي السوفتوير

سؤال منزلي: استبدل جملة if في البرنامج السابق بالجملة الأخيرة و لاحظ الفرق.



ـ ــ أشلاءــ ـو مـ الكلمةـ ـاجاورها

 

  محمد سفر العتيبي 02-8-2003 21:25 53.  

 

الدرس الثاني و الأربعون(42)
Tips-7
- More about Strings - 2


String length

نواصل مع بعض المناهج  "methods" و التي تستخدم للتعاطي مع المتغيرات أو القيم من فئة String ا (java.lang.Object---->String)----- تخيل لدينا القيمة التالية من نوع String

"I have been living in Saudi Arabia since 1989"

لو عددنا عناصر هذه القيمة سنجد ان طول هذه القيمة هو 1 + 4 + 4 + 6 + 2 + 5 + 6 + 5 + 4 + 8  فراغات = 45 حرفاً

إذا اردنا أن نعرف طول ال String فأننا نستخدم ذلك الأمر الذي استخدمناه من قبل مع المصفوفات وهو length ---- سنضع القيمة السابقة في متغير اسمه x من نوع string ثم سنجد عدد الأحرف و الفراغات و الرموز المكونة لهذه القيمة هل هو 45 أم لا؟ ----- سيكون ذلك على النحو التالي:

String x = "I have been living in Saudi Arabia since 1989"; int d = x.length();

المتغير d تم تعريفه ليكون من نوع int وهذا أمر بديهي لأننا نريد تخزين قيمة صحيحة و هي عدد الأحرف في هذا المتغير --- طبقها من خلال المثال التالي:

class LengthOfStringExample { public static void main(String[] args) { String x = "I have been living in Saudi Arabia since 1989"; int d = x.length(); System.out.println(d); } }

45

Press any key to continue...

تنبيه: لاتنسى القوسين الفارغين خلف length

charAt

charAt هي اختصار character at و تجيب السؤال التالي: "ماهو الحرف الموجود في الخانة س" حيث أن س عدد صحيح يمثل الخانة التي نريد أن نعرف الحرف أو الرمز الموجود فيها ----- مرة أخرى تخيل القيمة السابقة و هي:

"I have been living in Saudi Arabia since 1989"

لو أردنا أن نعرف الحرف الموجود في الخانة العاشرة فكل ماعلينا هو أن نعد بالترتيب حتى نصل الى تلك الخانة ونعرف الحرف الموجود فيها ---- هنا هذا الحرف هو حرف e الثاني في كلمة been ---- في لغة الجافا تكتب على الشكل التالي: 

String x = "I have been living in Saudi Arabia since 1989"

char d = x.charAt(9);

نبدأ بالمتغير الذي توجد فيه القيمة وهو هنا x ثم نقطة "period" ثم الأمر charAt ثم قوسين غير فارغين بل يوجد بداخلها عدد صحيح وهو هنا 9 ليمثل الخانة العاشرة لأن العد في لغة الجافا يبدأ من الصفر و ليس الواحد

لاحظ أنها مشابهة لكيفية تنفيذ length بإستثناء الرقم الموجود بين القوسين ---- طبقها من خلال المثال التالي:

class CharAtExample { public static void main(String[] args) { String x = "I have been living in Saudi Arabia since 1989"; char d = x.charAt(9); System.out.println(d); } }

e

Press any key to continue...

غني عن القول أن المتغير d تم تعريفه ليكون من نوع char لأننا نتوقع القيمة الناشئة عن استخدام امر charAt لتكون حرف أو رمز واحد. أي تعريف اخر خاطئ و لاشك.

سؤال منزلي: من غير أن تنفذ البرنامج ماهو الجواب المتوقع لو كان الرقم بين القوسين يساوي 19؟ ماذا لو كان 18؟

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

substring

substring يمكن تقسيم هذه الكلمة الى قسمين string و sub ----- الأخيرة تعني "مجموعة جزئية من . . . " وبما أنها متبوعة ب string يصبح الغرض من substring هو إيجاد متسلسلة جزئية من متسلسلة أكبر --- ففي المثال السابق وهو:

"I have been living in Saudi Arabia since 1989"

لو أردنا أن نعرف المتسلسلة الموجودة بين الخانة الرابعة (3)  و الخانة العاشرة (9)  فهي:

"ave be"

العد يبدأ من الخانة الرابعة وينتهي قبل الخانة العاشرة -- إي عند الخانة التاسعة (8) --- اعتقد انه تبادر الى ذهنك اننا سنضع بين قوسي substring رقمين و ليس رقم واحد -- الرقم الأول لكي نخبر الجافا ببداية السلسلة المطلوبة و الاخر بنهايتها --- تفكير جيد لو حدث هذا منك عزيزي القارئ ---- عموماً سيكون ذلك بطريقة مشابهة لما سبق حيث نبدأ بالمتسلسلة الكلية ثم نقطة ثم الامر substring و بما أن الجواب المتوقع يعتبر متسلسلة حرفية فسيتم تعريف المتغير الذي سنخزن فيه هذه المتسلسلة الجزئية المقتبسة من المتسلسلة الام لتكون من نوع String و ذلك على النحو التالي:

String x = "I have been living in Saudi Arabia since 1989";

char d = x.substring(3,9);

طبقها من خلال المثال التالي:

class SubStringExample { public static void main(String[] args) { String x = "I have been living in Saudi Arabia since 1989"; String d = x.substring(3,9); System.out.println(d); } }

ave be

Press any key to continue...

لو وضعنا رقماً واحداً فقط -- فإن البرنامج تلقائياً سيعرف أن الرقم الثاني هو أخر عنصر في المتسلسلة ---- في المثال السابق لو تجاهلنا الرقم 9 سيكون ناتج البرنامج على الشكل التالي:

ave been living in Saudi Arabia since 1989

Press any key to continue...

سؤال منزلي: ماذا تتوقع ناتج البرنامج السابق اذا كانت قيمة البدء هي 10 و قيمة النهاية 20؟ ماذا لو كانت قيمة البدء هي نفسها قيمة النهائية؟ 

تنبيه: لاتنسى أن الأمر هنا هو substring و ليس subString وهو خطأ شائع كما وجدت من خلال تصفحي لمواضيع متفرقة على الشبكة.

غداً مع الجزء الثالث مع بعض مناهج فئة  String أيضاً



ـ ــ أشلاءــ ـو مـ الكلمةـ ـاجاورها

 

  محمد سفر العتيبي 03-8-2003 11:04 54.  

الدرس الثاني و الأربعون(03-42)
Tips-7
- More about Strings - 3


startsWith

startsWith هو أيضاً أحد المناهج في فئة String ووظيفته الخاصة هي الفحص هل المتسلسلة لدينا تبدأ بهذه الأحرف أم لا. فهذا المنهج يفحص هل كلمة Mohammed تبدأ ب M أو Moh أو .... أم لا؟ إذن نتوقع الجواب جواباً منطقياً "boolean" فإن كان جواب السؤال نعم فالجواب true و إن كان لا فالجواب false ---- إذن يجب أن يتم تعريف المتغير الذي ستتم فيه تخزين قيمة الفحص ليكون من نوع boolean

وكما فعلنا سابقاً سيتم الربط بين المنهج وفئته من خلال النقطة "period" على النحو التالي:

boolean d = String.startsWith(String s)

فلو كانت المتسلسلة التي لدينا هي:

 String x = "I have been living in Saudi Arabia since 1989"

حيث أن x هي المتسلسلة الكبرى و نريد أن نبحث هل هي تبدأ بقيمة المتغير s و التي دعنا نتعمد أن نختارها لتكون "I have" أم لا؟

 

طبقها من خلال المثال التالي:

class startsWithExample { public static void main(String[] args) { String x = "I have been living in Saudi Arabia since 1989"; String s = "I have"; booleand = x.startsWith(s); System.out.println(d); } } true Press any key to continue...

سؤال منزلي: لماذا تم تعريف المتغير d ليكون من نوع  boolean?  الخطأ الذي سينتج لو تم تعريفه من نوع int مثلاُ سيكون incompatible types --- فماذا تعني؟


 

endsWith

end هي عكس كلمة start و تعني نهاية --- وتعامل بالمثل كما تم التعامل مع startsWith غير أنها تبحث عن نهاية الكلمة و ليس بدايتها و تجيب على هذا السؤال: هل المتسلسلة لدينا تنهي بهذه الأحرف أم لا؟

السؤال يبدأ بهل -- إذن الجواب يجب أن يكون منطقياً -- أي true أو false

طبق المثال السابق مع تغيير مايلزم --- سيكون ذلك على النحو التالي:

class endsWithExample { public static void main(String[] args) { String x = "I have been living in Saudi Arabia since 1989"; String s = "I have"; boolean d = x.endsWith(s); System.out.println(d); s = "989"; d = x.endsWith(s); System.out.println(d); } } false true Press any key to continue...


indexOf

هذا المنهج وظيفته البحث عن مكان بدء حرف أو كلمة معينة في المتسلسلة الحرفية لدينا -- و من ثم يعطينا مكان بدايتها في هذه المتسلسلة إن وجدت و إن لم توجد فسيعطينا -1 و تعني أنها غير موجودة. --- تخيل أنك تريد أن تبحث عن كلمة معينة في نص معين --- هذا الأمر يساعدك في أيجاد مكانها في النص: في مثالنا السابق كلمة Arabia تبدأ من الخانة 28 بينما كلمة has مثلاُ غير موجودة داخل تلك المتسلسلة --- بناءً عليه نتوقع أن يكون ناتج البحث للأولى 28 و ناتج البحث للثانية -1 كما يتضح ذلك بعد التطبيق من خلال المثال التالي:

class startsWithExample { public static void main(String[] args) { String x = "I have been living in Saudi Arabia since 1989"; String s = "Arabia"; int d = x.indexOf(s); System.out.println(d); s = "has"; d = x.indexOf(s); System.out.println(d); } } 30 -1 Press any key to continue...

سؤال منزلي: لماذا تم تعريف المتغير d ليكون من نوع  boolean?  الخطأ الذي سينتج لو تم تعريفه من نوع int مثلاُ سيكون incompatible types --- فماذا تعني؟


replace

هذا المنهج و يعني "استبدل" تنحصر وظيفته في استبدال أحد حروف المتسلسلة بحرف أخر --- و بالتالي ينتج لدينا متسلسلة جديدة ---- و لكن إن لم يكن الحرف الذي نود استبداله موجوداً في المتسلسلة الأصلية فلن يحدث أي تغيير --- في مثالنا السابق وهو:

 "I have been living in Saudi Arabia since 1989"

يوجد لدينا 4 أحرف e ونود استدبالها بحرف Z مثلاُ: ستكون المتسلسلة الجديدة هي:

"I havZ bZZn living in Saudi Arabia sincZ 1989"

بين أقواس replace سنضع قيمتين من نوع char ويفصل بينهما فاصلة --- الخانة الأولى تمثل الحرف المراد استبداله و الخانة الثانية تمثل الحرف الذي سيوضع مكان الحرف المستبدل: انظر للمثال التالي:

class replaceExample { public static void main(String[] args) { String x = "I have been living in Saudi Arabia since 1989"; String d = x.replace('e','Z'); System.out.println(d); } } I havZ bZZn living in Saudi Arabia sincZ 1989 Press any key to continue...

سؤال منزلي: لماذا تم تعريف المتغير d ليكون من نوع  String? ماذا لو تم استبدال علامتي التنصيص ' ' والتي تمثل char بعلامتي " " و التي تمثل String داخل أقواس منهج  replace في المثال السابق؟

و بعيداً عن صخب السياسة فالمثال السابق يصلح شفرة يمكن فكها فيما بعد ؟ ؟ ؟ ؟ ؟ مع السلامة لكي لا "نكع" زيادة --- سي يو نكست تايم مع الجزء الرابع و قبل الأخير من هذا الدرس.


 



 
  محمد سفر العتيبي 04-8-2003 17:11 55.  

الدرس الثاني و الأربعون(04-42)
Tips-7
- More about Strings - 4


lastIndexOf

هذا المنهج و يعني "مكان أخر وجود ل--------- في المتسلسلة". ضع مكان الفراغ إما السلسلة الجزئية أو الحرف. إذن بين أقواس هذا المنهج سنضع قيماً من نوع char أو قيماً من نوع String ووظيفته فحص السلسلة لدينا و من ثم إرجاع مكان وجود الحرف أو المقطع المطلوب في هذه السلسلة ---- و نقصد بكلمة السلسلة أو المتسلسلة "كلمة أو جملة مكونة من سلسلة من الأحرف أو الأعداد أو الرموز الخاصة ". انظر للمثال التالي:

String x = "Access is a relational database application that is exteremely powerful yet very staightforward to use."

هذه المتسلسلة تتكون من 103 خانة (بما في ذلك الفراغات طبعاً) وكلمة very تبدأ من الخانة 77 (76 بالنسبة للكمبيوتر)

إن لم توجد الكلمة أو الحرف المطلوب لدينا في المتسلسلة فسيعطينا البرنامج -1 و تعني أنها غير موجودة. --- طبق المثال التالي:

class lastIndexOfExample { public static void main(String[] args) { String x="Access is a relational database application that is exteremely powerful yet very staightforward to use."; String s; int d = x.length(); // الدرس قبل الماضي System.out.println(d); s = "very"; d = x.lastIndexOf(s); System.out.println(d); s = "has"; d = x.lastIndexOf(s); System.out.println(d); char c = 'h'; d = x.lastIndexOf(c); System.out.println(d); d = x.lastIndexOf('a'); System.out.println(d); } } 103 // طول المتسلسلة 76 // very كلمة -1 // جواب متوقع فكلمة has لاتوجد في المتسلسلة 86 // أخر وجود لحرف h في المتسلسلة 92 // أخر وجود لحرف a في المتسلسلة Press any key to continue...


concat

هذا المنهج هو اختصار لكلمة cocatenation وتعني "الحق بِ أو أضف" ووظيفته تنحصر في إضافة متسلسلة الى نهاية متسلسلة أخرى: فمثلاُ لو كان لدينا المتسلسلة " Nemr" تحت المتغير x و لدينا متسلسلة أخرى "ibn Adwan" تحت المتغير y فأن المنهج concat سيعطينا متسلسلة جديدة افترض ان اسمها z قيمتها هي "Nemr ibn Adwan" ستكون عملية الإلحاق على النحو التالي:

z = x.concat(y)

طبق المثال التالي:

class concatExample { public static void main(String[] args) { String x = "Nemr "; String y = "ibn Adwan"; String z; z = x.concat(y); System.out.println(z); } } Nemr ibn Adwan Press any key to continue...

سؤال منزلي1: لماذا وضعنا فراغاً خلف كلمة Nemr في البرنامج السابق؟


toCharArray

كما يوحي اسم هذا المنهج وهو : to+char+array ويعني "حول هذه المتسلسلة من نوع String الى مصفوفة من نوع char" و كما تعلم فإن المتغيرات من نوع char لاتقبل سوى حرف واحد. فمثلاُ كلمة "Mohammed" تعتبر بداهة قيمة من نوع String ولكنها يستحيل أن تكون من نوع char لأنها ببساطة تحتوي على أكثر من حرف واحد و تحديداً تحتوي على 8 أحرف --- ولكن من خلال المصفوفات فإنه يمكن تخزين كلمة "Mohammed" في متغير من نوع char متبوعاً ب [ ] للدلالة على ان هذا النوع يمثل مصفوفة متغيرة. هذا المنهج يحول هذه القيمة من نوع String الى مصفوفة من نوع char عدد عناصرها يساوي عدد أحرف هذه القيمة.

البرنامج التالي يوضح ماسبق حيث سيتم تحويل المتسلسلة الى سلسلة من الاحرف وسيطبع البرنامج و سندع البرنامج يطبع القيمة الخامسة ثم القيمة الولى ثم القيمة الثاالثة ثم القيمة الأخيرة من عناصر المصفوفة الناشئة:

class toArrayCharExample { public static void main(String[] args) { String x = "Mohammed"; char[] c = new char[40];// تعريف مصفوفة c = x.toCharArray(); System.out.println(c[4]);// العنصر الخامس System.out.println(c[0]);// العنصر الأول System.out.println(c[2]);// العنصر الثالث System.out.println(c[x.length()-1]);// العنصر الأخير } } m M h d Press any key to continue...

سؤال منزلي2: في السطر الأخير في البرنامج السابق لماذا كتبنا

System.out.println(c[x.length()-1]);

ولم نكتب

System.out.println(c[x.length()]);?


compareTo

مر معنا سابقاً هذا المنهج ---- ووظيفته هي المقارنة بين متغيرين أو قيمتين أو بين متغير و قيمة أو العكس ولكن جميعهم من نوع String --- ورغم أن العملية هنا عملية مقارنة فجرت العادة أن تكون النتيجة هي إما true أو false ---- أي قيمة منطقية من نوع boolean ----- هذا ماجرت عليه العادة --- و لكن هنا حالة خاصة فالجواب الذي سنحصل عليه سيكون عدداً صحيحاً من نوع int و ليس قيمة منطقية --- وهناك ثلاثة احتمالات لمعرفة هذا العدد و هي:

ان كانت قيمة المتغير الأول تساوي قيمة المتغير الثاني فالجواب سيكون صفر و يعني أنهما متساويان.

ان كانت قيمة المتغير الأول أكبر من قيمة المتغير الثاني فالجواب سيكون عدداً صحيحاً موجباً مثل 1 أو 2 أو 15 و هكذا وفق ميكانيكية ما --- ليست في مجال درسنا ولكن لهاعلاقة بال ASCII.

ان كانت قيمة المتغير الأول أصغر من قيمة المتغير الثاني فالجواب سيكون عدداً صحيحاً سالباً مثل -1 أو -3 أو -4 أو -11 و هكذا و لنفس التعليل السابق ولكن الشئ المؤكد انهد عدد سالب.

ماذا نقصد بكلمة أكبر من و أصغر من و يساوي و نحن لانتحدث عن أرقام بل عن مقارنة بين كلمات مثل "Ahmed" و "Mohammed"

جواب مختصر: في المقارنة بين الكلمات ننظر لوضعها في القاموس و أيهما يسبق وجوده فهو الأصغر فمثلاً كلمة Mohammed أكبر من كلمة Ahmed و كلمة good أكبر من كلمة goad

أيهما أكبر: JAVA أم java؟ لمعرفة الجواب ارجع الى ال ASCII code

و لكن بإمكانك معرفة الجواب من خلال لغة الجافا بإستخدام الأمر السابق وذلك على النحو التالي:

d = x.compareTo(y)

حيث أن x متغير من نوع String و هو هنا المقارن به و المتغير y أيضاً من نوع String وهو المقارن بينما المتغير d يجب أن يكون من نوع int لأن نتيجة المقارنة عدد صحيح من أحد الاحتمالات الثلاثة السابقة--- طبق من خلال المثال التالي:

class compareToExample { public static void main(String[] args) { String x = "Mohammed"; String y = "Mohammed"; int d = x.compareTo(y); System.out.println(d); x = "Mohammed"; y = "Ahmed"; d = x.compareTo(y); System.out.println(d); x = "Ahmed"; y = "Mohammed"; d = x.compareTo(y); System.out.println(d); x = "JAVA"; y = "java"; d = x.compareTo(y); System.out.println(d); } } 0 ===> Mohammed = Mohammed 12 ===> Mohammed > Ahmed -12 ===> Ahmed < Mohammed -32 ===> JAVA < java Press any key to continue...

سؤال منزلي3: كيف يمكن أن نحصل على جواب منطقي بإستخدام منهج compareTo في البرنامج السابق؟

جواب3: بما أن ناتج هذا المنهج عبارة عن عدد صحيح فإننا نقارته من خلال أدوات المقارنة الأساسية الستة التي درسناها في مطلع هذه السلسلة مثل > و == و البقية مع عدد صحيح أخر وهو الصفر كما فعلنا سابقاً في سؤال المشروع البسيط جداً. الكلمة الأخيرة استفزازية لشخص محدد.



 
  محمد سفر العتيبي 08-8-2003 16:33 56.  

الدرس الثاني و الأربعون(04-42)
Tips-7
 1- More about Strings - 4


في الأجزاء الثلاثة السابقة ناقشنا بعض المناهج الموجوة في الفئة String --- لاحظ كلمتي منهج و فئة -- أي method و class -- لقد دخلت هاتين الكلمتين على الخط في الدروس الأخيرة و الهدف من ذلك هو التهئية لأهم الدروس وهو الدرس 47 عندما سيكون لدينا القدرة حينها كتابة برنامج يتألف من العديد من الأجزاء و إن لم تنسوا فقد قلنا سابقاً أننا سنستبدل كلمة "جزء" بكلمة "منهج" -- ولكن الان يكفي أنك عرفت أن هناك فئة وهذه الفئة يوجد بها العديد من المناهج. مثلاً فئة String يوجد بها المناهج السابقة مثل charAt و length و toString و و و و

فئة String توجد في مكتبة الجافا. ولكن في أي قسم تقع فئة String في مكتبة الجافا؟ للإجابة على هذا السؤال نحتاج أن نعرف ماهي مكتبة الجافا و أقسامها, فمكتبة الجافا تتألف من العديد من الأقسام --سيكون الدرس بعد القادم - حول مكتبة الجافا -- سيكون الدرس طويلاً نوعاً ما و لذلك مايبرره للأهمية ولكن هذه الأقسام حالياً هي:

java.lang package java.util package java.io package java.net package java.awt package java.applet package

فئة String توجد في java.lang package --- في درس اليوم سنناقش ولكن من غير تفصيل فئتين اخريين شبيهتين بفئة String.

لاحظ أننا قلنا أنها فئتين و ليس منهجين و هذا يعني أنهما شئ و فئة String شئ أخر. ولكن تشابكهما في بعض الجوانب هو المسوغ لطرحها هنا.

الفئة الأولى هي: StringBuffer Class --- أيضاً توجد فيjava.lang package

الفئة الأخرى هي: StringTokenizer Class --- توجد في java.util package  كما ذكرنا ذلك سابقاً في الدروس 36-39

مرت علينا سابقاً هاتين الفئتين و سنبدأ الدرس بالأخيرة لقلة مناهجها المتفرعة منها


Methods in StringTokenizer Class

بما أنه يوجد في java.util فرأس برنامجنا يجب أن يبدأ بالسطر التالي:

import java.util.*;

النجمة * تعني "استفد من كل الفئات" أو "all classes" الموجودة داخل حزمة java.util ---- يوجد هناك أكثر من عشر فئات ولكن نحن لانريدها كلها فقط نريد فئة StringTokenizer ---- لذلك بدلاً من النجمة ضع اسم الفئة على النحو التالي:

import java.util.StringTokenizer;

كتابة السطر السابق تعني أن برنامجك فتح باب بيت فئة StringTokenizer فقط وترك باقي البيوت في java.util --- داخل ذلك البيت يوجد العديد من المناهج "methods" --- وهي:

countTokens() hasMoreElements() hasMoreTokens() nextElement() nextToken()

المناهج باللون الأحمر مرت علينا سابقاً وسنناقش جميع هذه المناهج هنا ولكن باختصار --- تخيل أن لدينا المتسلسلة x من نوع String التالية:

String x = "A tokenizer can be used to break a text into pieces called tokens";

يوجد في هذه المتغيرة 13 كلمات أو دعنا نقول معلومات وتسمى كل معلومة Token --- إذن يوجد لدينا 13 tokens ---- الفرق بين كل token و token هو الفراغ بين كل كلمة و كلمة.

بإستخدام منهج countTokens بإمكاننا معرفة عدد الكلمات في المتغير السابق. ولكن المشكلة تكمن في أن المتغير السابق من نوع String بينما countTokens توجد في StringTokenzier --- فماهو البروتوكول الذي يجب أن نتبعه لكي يتم التفاهم و الألفة بين النوعين؟  الجواب يجب أن تحول ذلك المتغير من نوع String الى متغير اخر من نوع StringTokenizer على النحو الشهير التالي:

StringTokenizer y = new StringTokenizer(x);

الأن لدينا متغير اسمه y من نوع StringTokenizer ومخزن في هذا المتغير قيمة x السابقة. لقد تم إنشاء y و تخزين القيمة فيها من خلال أمر new و المشيد ( )StringTokenizer والفئة StringTokenizer

لاتكترث لكلمة المشيد "constructor" حالياً.

مثل مافعلنا سابقاً مع مناهج String حيث كنا نربط المنهج بالفئة من خلال إستخدام النقطة "." --- هنا نفس الشئ:

num = y.countTokens();

المتغير num يجب تعريفه كعدد صحيح من نوع int و إذا عرف السبب بطل العجب فمنهج countTokens وظيفته إعطائك رقم "كمي" لعدد القيم في متسلسلة ما.

الأن نريد أن نمر على كل token في المتغير y --- لذا يجب أن نتأكد هل وصلنا الى النهاية أم لا --- ذلك سيتم من خلال منهج اسمه hasMoreTokens والقيمة الناتجة من هذا المنهج قيمة منطقية أما true أو false -- فإن كان لازال هناك tokens فالجواب المنطقي هو true ولكن إذا وصل الى النهاية فسوف يقول لك توقف من خلال الجواب المنطقي false. بإختصار هذا المنهج للتشييك.

إذا أردنا أن نعرف ماهي القيمة الحالية الني وصلنا عندها فإننا نستخدم منهج ثالث اسمه nextToken و ترجمته المجازية أنه يقول "أن القيمة التالية هي ..... ".

البرنامج التالي يقرأ المتسلسلة السابقة ثم يعد عدد عناصرها ثم يطبع كل عنصر على حده ولكن قبل طباعة كل عنصر يتأكد أولاً هل هو وصل الى خط النهاية أم لا.

import java.util.*; public class StringTokenizerExample { public static void main(String[] args) { String s = "A tokenizer can be used to break a text into pieces called tokens."; StringTokenizer st = new StringTokenizer(s1); System.out.println("The number of tokens is: " +st.countTokens());// عدد التوكنز System.out.println("The individual tokens are:\n"); while (st.hasMoreTokens())// للتشييك System.out.println(st1.nextToken());// للطباعة } } The number of tokens is: 13 The individual tokens are: A tokenizer can be used to break a text into pieces called tokens. Press any key to continue...

سؤال منزلي: استدبل المنهج nextToken بالمنهج nextElement و المنهج hasMoreTokens بالمنهج hasMoreElements في البرنامج السابق ثم أعد ترجمته و تنفيذه. هل يعطيك نفس الجوب؟.

<جواب: نعم.


Methods in StringBuffer Class

under preparation


هذا سيكون في الجزء الثاني من هذا الجزء (الرابع) من الدرس 42 --- الرد القادم.



 

 

  محمد سفر العتيبي 10-8-2003 17:23 57.  

الدرس الثاني و الأربعون(04-42)
Tips-7
2- More about Strings - 4


Some of StringBuffer's Class Methods

اليوم نكمل الدرس السابق وموضوعنا حول فئة StringBuffer أو "StringBuffer Class" --- في درسٍ ماضٍ مر علينا أحد المناهج الموجودة في هذه الفئة و هي منهج ()append وعرفنا وظيفته التي يؤديها إذا كان موجوداً في برنامجنا. --- احفظ هذه الجملة "الفئة تتألف من العديد من المناهج". أيضاً احفظ هذه الجملة الناقصة "------ تتألف من العديد من الفئات." ياترى ماهي الكلمة التي يجب أن توضع في الفراغ؟

و لكي لا أتبع ألأسلوب الثري للشيخ على الطنطاوي رحمه الله تعالى رحمة واسعة أقول نعود الى لب موضوعنا وهو التعرف على المزيد من المناهج "methods" الموجودة في فئة StringBuffer ذات العلاقة بالتعامل مع القيم من نوع String

هذه الفئة توجد في أحد أقسام مكتبة الجافا وهي java.lang package ولأن هذا القسم في مكتبة الجافا يفهمه البرنامج بداهة من غير استخدام أمر import فإننا لانحتاج الى كتابة السطر التالي في أعلى البرنامج:

import java.lang.*;

بالطبع يمكنك كتابتها و سواء كتبتها أم لم تكتبها سيفترض البرنامج وجودها. تلاحظون أن أغلب البرامج التي كتبناها لم نستخدم أمر import --- فماذا يعني ذلك؟

ذلك يعني أن جزئيات ذلك البرامج توجد تحت سقف java.lang فمثلاُ أدوات التعريف مثل int و double و غيرها مثل System.out.println توجد في هذا القسم.

فئة StringBuffer تتألف من العديد من المناهج و أشهر هذه المناهج هي: ()append و ()setLength و ()insert و ()setCharAt و ()capacity و ()charAt و ()reverse و ()length

البرنامج التالي يشتمل على جميع هذه المناهجمحصلة البرنامج أسفله في الصندوق الأسود):

import java.io.* ; public class StringBufferExample { static PrintWriter P = new PrintWriter(System.out,true); public static void main(String[] args) { int a; StringBuffer s=new StringBuffer("ibmmmmmmmm");// s أنشئ متغير اسمه P.println(s); // إطبع a=s.capacity();// احسب سعة المتغير P.println(a); // اطبع الجواب a=s.length();// طول المتغير == عدد أحرف المتسلسلة P.println(a); // اطبع الطول s.insert(2,"ara");// أدخل هذه الأحرف في المتسلسة بدأ من الخانة 2 P.println(s);// اطبع المتسلسلة الجديدة s.setLength(20);// اجعل طول المتسلسة 20 P.println(s+"XXX");// اطبعها مرة اخرى سيكون طولها عشرين ولكن الخانات العليا ستكون فارغة s.setLength(5);// اجعل الطول 5 --سيإخذ اول خمسة احرف و يتجاهل البقية P.println(s+"XXX");// اطبع s.append(" iduas");//الحق iduas لمتسلسلة P.println(s);// اطبع الجواب s.reverse();// اعكس المصفوفة الناشئة P.println(s);// اطبع الجواب s.setLength(12);// اجعل الطول 12 P.println(s.length());// اطبع الجواب s.setCharAt(11,'a');// اجعل الحرف في الخانة 11 الى a P.println(s);// اطبع الجواب s.setCharAt(0,'S');// S اجعل الحرف في الخانة 0 s.setCharAt(6,'A');//A اجعل الحرف في الخانة 6 P.println(s);// اطبع الجواب s.insert(0,"Kingdom of ");// إبدأ من الخانة صفر Kingdom of أدخل الى المتسلسلة كلمتي P.println(s);// اطبع الجواب a=s.capacity();// كم سعة المتغير مرة اخرى P.println(a);// اطبع الجواب a=s.length();// ماهو الطول الجديد للمتسلسلة P.println(a);// اطبع هذا الطول char x=s.charAt(3);// ماهو الحرف في الخانة 3 P.println(x);// اطبع هذا الحرف } } ibmmmmmmmm 26 10 ibarammmmmmmm ibarammmmmmmm XXX ibaraXXX ibara iduas saudi arabi saudi arabia Saudi Arabia Kingdom of Saudi Arabia 26 23 g Press any key to continue...

سنناقش كيف تولد لدينا الناتج السابق وفقاً لمناهج StringBuffer المختلفة التي تم استخدامها هنا و تم تلوينها باللون الأحمر داخل البرنامج -- فقد تم إنشاء المتغير s من فئة StringBuffer (في درس قادم سنقول الكائن s المستنسخ من فئة StringBuffer أو شئ من هذا القبيل) وتم تخزين القيمة "ibmmmmmmmm" في هذا المتغير -- إذن قيمة s هي الان:

s="ibmmmmmmmm"

عدد أحرف هذه الفيمة 10 إذن طولها 10 ونحصل على طولها باستخدام المنهج ()length وهو منهج موجود في فئة StringBuffer كما هو موجود أيضاً في فئة String --- حالياً اعتبر هذا تشابه اسماء --- سيكون ذلك على النحو التالي:

a = s.length();

لأن ناتج هذا المنهج عدد صحيح لذا تم تخزينه في متغيرة صحيحة انظر للبرنامج ف المتغير a تم تعريفه ليكون من نوع int.

قبل ذلك السطر لدينا منهج ()capacity في البرنامج السابق ووظيفة هذا المنهج هو إعطائنا السعة المحجوزة في الذاكرة لخزن قيمة s سيكون ذلك على النحو التالي:

a = s.capacity();

لاحظ العلاقة بين الفئة و المنهج فدائماً و أبداً تربط بينهم النقطة: الفئة أولاً ثم النقطة ثم المنهج وكل منهج كما تلاحظ يرافقه قوسين() --- طبعاً s هنا تمثل الفئة وهي StringBuffer كما عرف سابقاً --- لاحظ أن قيمة s لازالت نفسها ولم يغيرها المنهجان السابقان ولكن بعد ذلك أتى السطر التالي في برنامجنا:

s.insert(2,"ara");

هل لاحظت القيم بين قوسي منهج ()insert أحد مناهج فئة StringBuffer ---- في الخانة الأولى العدد الصحيح 2 وهو بديهياُ من نوع int و في الخانة الثانية قيمة من نوع String و هي "ara" --- فماذا يعني هذا المنهج و ماذا تعني هاتين القيمتين وتأثيرهما على المتغير s و قيمته الأصلية؟

insert تعني "أدخِل" --- بكسر الخاء --- و بتفصيل أكثر هذا المنهج يقول لك أدخل القيمة "ara" في المتغير s وبكن عليك ان تبدأ من الخانة 2 --- في هذه الحالة ستصبح قيمة s الجديدة بعد التعديل على النحو التالي:

s="ibarammmmmmmm"

هل رأيت أين دخلت القيمة "ara" ومنأين بدأت ---- انسى الأن قيمة s القديمة فقد تم تغييرها و أصبحت القيمة السابقة وطولها الفعلي 13 --- ولكن لاتنسَ أن لغة الجافا تعتبر zero-based أي أن العد يبدأ من الصفر.

قلنا أن طولها أصبح 13 -- بإمكانك عد الأحرف -- فماذا لو أردنا أن نوسع طولها و نجعله اكبر؟ -- يقوم بهذه المهمة منهج أخر اسمه (20)setLength و تعني مجازياً "إجعل الطول مساوياً للرقم الصحيح بين قوسي هذا المنهج" سيكون ذلك على النحو التالي:

s.setLength(20);

الأن أصبح طول s مساوياً ل 20 ولكن عدد أحرفها لازال 13 و هذا يعني أن الخانات الباقية ستبقى فارغة و هذا مايبرر استخدامي للقيمة "XXX" في أمر الطباعة في البرنامج السابق بعد طباعة قيمة s فقط لترى الفراغات: ستصبح قيمة المتغير s الأن:

s="ibarammmmmmmm0000000"

الأصفار السبعة هنا وضعتها مكان الفراغات للتوضيح و الشرح لذا جرى التنويه --- إعتبر كل صفر ثمثل فراغ.

بعد ذلك في برنامجنا استخدمنا هذا المنهج مرة أخرى ولكن لنجعل الطول 5 بدلاً من 20:

s.setLength(5);

لن يحدث كوارث أو أي شئ من هذا القبيل بل سيصبح طول المتغيرة s مساوياً ل 5 -- أي انه سيأخذ أول خمسة أحرف من الخانة 0 و حتى الخانة 4 و سيفلتر الباقي ويتجاهله في عملية تسمى "truncation" أي التقريب --- هل تتذكرون عبارة قرب العدد العشري 2.123456 إلى أقرب خانتين مئويتين فيصبح الجواب 2.12 وذلك في كتاب الرياضيات للصف الخامس ابتدائي --- في هذه الحالة قيمة المتغير s الجديدة ستكون:

s="ibara"

بعد ذلك يأتي منهج جديد في برنامجنا السابق وهو منهج ()append -- في الحقيقة ليس جديداً علينا فقد مر علينا سابقاً و وظيفته إلحاق القيمة من نوع String بين قوسي هذا المنهج بذيل قيمة متغير الفئة لدينا و هي s التي صرحنا عنها "عرفناها" سابقاً لتكون من نوع StringBuffer ---- السطر التالي مقتبس من البرنامج:

s.append(" iduas");

سيضيف هذا المنهج القيمة "iduas " الى ذيل قيمة s السابقة و هي "ibara" و بناءً عليه ستكون قيمة s الجديدة:

s="ibara iduas"

لاحظ الطول الجديد للمتغير وهو 11 --- 10 أحرف و فراغ واحد. بعد ذلك يأتي منهج من أهم المناهج داخل هذه الفئة وهو منهج ()reverse و جليٌ من الترجمة الحرفية للكلمة أن وظيفة هذا المنهج عكس القيمة لدينا وهذا ممايميز فئة StringBuffer عن فئة String --- لقد كُتِبَ على النحو التالي:

s.reverse();

أقواس المنهج فارغة وترجمة هذا السطر هي: "اعكس قيمة المتغيرة s" ---- لا أشك لحظة أنك عرفت قيمة s الجديدة التي أصبحت على النحو التالي:

s="saudi arabi"

لاحظ أن الطول لم يتغير فلازال 11 --- افترض أننا نريده 12 --- فهل لازلت تتذكر الأمر الذي شرحناه سابقاً من اجل تحديد طول المتسلسلة من نوع StringBuffer --- إنه (12)setLength:

s.setLength(12);

القيمة ستبقى كما هي ولكن الطول ازداد واحداً من 11 الى 12 --- قيمة s هي:

s="saudi arabi "

لاحظ الفراغ اليتيم خلف "arabi" --- الأن نريد أن نملاً هذا الفراغ اليتيم بالحرف 'a' و هو كما توحي علامتي التنصيص من نوع char سنستخدم منهجاً جديداً اسمه ()setCharAt و ترجمته المجازية فهماً هي "اجعل الحرف في الخانة 11 ليكون حرف a" --- فبين قوسي هذا المنهج يجب أن نضع قيمتين يفصل بينما فاصلة ---- القيمة الأولى عدد صحيح من نوع int لتحديد الخانة و القيمة الثانية من نوع char لنملاً بها تلك الخانة ---- السطر التالي مقتبس من البرنامج:

s.setCharAt(11,'a');

ملأنا الفراغ اليتيم بالحرف a و أصبحت القيمة المخزنة في المتغير s:

s="saudi arabia"

في البرنامج السابق استخدمنا هذا الأمر مرتين بعد ذلك المرة الأولى لنجعل الحرف في الخانة 0 وهو 's' ليكون 'S' و الحرف 'a' في الخانة 6 ليكون 'A' -- انظر للسطرين التاليين:

s.setCharAt(0,'S');// "Saudi arabia" s.setCharAt(6,'A'); //"Saudi Arabia"

في هذه الحالة أصبحت قيمة s الجديدة:

s="Saudi Arabia"

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

s.insert(0,"Kingdom of ");

حيث سيُدخِل القيمة " Khngdom of" في قيمة s السابقة بدأً من الخانة 0 من غير أن يحذف أي شئ من القيمة السابقة --- فكل مايحدث هو عملية إزاحة "translation" الى اليسار --- ستكون قيمة s بعد هذا السطر:

s="Kingdom of Saudi Arabia"

لاحظ ان هذا المنهج بديهياً يوسع طول المتسلسلة فقد أصبح طولها الكلي 23 ------ بعد ذلك أتى السطران التاليان في برنامجنا وقد سبق شرحهما:

a=s.capacity();// a= 26 a=s.length(); // a= 23

لماذا لم تتغير القيمة المعادة من منهج ()capacity في أول البرنامج عندما كانت قيمة s هي "ibmmmmmmmm" و في اخر البرنامج عندما أصبحت قيمتها "Kingdom of Saudi Arabia" حيث أن السعة في كلا الحالتين 26؟

و قد اختتمنا برامجنا بمنهج أخر في فئة StringBuffer وهو منهج (3)charAt و يعني "ماهو الحرف الموجود في الخانة 3؟" لاحظ أنه سأل عن الحرف --- إذن نتوقع الجواب ليكون حرفاً --- أي من نوع char و بالتالي يجب تخزين القيمة المعادة من هذا المنهج في متغير من نوع char ----- و ذلك السطر كان:

char x= s.charAt(3);

واضح من قيمة s أن قيمة x ستكون:

x = 'g'

تم الانتهاء من هذا الدرس وهو يعتبر تمهيداً بل مقدمة غير مباشرة لدرس قادم حول مكتبة الجافا ومحتوياتها وعنوان ذلك الدرس سيكون "Java language Library packages and references" سيكون ذلك في الدرس 46 ولكن الدرس القادم وهو 43 سيكون واحداً من اهم الدروس وهو تفصيل موسع حول Data & Variables Types في لغة البرمجة عموماً ولغة الجافا على وجه الخصوص. و قبل الوداع نعيد السؤال في مطلع هذا الدرس ياترى متهي الكلمة التي يجب أن توضع في الفراغ؟


 



 

 

  محمد سفر العتيبي 11-8-2003 17:33 58.  

الدرس الثالث و الأربعون (43)
Variable Types & Kinds -- 01
1-1 :Primitive Types

في لغة الجافا يوجد ثلاثة أنواع مختلفة من المتغيرات variable types و هي:

  1. primitive types
  2. class types
  3. array types

و أي متغير من الأنواع السابقة قد يصنف ليكون أحد نماذج للمتغيرات "Variable kinds " الثلاثة التالية:

  1. instance variables
  2. local variables
  3. class variables

فمثلاُ لو كان لدينا المتغير x الذي تم تعريفه ليكون من نوع int -- أي أنه جزء من ال primitive types فإن هذا المتغير قد يكون instance أو local أو class وذلك وفقاً للمكان الذي تم فيه تعريف هذا المتغير.في القاموس قد لايكون هناك فرق بين كلمتي type و kind ولكن هنا يجب أن تميز ماذا نقصد بكل مصطلح و يجب أن تعي ماذا يعني بعد نهاية أجزاء هذا الدرس.

هذه الأنواع أو الصيغ قد تم مناقشتها بشكل مباشر أو غير مباشر في الدروس السابقة ولكن الان قد كان حان الوقت المناسب للتحدث عنها بشكل أكثر عمقاً وشرحها تفصيلاً و يجب أن يكون لديك القدرة بعد نهاية أجزاء هذا الدرس أن تدرك نوع كل متغير وصيغته وأن يكون لديك القدرة على إجابة اسئلة مثل: لماذا استخدمت هذا المتغير هنا ك int و لماذا هذا المتغير local variable أو instance variable أو class variable

أيضاً يجب أن تكون لديك القدرة على إجابة اسئلة اخرى مثل الفرق بين الأنواع السابقة و هي primitive types و class types و array types

درسنا اليوم سيكون عن ال primitive types و نقصد بها أنواع التعريفية الأساسية الثمانية و هي:

byte -- short -- int --- long -- float --- double -- char -- boolean

والنوعان الأخران و هما class types و array types تجمع معاً تحت مسمى reference types --- إذن دعونا نختزل الأنواع الثلاثة السابقة إلى نو عين و هما:

  1. primitive types
  2. reference types

من هذا التصنيف قد يتبادر الى ذهنك أن كلمتي primitive و reference متعاكستان في المعنى وفق القاموس. لو فتحت القاموس الإنجليزي ستجد ان هذا الكلام ليس صحيحاً وكل كلمة تقع في شاطئ مختلف. نحن هنا نتحدث عن اللغة البرمجية و ليس عن اللغة الإنجليزية أو سواها.

من ناحية اللغة البرمجية هاتين الكلمتين متعاكستين في معناهما من ناحية ميكانيكية عمل كل نوع منهما و هذا الإختلاف لن نفهمه الا بعد أن نفهم ماذا يعني كل نوع أي ماذا تعني كلمة primitive و ماذا تعني كلمة reference. وهذا لن يحدث الا بعد انتهاء اجزاء هذا الدرس.

نعود الى درس اليوم و الى الأنواع الأساسية "primitive" الثمانية السابقة و قد مررنا كثيراً على هذه الأنواع "types" التعريفية ولكننا في هذا الجزء من الدرس سنتحدث عن جوانب أخرى لها بالأضافة الى أجزاء أخرى ستأتي توالياً حول أنواع التعريف الأخرى مثل class types و array types والتي تجمع تحت مسمى reference types و توضيحها أكثر و أكثر.

الأربعة أنواع الأولى و كما قلنا من قبل تستخدم للتصريح عن الأعداد الصحيحة ولكن ماهو الفرق بينها؟

أنظر الى الجدوال التالي:

Type Size Range ------------------------ byte 08 bits -128 ----> 127 short 16 bits -32,768 ----> 32,767 int 32 bits -2,147,483,648 ----> 2,147,483,647 long 64 bits -9,223,372,036,854,775,808 ----> 9,223,372,036,854,775,807

فوفقاً للأرقام الدقيقة في هذا الجدول يتضح أنها جميعاً تتشابه في كونها أعداداً صحيحة ولكنها تختلف في امتداد نطاق "range" هذه الأعداد.

فنطاق الأعداد الصحيحة من نوع byte يبدأ من سالب 128 الى 127 -- فمثلاُ لو تم تعريف متغير ما ليكون من نوع byte و بعد ذلك تم تخزين قيمة خارج هذا النطاق مثل 129 فإن مصحح الجافا سيدرك وجود خطأ في هذا البرنامج. بعبارة أخرى هذا النوع لايعطيك جميع الأعداد الصحيحة بل تلك التي تقع في نطاقه من سالب 128 الى موجب 127

نوع short يعطيك فرصة أكبر لنوسيع رقعة نطاق الأرقام فأي متغير من هذا النوع يمكن أن يحتوي قيمة بين -32768 الى 32767

نفس الكلام ينطبق على النوعين المتبقيين و هما int و الذي استخدمناه بكثرة في الدروس الماضية و long

لاحظ من الجدول السابق أن أعلى رقم صحيح يمكن إدراكه من خلال هذه الأنواع الرئيسية هو: 9,223,372,036,854,775,807 --- ماذا لو أضفنا 1 الى هذا الرقم؟

في هذه الحالة سيصبح الرقم هو: 9,223,372,036,854,775,808 ==> حوالي 10 مليار المليار = 10 كنتليون(الكنتليون الواحد = 1 و بعده 18 صفراً)

وبالطبع يستحيل تخزين هذا الرقم في متغبر تم تعريفه من خلال أحد الأنواع الرئيسية الأربعة السابقة بما فيها نوع long ؟ ؟ ؟ ؟ ؟ ؟ ؟ السبب: الرقم خارج نطاق الخدمة التي يمكن تقديمها ؟ ؟ ؟

سؤال مفتوح: ما الحل إذا كنا نريد رقماً يتألف من 40 خانة مثلاُ؟

ولكن السؤال الأهم حالياً لماذا هذه الأنواع الأربعة رغم أن أحدها وهو long يؤدي وضيفة جميع الأنواع الأخرى فمثلاُ الرقم 33 يوجد داخل جميع نطاقات هذه الأنواع جميعها.

نفهم السر خلف ذلك بالرجوع الى ذاكرة الكمبيوتر ---- انظر الى عمود size في الجدول السابق هذا العمود يمثل مقاس الرقم الصحيح لدينا و نقصد بمقاس الرقم عدد الخانات لهذا الرقم الصحيح ليس في النظام العشري ولكن في النظام الثنائي

الرقم 33 ينتمي الى النظام العشري ولكن الكمبيوتر سيحوله الى النظام الثنائي على النحو التالي:

33 (في النظام العشري) = 100001(في النظام الثنائي)

لاحظ أن هذا الرقم الثنائي 100001 يتألف من 6 خانات على وجه الدقة. ولكن إذا تم تعريفه ليكون من نوع byte فهو سيشغل 8 خانات وبالتالي 8 خلايا إضافية من مخيخ ذاكرة الكمبيوتر--- الخانات الإضافية ستملاً بالأصفار سيكون هذا الرقم هو:

00100001

ولكن لو تم تعريفه ليكون من نوع short سيشغل هذا الرقم 16 خلية في ذاكرة الكمبيوتر و كل خلية تتكفل بخانة. سيكون على الشكل التالي

0000000000100001

ولو كان من نوع int سيشغل 32 خلية --- انظر للجدول السابق

00000000000000000000000000100001

ولو كان من نوع long سيشغل 64 خلية --- انظر للجدول السابق

0000000000000000000000000000000000000000000000000000000000100001

الأن مارأيك انت؟ إذا كان لديك برنامجاً معيناً يتعامل مع عدد المدرسين في مدرستك و الذي يستحيل أن يتجاوز عددهم 100 مدرس مثلاُ فأي نوع تحبذ استخدامه؟. هل تحبذ ان تشغل حيزاً من ذاكرة كمبيوترك بأشياء غير ضرورية؟.

ماذا لو كان عدد المدرسين أكبر من 200؟

ماذا عن سكان دولة ما؟

ماذا عن وزن الكرة الأرضية إذا أردت تمثيلها كعدد صحيح؟

ماذا عن عدد أفوغادرو الشهير في علم الكيمياء إذا أردت تمثيله كعدد صحيح؟ ؟ ؟ ؟ ؟ 24 خانة: --- x1023 ب6.0221367

لاحظ أن الجواب المشترك للأسئلة السابقة هو: أن المسألة تعتمد على ........... (ضع ماشئت في الفراغ)

عدل في البرنامج التالي و تعمد أن تخطئ بوضع قيمة 200 مثلاُ في متغير من نوع byte لترى ماهي الرسالة التنبيهية بوجود خطأ التي ستحصل عليها بعد compile?

public class Lesson43a { public static void main(String[] args) {

byte x = 200; System.out.println(x); } }

ماذا عن float و double و char و boolean من ناحية شغل حيز من ذاكرة الكمبيوتر لمتغير ما صرح عنه بأحد هذه الأنواع؟ تفاصيل هذا السؤال في الجزء القادم من هذا الدرس

وختاماً لدرس اليوم: هل نحن أجبنا: لماذا قلنا أن int و byte و short و long و البقية تعتبر أنواع أساسية -- أي -- primitive type؟ جواب: لا.

هل تستطيع تكسير الذرة الى أجزاء أصغر؟ مشابه للسؤال الذي لم نجب عليه ولكن سنعرف لاحقاً.



 

 

  محمد سفر العتيبي 16-8-2003 21:57 59.  

 

الدرس الثالث و الأربعون (43)
Variable Types & Kinds
2-1 :Primitive Types

توقفنا في الدرس الماضي عند هذا السؤال: ماذا عن float و double و char و boolean من ناحية شغل حيز من ذاكرة الكمبيوتر لمتغير ما صرح عنه بأحد هذه الأنواع؟ و ذيل الموضوع بسؤال اخر هل يمكن تكسير الذرة. لاحظو أنني لم اقل البروتونات 1 أو الالكترونات 0 أو النيوترونات!!!!!!!!!!!!!!!!.

بعض تفاصيل هذا السؤال هي موضوع هذا الجزء

أنظر الى الجدوال التالي:

Type bitsize Range ------------------ float 32 bits 232 double 64 bits 264 char 16 bits 216: 65536 boolean 01 bits 21: true(1) or false(0)

سنبدأ من الأخيرة boolean فهي النوع الذي لايمتلك سوى قيمتين صح (true) أو خطأ(false) و لذلك لن يحجز أي متغير من نوع boolean سوى خلية واحدة في ذاكرة الكمبيوتر و يوجد بهذه الخلية اليتيمة إما الرقم الثنائي 0 ليمثل قيمة false أو الرقم الثنائي 1 ليمثل قيمة true. قارن هذا الكلام بقيمة 33 في الدرس السابق و التي مثلت ثنائياً ب16 خلية ملئية بالاصفار و الواحدات كما شرحناها. لا تنسى عزيزي أن جهاز الكمبيوتر مجرد قطع الكترونية غبية صماء صنعها البشر و ترتبط فيما بينها بالأسلاك و لا تفهم كلمات مثل true أو false بل تقهم الإشارات الكهربائية أما طافي او شغال أي 0 أو 1 و اخترعت سالفة 0 أو 1 من اجل تسهيل فهم عمل هذه القطع رياضياً لا أقل و لا أكثر. ومن يعرف اول حاسبة اخترعها بابج و ماتبعه من علماء مثل باسكال سيدرك كيف تطورت هذه الاجهزة.

انظر لذاكرة الكمبيوتر كخلية نحل ضخمة تتألف من مئات ملايين المربعات و كل مربع يمثل خلية واحدة فقط و كل خلية لاتقبل سوى قيمة ثنائة واحدة -- إما 0 أو 1.

أو عندما يحن عليك الليل اذهب الى بقعة لا يوجد فيها بشر ولكن في ليلة مقمرة ثم اضطجع على ضهرك على أحد الصياهد أو النفود نقية الرمال -- صاهد نفجان مثلاُ -- و تصفح خد السماء اللانهائي بالنسبة لمد بصرك و تأمل أن السماء مقسمة الى مربعات صغيرة و كل مربع صغير مساحته 1 سم مربع. سترى ضوء 1 نجمة ما في مربع ما و الكثير من المربعات فارغة 0. -- نعتذر عن "اللحسة"

نأتي الأن الى توضيح أكثر حول أمر تعريف اخر ينتمي الى عائلة primitive type وهو نوع char

ذكرنا سابقاً أن أي متغير من هذا النوع لايقبل سوى حرف واحد محصوراً بين علامتي التنصيص مثل 'Q' ---- حقيقة لا اعلم هل هي تسمى علامتي تنصيص او اقتباس. ارجح الأولى و لكن أرجوا من يقرأ هذا السطر و يعرف أن يخبرني من خلال صفحة الاستفسارات او على الايميل. هناك مسائل كثيرة لا انكر انني "اتنقع" كثيراً عند محاولة معرفتها.

في برنامج الجافا نكتب 'Q' ولكن ذاكرة الكمبيوتر هل ستفهم أنها قيمة Q. أبداً ذاكرة الجافا لاتفهم سوى 0 أو 1؟؟؟؟؟ جدول "خبط لزق" السابق يقول أن هذه القيمة و بما انها من نوع char فهي ستشغل 16 خلية متجاورة. أذن هذه القيمة ستفشح برجليها فوق 16 خلية و كل خلية تحتوي على اما 0 أو 1.

هناك قيم اخرى مثل و'A' و 'a'  و 'b'  و 'c' و '7' و '0' و '9' و '$' و '*' و '?' و '~' و '@' و 'ط' و 'غ' و '%' و الكثير.

كم يتخيل ذهنك من قيمة من نوع char. هناك جميع الاحرف الانجليزية بكبيرها و صغيرها و احرف اللغات الاخرى و منها العربية و هناك الرموز الخاصة مثل % و^ و  _ و + و هناك الرموز اللاتينية و هناك و هناك الكثير. فكم قيمة من نوع char قد يحتويها ذهنك و لكن بالتأكيد سيفهمها الكمبيوتر. الجواب: 65536 ---- يبدو لي انك لاتعرف منها سوى 100 كأمر طبيعي --- أنا شخصياً اعرف حوالي 150 مابين الحروف الابجدية العربية و الانجليزية الى الارقام الى الكثير من الرموز الهندسية التي تمس تخصيي الفعلي --- الهندسة الكهربائية --- فهذه الحروف تكتب احادية في برنامج الجافا مثل 'Q' ولكنها في الكمبوتر تمثل ب16 خانة و من الدرس السابق أيضاً القيم الصحيحة من نوع short تمثل ب 16 خانة في ذاكرة الكمبيوتر. فمثلاُ العديد الصحيح 81 اذا عرف ك short فهو سيكون ثنائياً على النحو التالي:

81 = 0000000001010001

لاحظ انها 16 خانة --- أيضاً القيمة الحرفية 'Q' تمثل على النحو التالي: 

'Q' = 0000000001010001 (ASCII Standard راجع)

هل لاحظت التطابق و فهمت لماذا قلنا أنها مشكلة؟ فيبدو أن حرف 'Q' و رقم 81 و جهان لعملة واحدة. و هذا مايبرر استخدامنا لأداتين تعريفتين مختلفتين short و char للتمييز بينهما. هما في لغة الألة نفس الشئ و لكن في لغة الجافا شيئن مختلفين.

البرنامج التالي صمم ليعطيك حروف ال ASCII المقابلة للأرقام الصحيحة من 0 و حتى 128. لماذا تجاهلنا أول 32 رقماً؟

class abcd { public static void main(String[] args) { short c; for (c = 0 ; c < 128; c ++) { System.out.print((char)c); } } } 0: 1: ? 2: ? 3: ? 4: ? 5: ? 6: ? 7: 8: 9: 10: 11: ? 12: ? 13: 14: ? 15: ? 16: ? 17: ? 18: ? 19: ? 20: 21: § 22: ? 23: ? 24: ? 25: ? 26: ? 27: ? 28: ? 29: ? 30: ? 31: ? 32: 33: ! 34: " 35: # 36: $ 37: % 38: & 39: ' 40: ( 41: ) 42: * 43: + 44: , 45: - 46: . 47: / 48: 0 49: 1 50: 2 51: 3 52: 4 53: 5 54: 6 55: 7 56: 8 57: 9 58: : 59: ; 60: < 61: = 62: > 63: ? 64: @ 65: A 66: B 67: C 68: D 69: E 70: F 71: G 72: H 73: I 74: J 75: K 76: L 77: M 78: N 79: O 80: P 81: Q 82: R 83: S 84: T 85: U 86: V 87: W 88: X 89: Y 90: Z 91: [ 92: \ 93: ] 94: ^ 95: _ 96: ` 97: a 98: b 99: c 100: d 101: e 102: f 103: g 104: h 105: i 106: j 107: k 108: l 109: m 110: n 111: o 112: p 113: q 114: r 115: s 116: t 117: u 118: v 119: w 120: x 121: y 122: z 123: { 124: | 125: } 126: ~ Press any key to continue...

ماهو الحرف المقابل لرقم 97 في تشفير الأسكي؟ ماهو الحرف المقابل لرقم 65 في تشفير الأسكي؟ و بناءً عليه أيهما أكبر ahmed أم Ahmed؟؟؟؟؟؟

من البرنامج قد تم التحويل من رقم الى حرف من خلال ما أسميناه casting أي التحويل من نوع أساسي الى نوع اساسي اخر. لاحظ أنه في هذه العملية أن النوع يوضع بين قوسين مثل (char)

استبدل short في البرنامج السابق  بالمعرف int --- سيعطيك نفس الجواب.

ماهي الحروف أو الرموز المقابلة ل 0 و 7 و 8 و 9 و 10؟

ماهو الرمز المقابل لكل رقم بين48 و حتى 57؟

ماهو الرقم الذي يقابل علامة يساوي =؟

أعتقد أن هذا يكفي حول نوع char

غداً مع double و float فإلى اللقاء.



 

 

  محمد سفر العتيبي 24-8-2003 20:06 60.  

الدرس الثالث و الأربعون (43)
Variable Types & Kinds
4-1 :Primitive Types

نختتم هذا الجزء حول أنواع التعريف الأساسية "" بالنوعين double و float و كما هو معلوم هذان النوعان يتعاطيان مع القيم ذات الصيغة الكسرية أو العشرية مثل 2.0001 أو 6.023 أو 2.0000

لهذين النوعين فوائد لاتوجد في الأنواع الأخرى حول التعامل مع الأرقام وخصوصاً الكبيرة منها. هل تعرف عدد افوغادرو؟ هل تعرف حجم الكرة الأرضية أو وزنها؟

قبل التطرق للفوائد سنناقش بعض الزوائد --- انظر للجدول التالي: "مقتبس من الدرس السابق" :

Type bitsize Range ----- float 32 bits <2128 double 64 bits <21024

بالنسبة لنوع float سيكون عدد الخانات بالنظام الثنائي 32 خانة(يشبه int). و بالنسبة ل double سيكون 64 خانة (يشبه long )

ولكن ماهو أعلى رقم ممكن أن نجده بإستخدام لغة الجافا؟

إذا كان المتغير من نوع double فإن أعلى رقم هو:

 

1.79769313486231570E308 = 1.79769313486231570x10308 < 21024

و أصغر عدد موجب صحيح قبل الصفر يمكن تمييزه هو:

4.9406564581246544E-324 = 4.9406564581246544x10-324

بينما إذا صرح عن المتغير ليكون من نوع float فإن أعلى رقم موجب ممكن الحصول عليه هو:

3.40282347E38 = 3.40282347x1038 < 2128

وأيضاً أصغر رقم موجب صحيح هو: 

1.40239846E-45 =1.40239846x10-45

هل تخيلت الرقم الأول؟ و هل رأيت كيف تمت كتابته؟

فالقيم من نوع double تتكون من 309 خانة عشرية(308+1) ولكن لصعوبة كتاباتها و للتوفير في المساحة التي ستشغل من ذاكرة الكمبيوتر لتخزين هذا الرقم المهول فإنها تكتب بالصورة الأسية و ذلك بإستخدام الحرف E و هو مختصر Exponent   التي تعني "أس"

تخيل لدينا عدداُ كبيراً يتألف من 7 و الى يساره 40 صفراً كما هو ممثل بمايلي:

70000,000000000000,000000000000,000000000000

هل تخيلت جسامة هذا الرقم؟ إنه يُنطَق سبعين الف تريليون تريليون تريليون(ركز على الفواصل). أو سبعين الف كنتليون كنتليون(ركز على الألوان )

في الأعداد الصحيحة --- تحديداً long -- فإن أعلى رقم نحصل عليه حسب النظام العشري يتألف من 19 خانة. بينما الرقم السابق يتألف من 41 خانة. لذا لايمكن تعريفه الا باستخدام أمر double

تخيل لدينا العدد التالي الصغير جداً مقارنة بالعدد الجسيم السابق:

9,999,999

هذا الرقم كتب بالصورة الرياضية المعروفة و الفواصل فقط لمعرفة الرقم بسرعة من خلال معرفة عدد الخانات ---- هذا الرقم أقل من 10 مليون ب 1 --- أي أنه 9 مليون و 999 الف و 999

لو أضفنا عليه 1 سيكون 10 مليون على النحو التالي:

9,999,999+1 = 10,000,000

كلا الرقمين قد يمثلان كما سبق أو بإستخدام الأس من أجل توفير الفراغ على النحو التالي:

9,999,999 = 9.999999x106 10,000,000 =10.0x106 = 1.0x107

أعتقد أن الأمور واضحة حتى الأن --- فأين المشكلة؟

طبعاً نقصد بالمشكلة كيف سيطبع برنامج الجافا الأرقام العشرية. هل بالصورة الأسية أم بالصورة الرياضية المعروفة؟

جواب: يعتبر الرقم 9,999,999 (سبع خانات) هو الحد الفاصل بين الطباعة بالصورة المعروفة و الطباعة بالصورة الأسية --- فالرقم السابق مجرد أن نضيف اليه 1 سيتكون من 8 خانات و ليس 7 --- بإمكانك عد خانات الرقم 10 مليون السابق ---- أي عندما يصبح عدد خانات الرقم ادينا 8 فإن عرض الرقم سيكون بالصورة الأسية على النحو التالي:

1.0E7=1x10000000 = 1.0x107

لا شك أنك أدركت أن الحرف E يعني "10 أس"

واختصاراً لو كان عدد خانات الرقم لدينا 7 أو أقل فإن البرنامج سيعرضه كما هو ولكن لو تجاوز عدد الخانات 7 فإنه سيعرض بالصورة الأسية --- انظر للبرنامج التالي و الذي كتبناه ليطبع عددين أحدهما هو 9999999 و الأخر هو 10000000

class DoubleEaxample { public static void main(String[] args) { double x,y; x=9999999; System.out.println("x = "+x); y=x+1; System.out.println("y = "+y); } } x = 9999999.0 y = 1.0E7 Press any key to continue...

الان سنكتب برنامجاً بسيطاً لمجرد عرض رقم ما و هذا الرقم هو:

12345678901234567901234567890.0

واضح أن الجزء الصحيح لهذا الرقم يتألف من 30 خانة فهل سيكتبه البرنامج على النحو التالي(7 خانات و هي السعة الأعلى على يسار الفاصلة كما ذكرنا و البقية على اليمين):

1234567.89012345678901234567890E23

ام على هذا النحو(رقم واحد على يسار الفاصلة و البقية في الجزء الكسري :

1.23456789012345678901234567890E29

أم سيكون بصورة أخرى؟

الحقيقة أن الجواب سيكون مشابه للنموذج الثاني أي رقم واحد على يسار الفاصلة و البقية تختزل من خلال الأس ولكن سيتم تقريب الجواب لأقرب 16 خانة بدلاً من 29 خانة بعد الفاصلة حيث سيتم التخلص من الخانات الزرقاء في العدد السابق --- ستكون محصلة برنامجنا على النحو التالي:

1.2345678901234567E29

سنتأكد من شرحنا هذا باستخدام البرنامج التالي:

class DoubleEaxample { public static void main(String[] args) { double x; x=12345678901234567901234567890; System.out.println("x = "+x); } } x = 1.2345678901234568E29 Press any key to continue...

لاحظ في الجواب النهائي أن 8 كتبت بدلاً من 7 (انظر للرقم 8 باللون الأصفر) و السبب هو التقريب العشري حيث تم تقريب ال 7 الى 8 لأن العدد على يمين 7 وهو 8 و الذي تم التخلص منه أكبر من 5 و بالتالي تم التقريب.

ذكرناً في بداية الدرس أن أعلى قيمة يتم تمثيلها بإستخدام double تتألف من 309 خانة  و هذا الرقم تحديداً هو:

1.7976931348623157E308

لو غيرنا الرقم 57 باللون الأحمر الى 59 (إضافة بسيطة)--- فإن الكمبيوتر سيصاب بالغثيان ولن يفهم الرقم لأنه خارج الخدمة الممكن تقديمها -- فالرقم السابق هو أفضل الموجود و الرقم التالي هو بداية الغثيان حيث سينتج لديك رسالة تنبيه لخطأ بعد compile

1.7976931348623159E308

ضع هذا الرقم كقيمة للمتغير x في البرنامج السابق سينتج لديك الرسالة التالية:

--------------------Configuration: JDK version 1.3.1_01 Default-------------------- C:\Documents and Settings\User\Desktop\J\abc.java:6: floating point number too large x=1.7976931348623159E308; ^ 1 error Process completed.

و بما أن هناك خطأ فلايمكن تنفيذ البرنامج. و إن تم تنفيذه بالصدفة و بالصدفة كان لديك ناتجاً ما --- فاعتبر هذه القيمة أتت من الواق واق أو خرجت من فم سمكة تسبح في بحيرة البجع.

لاتنسى أن تلحق القيم من نوع double بالحرف D أو d بعد نهاية الرقم و القيم من نوع float بالحرف f أو F و لكي لا ننسى القيم من نوع long يمكن الحاقها بالحرف L أو l كما في الأمثلة التالية:

long x= 78L; float d=1.2f, d2 = 3.33F; double y = 1.23D, y2 = 1.2635E-45D, y3 = 4.7E-6d;

علامة الأس العشري E قد تكتب صغيرة أو كبيرة -- أي E أو e كما في المثال التالي:

double y2 = 1.2635E-45, y3 = 1.2635e-6;

يتبقى كيفية تمثيل الرقم من نوع float أو double داخل ذاكرة الكمبيوتر و التي لاتعرف سوى لغة 1 أو 0 و من الجدول السابق نعرف كم عدد الخلايا التي سيحجزها كل نوع فعندما يتم تعريف المتغير ليكون من نوع float فإنه سيتم حجز 32 خلية لتخزين هذا الرقم بينما سيتم حجز 64 خلية لو كان المتغير من نوع double و ليست القضية سلسة هنا لوجود الأس أو الفاصلة و لاننسى مانسيناه في الدرس السابق وهو أن أول خلية تمثل الإشارة فإذا كانت اشارة الرقم + تملاً أول خلية بالصفر و إذا كانت الإشارة -(سالب) تملأ اول خلية بالرقم 1 ---- بقية الخلايا لتمثيل الرقم نفسه.

float binary representation -- للقراءة فقط

تمثيل القيم من نوع float يعتمد على تصنيف IEEE Floating-Point Standard 754  و الذي يدرس كيفية تحويل العدد من نوع float الى عدد ثنائي مفهوم --- ذكرنا أن هذا النوع يستغل 32 خلية متجاورة وكل خلية تحمل إما 0 أو 1 --- سنفترض أن جميع الخلايا مدبئياً فراغة على النحو التالي:

00000000000000000000000000000000 : عدد الخلايا 32

الخانة الأولى محجوزة للإشارة(خانة واحدة) و الخانات من 2 الى 9 محجوزة للأس(8 خانات) و الخانات من 10 الى 32 محجوزة للجزء العشري(23 خانة). قارن بين الألوان

الان تخيل ان العدد لدينا من نوع float هو:

0.5

الإشارة موجبة لذلك أول خانة ستكون 0 و ليس 1 --- هذا العدد يجب أن يكتب أولاً بالصورة الأسية و ذلك على النحو التالي:

0.5 =1/2 = 1.0x2-1

لاحظ أن الأساس هو 2 و الأس -1 ----- هذا الأس سيشغل الخانات من 2 الى 9 --- فما هو المقابل الثنائي للعدد -1؟

لأن النوع لدينا double و للتخلص من الناقص فإننا نضيف اليه العدد 127 كما تم تعريف ذلك من خلال المقياس العالمي IEEE-Standard سيصبح المكافئ الأسي ل -1 هو 127 - 1 = 126

126 مجرد رقم عشري و من السهل تحويله الى رقم ثنائي (-1 و 126 تعتبر نفس الشئ) و ذلك على النحو التالي: 

-1 + 127 = 126 = 01111110

حتى هذه اللحظة تم ملئ الخانات من 1 الى 9 و أصبح الرقم الثنائي هو: 

00111111000000000000000000000000

بقية الخانات و كما ذكرنا محجوزة للجزء العشري "الكسري" وهو 0 في حالتنا هذه --- انظر للصفر باللون الأخضر في سطر سابق و نعيده هنا:

0.5 =1/2 = 1.0x2-1

و هذا يقتضي أن جميع الخانات الباقية يجب أن تملاً بالصفر. و سيكون الرقم مرتباً في ذاكرة الكمبيوتر على النحو التالي: 

0.5 = 00111111000000000000000000000000

غني عن القول أن مكان النقطة "الفاصلة"  سيكون بين اللون الأزرق و البني و للتوضيح فقط:

0.5 = 001111110.00000000000000000000000

لو كان الرقم -0.5 --- بالسالب --- فقط غير الصفر الأحمر الى 1 و ذلك على النحو التالي: 

-0.5 = 101111110.00000000000000000000000

الأمثلة التالية إضافية و عليك إثباتها و الأجوبة مؤكدة:

1.0 = 001111111.00000000000000000000000 1.5 = 011111111.10000000000000000000000 6.5 = 010000001.10100000000000000000000 10.65 = 010000010.01010100110011001100110

ماذا عن القيم من نوع double؟

نفس الإجراءات السابقة و لكن هنا الدقة ستكون مزدوجة "double precsion" على عكس نوع float و الذي كانت الدقة فيه احادية "single-precsion"

الخانة الأولى للإشارة و الخانت ال 11 التالية للأس و بقية الخانات (52 خانة) محجوزة للجزء الكسري. و المجموع هو 64 خانة على النحو المبدئي التالي: 

0000000000000000000000000000000000000000000000000000000000000000

لا أنصحك بعدها فهي 64 خانة. سنعيد مثالنا السابق على افتراض أن القيمة 0.5 تم تعريفها في متغير من نوع double ---- الإشارة موجبة --> أول خانة تملاً بالصفر --- الأس هو نفسه بعد التحويل و يساوي سالب واحد -1 ---> بدلاً من 127 نستخدم 1023 ---> إذن

-1 + 1023 = 1022

بتحويل 1022 اللا النظام الثنائي : 

1022 = 01111111110

بقية الخانات صفر لأن الجزء العشري يساوي 0. و بناءً عليه سيكون 0.5 على النحو التالي ثنائياً: 

0.5 = 0011111111100000000000000000000000000000000000000000000000000000

أمثلة أخرى: 

4.0 = 0100000000010000000000000000000000000000000000000000000000000000 4.5 = 0100000000010010000000000000000000000000000000000000000000000000 5.0 = 0100000000010100000000000000000000000000000000000000000000000000 5.5 = 0100000000010110000000000000000000000000000000000000000000000000 -5.5 = 1100000000010110000000000000000000000000000000000000000000000000 10.0= 0100000000100100000000000000000000000000000000000000000000000000

 لمعرفة المزيد حول تحويل الأرقام العشرية "الكسرية" الى لغة الكمبيوتر ابحث في الانترنت عن مواضيع تحتوي على العناواين التالية و ذلك من خلال إحدى محركات البحث الشهيرة و لاتنسى أن الجزء الأخير للقراءة ة الثقافة العامة حول جزئية بسيطة في فهم ذاكرة الكمبيوتر لأحد اجزاء البرنامج. و هي قد تبدو صعبة في البداية ولكنها ممتعة و مشوقة بعد أن تنغمس فيها قليلاً.

IEEE-754 Floating-Point Conversion: From Decimal Floating-Point To 32-bit and 64-bit Hexadecimal Representations Along with Their Binary Equivalents

الدرس القادم حول reference types

 



ـ ــ أشلاءــ ـو مـ الكلمةـ ـاجاورها

 

  محمد سفر العتيبي 29-8-2003 15:28 61.  

الدرس الثالث و الأربعون (43)
Variable Types & Kinds
Reference Types 2-1: class name types

في القسم الأول من الدرس 43 توسعنا أكثر حول أنواع التعريف الأساسية أو الأولية "primitive types" الأن مع النوع الثاني و هو reference types

reference types تنقسم الى قسمين و هما:

  1. The name of a class or interface :::: اسم الفئة أو اسم وتجهة التداخل
  2. An array :::: المصفوفات

واجهة التداخل "interface" لأول مرة نذكرها و هي إحدى الخصائص الجميلة في لغة الجافا وسيتم تأجيلها حتى الدرس الأخير لأن هناك مكانها الطبيعي ولكن حالياً يكفي أن تعرف أنها عموماً تحت خانة المتغيرات من نوع reference

المصفوفات Arrays مرت معنا سابقاً و تنتمي الى reference type و ليس primitive type وسيتم تأجيل الحديث عنها. و سنركز اليوم على class types

reference types قد نترجمها حرفياً الى المتغيرات المرجعية فهي ليست أساسية مثل ال primitive types بل مرجعية.

ولكن أشهر فئة تعتبر reference types هي فئة String

 

من كثرة التكرار قد يتبادر الى ذهنك عند ذكر كلمة نوع المتغير الأعداد بأنواعها أو الأحرف أو القيم المنطقية. احذر من هذا التفكير ---  فكر بنظرة أشمل --- تأمل الأمثلة التالية:

التاريخ Date

الألوان Color

الأشكال الهندسية Shape

أنواع الخطوط Font

و غيرها الكثير و التي قد نجمعها تحت اسم "name" معين و نسميه نوع "type"

ماذا يتبادر الى ذهنك عندما نقول أننا نستخدم نوع التعريفint؟

لاشك أن الذي يتبارد الى ذهنك هو الأرقام الصحيحة مثل 2 و 6 و 107 و -4 و هكذا بينما لو ذكرنا نوع char فسوف يقفز الى ذهنك حروف الأبجدية مثلاُ.

الان دعونا نجعل نظرتنا شمولية أكثر و نسأل نفس السؤال مالذي سيتبادر الى ذهنك لو أخبرناك أن Color مثلاُ أحد أنواع التعريف في لغة الجافا؟

لاشك أنك ستتذكر الأصفر "yellow" و الأزرق "blue" و الأحمر "red"  و الأسود "black"  و الأبيض "white" و الأخضر "green" و البني "brown" و الرمادي "gray" و البرتقالي "orange" و الوردي "pink" و البنفسجي "violet"   و ...... "purple" و بقية الألوان و التي يربو عدد مخاليطها من الألوان الأساسية الثلاثة "الأخضر+الأحمر+الأزرق" على المليون لون و تحديداً 1600000 لون:: (مليون و ستمائة الف)

ماذا لو قلنا لك أن هناك نوع تعريفي اخر في لغة الجافا اسمهShape؟

لاشك أنك ستتذكر الأشكال "Shapes" المختلفة مثل الدائرة "Circle" و المستطيل "Recatangle" و الشكل الإهليلجي أو البيضاوي "Oval" و المثلث "Traingle" و الخماسي "Pentagon" و المربع "Square" و غيرها ---- Oval تعادل كلمة القطع الناقص في الرياضيات. فهي دائرة ولكن قطرها العمودي لايساوي قطرها الأفقي.

و أي شكل تتخيله فهو موجود في لغة الجافا أو يمكنك صناعته إن لم يكن موجوداً باستخدام ماهو موجود.

ماذا لو أخبرناك أن هناك أيضاً نوع تعريفي اسمه Font ؟ و أن هناك نوع تعريفي اخر اسمه Date ؟

جميع ماذكر سابقاً هو أنواع تعريفية تقهمها الجافا وجميعها تعتبر reference types و أيضاً جميعها تعتبر اسم فئة "class name" ---- أي انها ببساطة عبارة عن اسم برامج كالتي كتبناها حتى هذه اللحظة ولكن هذه البرامج مكتوبة و معدة مسبقاً في مكتبة الجافا و في المكان المناسب.

معنى هذا الكلام أن البرتمج التي كتبناها و تبدأ بكلمة class name تعتبر أيضاً أنواع تعريفية من إعداد المستخدم.

هذا يقود الى الحقيقة التي تقول: أن المستخدم بإمكانه صناعة انواع تعريفية تلائم احتياجاته.

الكلام السابق كلام نظري و من خلال الأمثلة المكثفة تصل الفكرة.

سنناقش أولاً نوع Date --- هذا النوع يعتبر فئة "Class" و على وجه الدقة "اسم فئة" وهو برنامج معد سابقاً في مكتبة الجافا. لا أشك لحظة واحدة أنك متيقن أن اول سطر من هذا البرنامج الجاهز في مكتبة الجافا و لانحتاج أن نعرف تفاصيله هو:

class Date {

// تفاصيل هذا البرنامج }

لسنا في حاجة لمعرفة تفاصيل هذا البرنامج ولكننا في حاجة لمعرفة كيف يمكننا استخدامه كونه جاهز للاستعمال.

سيارتك ؟ لست في حاجة لمعرفة كيف تم صناعتها --- أنت فقط في حاجة لمعرفة كيف تقودها.

جهاز التلفاز؟ الراديو؟ الخبز؟ الكمبيوتر؟ كأس الحليب؟ كلها جاهزة للاستخدام ---- استخدمها من غير ان تقلق كيف تم صناعتها.

إذن Date ذكرنا أنها و حسب الترتيب في هذا الدرس:

1. تعريف للمتغير و تعتبر Reference Type

2. اسم فئة "Class name" موجودة في مكتبة الجافا سلفاً

سنضع 1 و 2 في جملة مفيدة. "بإمكاننا استخدام اسم الفئة للتعريف و التصريح عن نوع المتغير"

مع البرنامج التالي:

import java.util.*; class Lesson34 { public static void main(String[] args) { Date x = new Date(); System.out.println(x); } } Fri Aug 29 07:41:27 AST 2003 Press any key to continue...

في البرنامج السابق تم تعريف المتغير x ليكون من نوع Date. و بعد إدخال هذا المتغير في أمر عرض الجواب println كان الجواب كما ترون باللون الأصفر وهو:

Fri Aug 29 07:41:27 AST 2003

و هو عبارة عن متسلسلة تتألف من عدد من الأرقام و الكلمات و يفصل بينها بعض "الفراغات" أو ":" لتمثيل التاريخ و اليوم ونظام التوقيت و غيرها كما سيأتي:

1. اسم اليوم >   Fri   == الجمعة

2. الشهر >  Aug ==أغسطس

3. اليوم > 29

4. الساعة > 7  

5. الدقيقة > 41  

6. الثانية > 27  

7. نظام التوقيت >  AST   اختصار Arab Standard Time

8. السنة > 2003

أعتقد أن المثال السابق يغني عن مزيد شرح و لكن الأهم هو الطريقة التي تم بها التعريف -- لقد استخدمنا أمر الانشاء new على النحو التالي:

Date x = new Date();

السبب: لأنها reference type ومجرد وجود هذا السطر يعني أنه يأمر بإنشاء كائن جديد من فئة موجودة أصلاً --- بالبدوي الفصيح "يقول لبرنامجك اذهب الى مكتبة الجافا و تحديداً java.util --انظر لوجودها في أعلى البرنامج السابق -- ستجد هناك برنامجاً اسمه Date --هذا البرنامج صمم خصيصاً ليذهب لنظام التوقيت على جهازك "Windows" مثلاُ و يأخذ بيانات اليوم الثمانية السابقة و يحضرها لبرنامجك وبالتالي تستطيع عرضها. كل هذا يحدث بسبب وجود السطر السابق.

أمر new نستطيع أن نقول إنه العلامة الفارقة في المتغيرات من نوع reference -- وهذا يقتضي أن مامر معنا سابقاً من كائنات تم تعريفها بساتخدام هذا الأمر new -- ينتمي الى عائلة reference مثل المصفوفات arrays و String و StringTokenizer و BufferReader و StringBuffer و PrintWriter و FileWriter و InputStreamReader -- هل نسيت شيئاً مما سبق --  و سواها الكثير.

كل واحدة من هذه الفئات له وظيفة محددة مختلفة عن الأخرى و لكن جميعها تعتبر أنواع تعريفية و تعريفها داخل البرنامج يتخذ نفس الكيفية على النحو التالي:

Date x = new Date() =====> class_name variable = new constructor

 

فهي تبدأ باسم الفئة "Class name" و هو في حالتنا هذه Date

ثم المتغير "variable" وهو في حالتنا هذه  x

ثم علامة يساوي = "assignmenet operator" 

ثم new  و هي أمر إنشاء كائن جديد من الفئة لدينا وهي في هذه الحالة Date

ثم أخيراً المشيد "Constructor" وهو في هذه الحالة Date --- لاحظ الفرق أن في الأخيرة يوجد القوسين () و بالتالي عرفنا أنها constructor و ذكرنا في درس سابق أن وجود هذا النوع من القوسين يقتضي أن الذي لدينا يعتبر منهج "method" و قلنا أن المنهج هو جزء من الفئة ----- في حالتنا هذه يعني هذا الكلام أن برنامج Date الموجود في مكتبة الجافا يحتوى على منهج اسمه ()Date  و إذا حدثت هذه الحالة الخاصة و هي أن اسم المنهج هو نفسه اسم الفئة --أي البرنامج -- فالمنهج في هذه الحالة يسمى اصطلاحاً constructor

constructor = > special method

نأتي الأن لأشهر الأنواع التي تصنف تحت خانة reference type وهو السلاسل String و بنفس الكيفية التعريفية السابقة يكتب على النحو التالي:

String y = new String("Alsaha")

فهنا تم انشاء كائن اسمه y من فئة String وتم تخزين قيمة "Alsaha" في هذا الكائن "object".

لاحظ أن بيت القوسين وضعنا قيمة و في Date تركنا القوس فارغاً وقد نفعل العكس لكليهما حسب الهدف من البرنامج وهو ليس موضوعونا الان.

مارأيك أن نقول أن كلمتي "إنشاء كائن" هي وجه اخر لكلمتي "تعريف متغير" و بالتالي "إنشاء الكائن" هي نفسها "تعريف المتغير"  و "أنشأنا كائناً" تعادل "عرفنا متغيراً" و باقي تصاريف اللغة العربية الممكنة.

إذن من هذه اللحظة سنستخدم كلمتي "تعريف المتغير" مع المتغيرات الأساسية "primitive types"

و كلمتي "إنشاء كائن" مع المتغيرات غير الأساسية reference types"

ولكن دوماً و أبداً لاتنسى أنهما وجهين لقطعة معدينة واحدة.

--------------------------------------------------------------

في الجزء القادم من هذا الدرس سنكمل مع أنواع أخرى كأمثلة و عليك أن تلاحظ من الشرح الفروق بين primitive types و reference types -- 

درس اليوم كان الفرق هو أننا نستخدم أمر new في تعريف المتغيرات التي تنتمي الى ال reference types

اليوم تم التطرق ولو تنويهاً الى ذكر بعض الفئات الجاهزة و التي تستخدم كصيغ تعريفية مثل Font و Color و Shape و Date و String و أيضاً هناك نوع شهير إن لم يكن الأشهر و هو فئة Graphics

أيضاً هناك ماذكرناه باختصار في درس سابق و هو مايسمى بال Wrapper classes أي "الفئات المغلفة" و ستكون في الجزء الثالث تحت عنوان درس اليوم.

جميع هذه الفئات التعريفية بإستثناء Date و String سيتم التطرق لها في الجزء الثاني من سلسلة الجافا عند دراسة ال Java Applets and GUI في الشهر القادم بإذن الله بما يعتبره الكثيرون فاكهة هذه اللغة --بينما في الغد سيتم التطرق الى فئات اخرى جاهزة ولكن تعتبر جديدة بالنسبة لك كدارس للغة الجافا مثل فئة Random و BitSit و Vector

====================================

سؤال منزلي1: ماذا نقصد بالكلمات التالية؟ لا تستخدم اكثر من 5 كلمات في شرحها و كلمة واحدة قد تكفي لبعضها حتى هذه اللحظة

class -- object -- method --- constructor --- interface --Shape --Font

سؤال منزلي2: للقراءة فقط: ماذا نقصد بالكلمات التالية:

memory -- value --address --space -- instance -- pointer --memory space -- allocate -- initialize -- reference variable -- collection -- element -- null -- index -- subcsript

سؤال منزلي3: مجرد اختبار فقط:مايأتي كلمة و عكسها فما معنى كل كلمة حرفياً و فهماُ؟

automatic : : nonautomatic                        automatically  : :  nonautomatically

                 implicit : : explicit                                     implicitly : : explicitly

سؤال منزلي4: في أي جزء من مكتبة الجافا توجد الفئة Date ؟ الجواب: java.util



 

 

  محمد سفر العتيبي 31-8-2003 15:38 62.  

الدرس الثالث و الأربعون (43)
Variable Types & Kinds
Reference Types 2-2: class name types: Point, Random

سؤال منزلي 1: كم نوعاً تعريفياً يوجد تحت خانة ال reference type ؟

جواب1: 3 و هي:

1. class type مثل Date و String و StringTokenizer و Random أو أي أسم برنامج قد كتبناه مثل: LessonOne في الدرس الأول 

2. interface type: لن نتطرق له وهو مؤجل حتى الدرس الأخير.

3. array type مثل: [ ]int و [ ]double و [ ][ ]String و  [ ]boolean و تم التطرق لها سابقاً.

-------------------------

السؤال السابق من درس الأمس و كما يقول المثل: التكرار يعلم ....... (للأسف الشديد نسيت بقية المثل)

اليوم سنناقش فئات إضافية جاهزة تدعمها مكتبة الجافا و هي فئة Random و فئة Vector و فئة Point و فئة BitSet و نحن لانناقش هذه الفئات بحد ذاتها و لكن نناقش كيفية استخدامها كأدوات تعريف في البرنامج على غرار الأدوات التعريفية الأساسية -- فكل فئة من هذه الفئات مثلها مثل فئة String و StringBuffer بإحتوائها على العديد من المناهج و التي تؤدي وظيفة محددة. و التركيز هنا ليس على مناهج هذه الفئات بل على استخدامها كأدوات تعريفية لعلاقتها بعنوان الدرس. فالفئات الأربع السابقة هي ضمن عشرات الفئات الموجودة في مكتبة الجافا و تعتبر Reference types و نستخدمها هنا فقط كأمثلة رغم ان هذه الفئات الأربع تحديداً يجب أن يكون تعلمها في مستويات تعليمية أعلى من هذه المرحلة و لكن لكل شيخ طريقته. اكره العبارة الأخيرة و لكن ...........

سنبدأ بفئة Point

Point class

مثلها مثل تعريف ماسبق من ال reference type حيث ننشئ الكائن "نعرف المتغير" باستخدام أمر new -- لماذا؟

جواب: لأنها reference type

سيكون ذلك على النحو التالي:

Point a = new Point(x,y);

كما قد يستشف بعضكم من الاسم "Point" و تعني نقطة فهذه الأداة التعريفية صممت في لغة الجافا لتعريف الأزواج المرتبة على مستوى الإحداثيات الديكارتي -- المستوى --- هذا يبرر وجود قيمتين x و y بين أقواس Point --- هاتين القيمتين x  و y يجب أن تكونا عددين صحيحين من نوع int. البرنامج التالي يعرف المتغير a ليكون نقطة على المستوى -- ذلك تم من خلال أمر التعريف Point

بعد ذلك و من خلال المشيد (س,ص)Point يتم تخزين القيمة "الزوج المرتب س و ص" في هذا المتغير -- دعونا نكون أكثر دقة و فهماً و نقول في هذه النقطة.

مايهمنا هنا شرحناه ولكن هذه الفئة "Point" تستخدم في تطبيقات شهيرة --- تخيل أنك صممت لعبة حربية معينة باستخدام الجافاابلت وعندما تطلق رصاصة فإنها تذهب من النقطة س الى النقطة ص. لاشك ان فئة Point لها دخل في تحديد النقطة او عدد من النقاط. ففيها يوجد منهج اسمه move و مناهج اخرى ليس هذا اوانها--- الشرح الاخير للثقافة العامة و الأمثلة أكثر من أن تحصى و قد يحين وقت نترجم فيه هذا الكلام الى واقع تطبيقي من خلال تصاميمنا.

class PointExample { public static void main(String[] args) { Point a = new Point(5,3); System.out.println(a); } } (5,3) Press any key to continue...

من ناتج البرنامج السابق هل لاحظت كيف فهمت الجافا كيفية عرض الاحداثي السيني و الصادي للنقطة a --- لقد تم عرضها كما اعتدنا كتابتها في مقررات الرياضيات -- فالزوج المرتب يعبر عنه باستخدام القوسين و يفصل بينهما فاصلة. (5 , 3)

أيضاً قد يستخدم هذا الأمر كمصفوفة رغم أنه Reference type -- تماماً كما فعلنا مع النوع الشهير التعريفي الشهير String و ذلك على النحو التالي:

Point[] a = { new Point(4,3), new Point (2,9)};

فنحن هنا لدينا مصفوفة من نوع Point عدد عناصرها 2 و كل عنصر يمثل زوجاً مرتباً: الزوج المرتب الأول (4,3) هو و الزوج المرتب الثاني (2,9)

Random class

Random و تعني عشوائي و هو فئة في مكتبة الجافا و تحديداً تحت رف "java.util" و يستخدم للتعريف بنفس الصيغة السابقة حيث يجب استخدام أمر new. افترض أننا قلنا يجب بنسبة 90% فهناك حالات شاذة.

بدلاً من استخدام كلمة "عشوائي" دعونا نقول "توليد ارقام عشوائية و من أي نوع"

إذن: هذه الأداة تنحصر وظيفتها في توليد الأرقام العشوائية سواءً من نوع int أو long أو float أو double و ذلك بإستخدام المنهج المناسب المتعلق بكل نوع.

التعريف على النحو التالي:

Random r = new Random();

هنا تم تعريف المتغير r  ك Random و هذا المتغير بحد ذاته ليس رقماً بل يستخدم لتوليد الرقم. لاحظ دقة العبارة. هذا الرقم الذي نود توليده عشوائياً نحن من يحدد نوعه مسبقاً إما int أو long أو float أو double --- فهناك أربعة مناهج في هذه الفئة Random و هي : منهج ()nextInt والذي يستخدم لتوليد الأعداد من نوع int و منهج ()nextLong والذي يستخدم لتوليد الأعداد من نوع long و منهج ()nextFloat و الذي يستخدم لتوليد الأعداد من نوع float و منهج ()nextDouble والذي يستخدم لتوليد الأعدلد من نوع double.

البرنامج التالي صمم بإستخدام جملة for ليولد 5 أرقام عشوائية على التوالي من نوع long و لذلك تم تعريف المتغير x ليكون long و بالتالي يلزمنا استخدام منهج Random المناسب وهو في هذه nextLong ---- الجواب النهائي أسفل البرنامج:

import java.util.*; class PointExample { public static void main(String[] args) { Random r =new Random(); long x; for(int i=1;i<=5; i++) { x = r.nextLong(); System.out.println(x); } } } 8017471308026130765 1055022869523171461 -4666092626985481231 6900855756884234733 -1801427158451876438 Press any key to continue...

لاحظ الأرقام و طولها (19 خانة: ماذا يذكرك هذا؟) --- لو تم تعريف المتغير x ليكون int و تغيير مايلزم (غير nextLong إلى nextInt  ة بعد ترجمة و تنفيذ البرنامج مرة أخرى كان الجواب معي هو:

-1430064046 -1047220826 1167891498 862278342 85452661 Press any key to continue...

لاحظ مدى الأرقام ---- ماذا لو تم استخدام double و منهجها الخاص nextDouble -- بعد تغيير مايلزم في البرنامج السابق و إعادة الترجمة ثم التنفيذ كان الجواب معي:

0.38696243079668236 0.322426997712692 0.6546376128909921 0.11502901047293812 0.2317239873309408 Press any key to continue...

ماذا تلاحظ في هذه الأرقام؟ هل جميعها تقع بين 0.0  و 1.0؟ ها تذكرك شيئاً ما-- Math.ran مثلاُ؟ كم عدد الأرقام على يسار الفاصلة؟ لماذا؟

الأن سننفذ البرنامج السابق بعد تغيير مايلزم ولكن بالنسبة ل float --- كان الناتج العشوائي:

0.024551094 0.4595768 0.5123665 0.43783343 0.88667035 Press any key to continue...

هناك مناهج أخرى و ليس خارج مجال هذا الدرس فالقصد هو تحديد وظيفة فئة Random و التي تعتبر reference type و لن يستقيم شرح بدون أمثلة.

سؤال منزلي:اكتب برنامجاً يولد أعداداً عشوائية ولكن تقع بين 0 و 100؟

مساعدة لحل السؤال: استخدم نفس البرنامج السابق ولكن بإضافة علامة باقي القسمة % لتحصر الرقم بين 0 و 100. فقط أضف السطر التالي خلف ()x=r.nextInt

x=x%100;

 Vector class

التفاصيل في الدرس القادم

Vector v = new Vector();

لماذا تستخدم هذه الفئة؟ هل يعني لك الاسم شيئاً؟

BitSet class

التفاصيل في الدرس القادم

BitSet b = new BitSet();

نفس السؤال السابق.



 

 

  محمد سفر العتيبي 02-9-2003 16:34 63.  

الدرس الثالث و الأربعون (43)
Variable Types & Kinds
Reference Types 2-3: class name types: BitSet, Vector

الدرس الماضي كان حول فئتي Random و Point و اليوم سيكون حول فئتي BitSet و Vector و غداً حول الفئات المغلفة Wrapper classes و كل هذه الفئات تقع تحد بند  reference types و نضعها هنا كأمثلة شهيرة على هذا النوع في لغة الجافا.

BitSet class

 ننشئ كائناً من هذا النوع "نعرف المتغير" باستخدام أمر new -- لماذا؟

سيكون ذلك على النحو التالي:

BitSet b = new BitSet();

الأن لدينا كائناً اسمه b تم إنشاءه بإستخدام فئة BitSet

و ظيفة هذه الفئة هو فحص عدد موجب صحيح مثل 44 مثلاُ ومن ثم تحويله الى عدد ثنائي و بعد ذلك تنتج هذه الفئة مصفوفة يوجد بها رقم الخانات التي تحتوي على الرقم 1 و يتجاهل الخانات التي تحتوي على الرقم 0. الرقم 44 ثنائياً هو:

44 = 101100

101100 : انظر للخانات من اليمين الى اليسار و ابدأ عد الخانات من الصفر. من هذا العدد الثنائي يتضح أن الخانات 2 و 3 و 5 مملوءة ب 1 و الخانات 1 و 4 و 5 مملوءة ب0

إذا كان حرصنا على العدد 1 فإن قيمة b ستكون مصفوفة من 3 عناصر و هذه المصفوفة هي: 

b = {2, 3, 5}

بينما إذا كان حرصنا على 0 سيكون الكائن "المتغير" b: 

b = {0, 1, 4}

الأن ما رأيكم أن نترجم الكلمة BitSet فقد يعني ذلك الكثير. Bit تعني رقم ثنائي واحد و نعلم أن الخانة الثنائية لا تتقبل سوى رقمين إما 0 أو 1 --- قارنها بالخانة العشرية التي قد تتقبل 10 أشكال و هي "0" و "1" و "2" و "3"و "4" و "5" و "6" و "7" و "8" و "9" ----------  Set تعني مجموعة و مرادفها Collection و الكلمتين "Bit" و "Set" معاً تعني مجموعة من الأرقام الثنائية

ذكرنا كلمة Collection  هنا لأنها كلمة شهيرة في لغة الجافا و خصوصاً في موضوع ال Data Struture فتحت هذه الكلمة في هذا الموضوع يأتي مصطلحات عديدة منها BitSet و هناك Stack, ArrayList و Queue و Vector و غيرها الكثير من الفئات ذات العلاقة.

المثال التالي عبارة عن برنامج يحدد مكان "رقم" الخانات التي يوجد بها "1" للرقم الصحيح 44

import java.util.*; public class BitSetExample { public static void main(String[] args) { BitSet b = new BitSet(); for(int i = 0; i <=31; i++) if(((1 << i) & 44 ) != 0) b.set(i); else b.clear(i); System.out.println(b); } } {2, 3, 5} Press any key to continue...

سنبدلأ شرح البرنامج من أخره حيث أمر الطباعة للمتغير b و هو من نوع BitSet أو مجموعة بتات -- تمعن جيداً كيفية عرض الناتج النهائي إنها عدد من الأرقام الصحيحة بين قوسي المجموعة و هذا بالضبط هو الهدف المحدد لفئة BitSet --- هنا و لو انها خارج نطاق هذا الدرس استخدمنا منهجين "two methods" و هما ()set و ()clear وواضح جداً أن هذين المنهجين يوجدان في فئة BitSet --- هل لاحظت ارتباطها بالمتغير b الذي تم انشاؤه من خلال هذه الفئة. و فئة BitSet توجد في مكتبة الجافا و تحديداً في قسم ال java.util

في البرنامج السابق تم استعراض الرقم 44 من اليمين اليسار فإذا كان العنصر في الخانة 1 فنحن نستخدم منهج set

و إذا كان صفر فإننا نستخدم منهج clear

سؤال منزلي1:  أعد ترجمة و تنفيذ البرنامج السابق بعد استبدال الرقم 44 بالأرقام 32 و 49 و 66 على التوالي هل ستحصل على الأجوبة التالية:

32: {5} : 100000 //لاحظ وجود 1 في الخانة 5 49: {0, 4, 5} : 110001 66: {1, 6} : 1000010

Vector class

هذه الفئة توجد في java.util و قد برزت الحاجة لتصميم هذه الفئة للتحكم ديناميكياً في تخزين الكائنات. فللأسف الجافا كانت لا تحتوي على فقرات ربط ديناميكية للبرامج البنائية "Data Structure" و الان هذه الفئة تلعب هذا الدور. موضوعها ليس طويلاً ولكن ستأتي تحت عنوان Data Structure في الجزء الثالث من سلسلة تعلم الجافا بإذن الله. ما يهمنا هو نظرتنا اليها ك reference type و كيفية انشاء الكائنات من خلالها مع نبذة بسيطة عن وظيفتها من خلال مثال برمجي مبسط الى حد ما.

إنشاء الكائن و كالعادة يتم على النحو التالي:

Vector r = new Vector();

المثال البرمجي التالي يشرح الوظيفة الأساسية لهذه الفئة المسماة Vector.

import java.util.*; class VectorExample { public static void main(String[] args) {

Vector v = new Vector(); for (int i= 0; i<20; i++) { v.addElement(new Integer(i)); } System.out.println(v); } } [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] Press any key to continue...

وكما فعلنا سابقاً سننظر محصلة السطر الأخير وهو أمر الطباعة --- الا تلاحظ أنه اشبه بمصفوفة يوجد بها العديد من القيم محاطة بأقواس المصفوفة أو المتجهة و هي [ , , , , ]

لا حظ الفرق بين أقواس المتجهه "Vector" وهي [ ] و أقواس المجموعة "Set" و هي { } من المثال السابق.

ففي البرنامج السابق تم انشاء الكائن v بإستخدام الفئة Vector و من خلال استخدام جملة for تم إضافة 20 عنصراً بإستخدام المنهج addElement و غني عن القول أنه أحد مناهج الفئة Vector -- الا تلاحظ ارتباطه من خلال النقطة بالكائن "المتغير" v الذي تم إنشاؤه "تعريفه" باستخدام فئة Vector

سنقتبس السطر التالي من البرنامج:

v.addElement(new Integer(i));

منهج addElement سيضيف القيمة الموجودة بين أقواسه الى المصفوفة المتجهة الديناميكية v --- هذه القيمة يجب أن تكون من الأنواع الكائنية "Object Type= Reference Type" و ليس الأنواع الأساسية "Primitive Types" و لذلك اضطررنا لتحويل القيمة i  -- و التي هي أصلاً Primitive type بعد أن عرفناها من خلال int -- الى قيمة كائنية بغستخدام الفئة Integer وهي إحدى الفئات التي يطلق عليها عموماً الفئات المغلفة "Wrapper Classes" --- هذه هي وظيفتها على وجه التحديد هو اعتبار الرقم الصحيح 31 مثلاُ ككائن "reference" و ليس قيمة أولية "primitive"  و لذلك مايبرره --- و ستفهم هذا التبرير عندما ندرس شيئاً اسمه ال functions and  Subroutines  بالإضافة الى المبرر السابق وهو أن قيم الفئة Vector يجب أن تكون reference و ليس primitive

و عموماً ال Wrapper Classes هي ختام هذا الجزء في الدرس القادم مع تعليق ختامي للفرق الدقيق بين primitive types و reference types لإعتقادي ان هذه الأمثلة كافية للتشبع على الأقل بترسيخ المصطلحات في ذهنك كمبرمج.

سؤال منزلي 2:  استبدل هذا السطر في البرنامج السابق "هنا القيمة تعتبر Object or reference"

v.addElement(new Integer(i));

بالسطر التالي "هنا القيمة تعتبر primitive"

v.addElement(i);

بعد Compile سينتج لديك رسالة تنبيه لوجود خطأ. ماهذه الرسالة؟ و لماذا؟

سؤال منزلي 3: ماذا يعني السطر التالي:

Integer(5);

جواب: تحويل القيمة الصحيحة 5 الى قيمة كائنية -- أي تحويل من primitive type الى reference type

--------

انتظر الدرس القادم



 

 

  محمد سفر العتيبي 05-9-2003 16:05 64.  

الدرس الثالث و الأربعون (43)
Variable Types & Kinds
Reference Types 2-4-1: abstract class name:  Wrapper Classes>>>Integer class

Wrapper classes أو الفئات المغلفة هي "اسم مختصر جامع شامل" لعدة فئات. شبه الجملة باللون البنفسجي تترجم الى الانجليزية بكلمة absrtact. لايفوتك أننا كتبنا classes بصيغة الجمع و ليس المفرد class -- لماذا؟ لأنها تحتوي على عدة فئات مختلفة الأسماء فنحن لايوجد لدينا فئة اسمها Wrapper بل يوجد لدينا عدة فئات مثل فئة Integer و فئة Byte و فئة Short و فئة Long و فئة Double و فئة Float و فئة Boolean و فئة Character و هذه الفئات الثمانية جميعاً توضع تحت عنوان واحد لسبب ما  وهذا العنوان هو عنوان درسنا الفرعي اليوم "Wrapper Classes "

لسبب ما ؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟

لأنها أولاً فئات تعتبر "reference types" تقابل الأنواع الأساسية الثمانية "primitive type" وبما انها فئات فهي ستحتوي على مناهج "methods" و بما انها تحتوي على مناهج فنحن نستطيع التعامل مع قيمها من خلال هذه المناهج لأن القيم و من خلال تعريفها من خلال الفئات المغلفة تصبح كائنات و بما أنها كائنات فنحن نستطيع اللعب بها و تطويعها لرغباتنا. و من أمثلة ذلك وجود منهج يحول العدد الصحيح الى عدد ثنائي على سبيل المثال. أيضاً لاتنسوا من درس الأمس أن بعض الفئات الاخرى مثل Vector ترفض التعامل مع القيم الأولية (int مثلاُ) و لاتتجاوب الا مع القيم الكائنية(Integer مثلاُ).

مايلي النوع الأولي باللون الأزرق و بجانبه فئته المقابلة باللون الأزرق الغامق و ذلك كما تظهر لك عند استخدام محرر الجافا JCreator (انظر للصورة التوضيحية ).

Byte : byte

Short : short

Integer : int

Long : long

Float : float

Double : double

Character : char

Boolean : boolean

لاحظ ان الفئات تبدأ بحرف كبير و الأنواع الأولية أو الأساية تبدأ بحرف صغير و بإستثناء int و char فإن بقية الأنواع تكتب وتنطق بنفس الكلمات.

كيفية التعريف

بما انها فئات فالتعريف "إنشاء الكائن" يتم على الطريقة السابقة لإنشاء الكائنات "تعريف متغيراتها" و ذلك على النحو التالي:

Byte b = new Byte(); Short s = new Short(); Integer i = new Integer(); Long x = new Long(); Float y = new Float(); Double d = new Double(); Character c = new Character(); Boolean z = new Boolean();

عملياً درس اليوم انتهى و لكن لن يرسخ شئ من هذه الفئة في الذهن كما ينبغي الا بعد معرفة و ظائف بعض هذه الفئات المغلفة. سنناقش تحت عنوان درس اليوم فئتين فقط من هذه الفئات و هما فئة Character و فئة Integer و ذلك من خلال دراسة بعض مناهجها الجاهزة في مكتبة الجافا و تحديداً في قسم java.lang و هذا القسم لايحتاج ان نكتبه في اعلى البرنامج من خلال امر import لأن الجافا صممت لتدخل لمحتويات هذا القسم من غير امر الاستئذان import -- سنبدأ بالفئة الأخيرة Integer Class في هذا الدرس و في الدرس القادم الفئة الأخرى  Character

Integer class

تقريباً المناهج التالية هي جميع ماتحتويه فئة Integer :::

()doubleValue و ()equals و ()floatValue و ()getInteger و ()hashCode و ()intValue و ()longValue  و ()parseInt و ()toBinaryString و ()toHexString و ()toOctalString  و   ()toString و ()valueOf

سيتم هنا مناقشة اهم هذه المناهج ---- المناهج باللون الأخضر تم مناقشتها في درس سابق إن كنتم لازلتم تتذكرون --- المناهج باللون الأزرق تستخدم لتحويل القيمة الصحيحة الى القيمة المقابلة كما يوحي بذلك اسم المنهج -- البرنامج التالي يوضح الفكرة:

public class ValueExample { public static void main(String[] args) { Integer x = new Integer(99999999); float f=x.floatValue(); double d=x.doubleValue(); int i=x.intValue(); long y=x.longValue(); System.out.println(x); System.out.println(f); System.out.println(d); System.out.println(i); System.out.println(y); } } 99999999 // العدد الأصلي 1.0E8 // float 9.9999999E7 // double 99999999 // int 99999999 // long Press any key to continue...

المناهج باللون الأحمر قد تكون أهم مناهج فئة Integer بل و جميع الفئات في لغة الجافا و ذلك بالنسبة لكثير من طلبة التخصصات الحاسوبية

المنهج ()toBinaryString تستخدم لتحويل الأرقام الصحيحة في النظام العشري الى مكافئها في النظام الثنائي "Binary Numbers " -- يأتينا الجواب على شكل String يتألف من الاصفار 0 و الواحدات 1.

المنهج ()toOctalString   تستخدم لتحويل الأرقام الصحيحة في النظام العشري الى مكافئها في النظام الثماني "Octal  Numbers

" -- يأتينا الجواب على شكل String يتألف من الأشكال من 0 الى 7 بالأضافة

المنهج ()toHexString   تستخدم لتحويل الأرقام الصحيحة في النظام العشري الى مكافئها في النظام الستعشري "HexaDecimal Numbers

" -- يأتينا الجواب على شكل String يتألف من الأشكال من 0 الى 9 بالأضافة الى أول 6 أحرف في الأبجدية و هي A و B و C و D و E و F ---- راجع نظام الأعداد في أي موقع انترنتي أو كتاب مناسب

تخيل لدينا الأعداد الصحيحة 13 و 41 و 88 في النظام العشري المعروف لدينا --- لسبب ما أنا اعرف مقابلها الثنائي و الثماني و الستعشري كمعرفتي بجدول الضرب للأعداد من 1 الى 10 و هي على النحو التالي:

1310 = 11012 = 158 = d16 4110 = 1010012 = 518 = 2916 8810 = 10110002 = 1308 = 5816

المثال التالي يوجد مكافئات العدد العشري 1234 الثلاثة الأخرى --- عليك إثبات الأرقام السابقة من خلال استبدال هذه القيمة بالقيم السابقة في كل مرة.

public class ValueExample { public static void main(String[] args) { int y=1234; Integer x = new Integer(y); String s=x.toBinaryString(y); String d=x.toOctalString(y); String i=x.toHexString(y); System.out.println(x); System.out.println(s); System.out.println(d); System.out.println(i); } } 1234 // عشري 10011010010 // ثنائي 2322 // ثماني 4d2 // ستعشري Press any key to continue...

هل لا حظت كيفية ارتباط العدد الأولي الصحيح y مع العدد الصحيح الكائني x مع المتغير d وهو من نوع String -- فبين قوسي المنهج نضع y و هذا المنهج يجب أن يربط مع الفئة Integer من خلال متغيرها x و ذلك باستخدام النقطة. الان انظر و بتركيز اكثر للبرنامج مرة أخرى.

منهج ()equals تستخدم للمقارنة بين كائنين من نوع Integer

منهج ()parseInt هو أول منهج من فئة Integer درسناه في هذه السلسلة في أحد الدروس السابقة حول كيفية القراءة من الكونسول أو ملف خارجي حيث تنحصر وظيفته في تحويل القيمة من String الى int .

Character class

تمهيد لدرس الغد: تقريباً المناهج التالية هي جميع ماتحتويه فئة Character:

charValue, digit, equals, forDigit, hashCode, isDefined, isDigit, isJavaLetter, isJavaLetterOrDigit, isLetter, isLetterOrDigit, isLowerCase, isSpace, isTitleCase, isUpperCase, toLowerCase, toString, toTitleCase, toUpperCase

و غدأ سنناقش أغلبها حسب الأهمية أو سهولة فهمها.

 



 

 

  محمد سفر العتيبي 28-9-2003 06:43 66.  

الدرس الرابع و الأربعون(44)
Java Keywords: 1

تعتبر حروف اللغة -- أياً كانت اللغة -- مهمة جداً. فهذه الحروف تعتبر الذرات التي تتركب منها الكلمات و الكلمات تؤلف الجمل و عدة جمل تؤلف قطعة نصية. و هذه النصوص ضرورية جداً للتواصل بين البشر. القاموس المنحيط يحتوي على مفردات اللغة العربية. كل مفردة "كلمة" لها معنى خاص يميزها عن غيرها. بعبارة أخرى كل كلمة لها مغزى و هدف يتفق عليه البشر. فمثلاُ كلمة "كتاب" تستقبلها إذان متحدثي اللغة العربية بنفس الفهم و يقفز الى أذهانهم عند ذكر هذه الكلمة شئ محدد وهو "الكتاب".  ماهو تعريف الكتاب؟ ماهو الغرض من الكتاب؟ و إجمالاً هناك مئات الالاف من الكلمات المحجوزة "reserved words" للإستخدام في التحدث باللغة العربية.

في لغة الجافا نفس الشئ فهناك العديد من الكلمات --- ليست كثيرة بالطبع بل تبلغ عدة عشرات --- و هي محجوزة للإستخدام في لغة الجافا لغرض محدد ولايمكن استخدامها من قبل المستخدم لغرض اخر -- فمطوروا لغة الجافا هم من حدد هذه الكلمات و لأي غرض حجزت. "reserved words" لها اسم أخر أشهر وهو "keywords" أو الكلمات الرئيسية في لغة الجافا ولكن هناك فرق دقيق و التفصيل التالي يوضح الأمور أكثر.

reserved تعني محجوز أو محجوزة "للمؤنث" فمثلاُ عندما تحجز مقعداً في قاعة سينما أو تحجز تذكرة طيران أو تحجز موعداً مع طبيب الأسنان --- فإن المرادف لها جميعاً هو Reserved ---- فمثلاُ تذكرة محجوزة resereved ticket و هكذا.

هنا في لغة الجافا يوجد العديد من الكلمات و المحجوزة مسبقاً لتأدية الوظائف الأساسية --- وبما انها محجوزة مسبقاً فلايمكن استخدامها كأسماء متغيرات أو أسماء دوال أو اسماء مناهج والحمدلله تعالى حروف اللغة كثيرة و يمكنك اختيار ملايين الاسماء و لكن احذر أن تقترب من الأسماء أو الكلمات التخصصية للجافا مثل أدوات التعريف الأساسية الثمانية أو أدوات التحكم أو غيرها.

عدد الكلمات المحجوزة للإستخدام في لغة الجافا يربوا على ال 50 كلمة: تحديداً 52 reserved words و هي حسب الترتيب الأبجدي:

من الجدول السابق يطلق على مجموعة الثلاث كلمات باللون الأزرق و هي: null --- true  ----  false   هذا الاسم "assigned values" أو القيم الخاصة  --- أيضاً يطلق عليها الثوابت "constants" فهي مجرد قيم ثابتة كما مر معنا سابقاً

بقية الكلمات و عددها 49 تسمى "keywords" أو الكلمات الرئيسية.

بينما جميعها و كما ذكرنا توضع تحت كلمة "reserved words"

ملخص الكلام السابق:

  1. يوجد هناك 52 كلمة تعتبر Reserved words
  2. و من ضمنها 49 كلمة تعتبر keywords
  3. والثلاث الأخرى تعتبر مجرد قيم و ليست keywords و هي : true -- false -- null
  4. لايمكن استخدامها كأسماء متغيرات "variable"  أو مناهج "methods" أو فئات "class" أي لايمكن استخدامها ك "identifiers"
  5. جميعها هذه الكلمات تتألف من الأحرف الصغيرة مثل: true  و int و for
  6. من لديه إلملم بلغة ++C يجد أن هناك 33 كلمة مشتركة بين الجافا و تلك اللغة.

نصف الكلمات الرئيسية "java keywords" في الجدول السابق يفترض أن الجميع ملم بها بحكم دراستنا لها سابقاً.

درس الغد عبارة عن إطلالة من زاوية أخرى على تلك الكلمات وذلك بإستخدام الخصائص التي تجمع بعضاًً منها تحت خانة واحدة. فمثلاُ هناك أدوات التعريف الرئيسية الثمانية و التي توضع في مجموعة واحدة. سيكون التركيز منصباً على أدوات التحكم --- بينما الجزء الثالث سيكون عبارة عن تمهيد مبسط للأدوات الفئوية "class keywords" و الجزء الرابع أيضاً شرح تمهيدي لما يسمى المعدلات "modifiers" و قد يكون هناك جزء أخير حول بعض التنبيهات.

ولكن علي التنبيه أولاً أن الغرض من هذا الدرس "الدرس 44" هو تمييع بعضاً من الصعوبة التي ستأتي لاحقاً و هو للقراءة السريعة من أجل التمييز بين بعض المصطلحات و ماذا يجب أن يقفز الى ذهنك عند ورود كل مصطلح باللغة الإنجليزية مثل "modifier" أو "" أو "" و ذلك في دروس قادمة.

بإختصار: هذا الدرس يعتبر أدنى الأساسيات لماذا سيأتي.

لاحظ أننا لن نكتب أكواد برمجية لتوضيح الأفكار في هذا الدرس. فهذا ليس الهدف هنا.



ـ ــ أشلاءــ ـو مـ الكلمةـ ـاجاورها

 

  محمد سفر العتيبي 29-9-2003 10:03 67.  

الدرس الرابع و الأربعون(44)
Java Keywords: 2

درس اليوم عبارة عن إطلالة من زاوية أخرى على ال "java keywords" و ذلك بتجميع الكلمات التي تتقاسم خاصية ما تحت بند واحد. هذه الطريقة تعزز فهمنا لتلك الأدوات أكثر و تختصر الكثير من الوقت. الجدول التالي مقتبس من الدرس السابق ولكن كل مجموعة مشتركة تتقاسم نفس اللون:

 

 

تلاحظ أن هناك 5 ألوان و بالتالي 5 أقسام وهي

  1. اللون الأزرق: primitive data types أو ادوات تعريف القيم الرئيسية
  2. اللون الأحمر:Control flow أو أدوات التحكم
  3. اللون البني: class أو الأدوات الفئوية "المتعلقة بالفئة"
  4. اللون الأخضر:modifiers أو المعدلات
  5. اللون الأسود:  Miscellaneous أدوات متنوعة مختلفة لايجمعها قاسم مشترك.

الجدول التالي يضع كل مجموعة في عمود مع تظليل ماسبق دراسته باللون الأصفر

بالنسبة لأدوات التحكم الستة عشر (16) يمكن تجزئتها الى ثلاثة أقسام على النحو التالي

1. أدوات التحكم المختصة بتصيد الأخطاء أو التعامل مع الإستثناءات : Keywords for catch-exception

 2. أدوات التجكم الشهيرة المتعلقة بإتخاذا القرار أو التكرار: Keywords for loops or decision-makers

الجدول التالي يوضح ال keywords المرتبطة بكل قسم:

أيضاً القسم الثاني من أدوات التحكم وهو "loops and decsion-makers"  يمكن وضعها تحت 3 خانات مختلفة وهي:

1. أدوات القفز "jump" و التي تتحكم في التنقل بين أسطر البرنامج

2. أدوات الإختيار "selection"

3. و الأهشر و هي أدوات التكرار "repetion"

الجدول التالي يوضح الأدوات المرتبطة بكل قسم من الأقسام الثلاثة

بالنسبة ل reserved words و التي تعتبر قيم يطلق عليها اصطلاحاُ "constants" أو الثوابت. 

 

الجزء القادم عبارة عن إطلالة أكثر و تقرب من ألأدوات المرتبطة بالفئة "class keywords" والجزء الذي يليه حول المعدلات "modifier keywords" و أغلبها يعتبر العمود الفقري للجزء الثاني و الثالث من هذه السلسلة بالإضافة الى خاتمة هذه الجزء و هي مما يميز لغة الجافا عن غيرها بينما ما سبق شرحه يعتبر غالباً قاسماً مشتركاً بين أكثر من لغة.