در يك برنامه جاوا ، متغير ، اساسي ترين واحد ذخيره سازي است . يك متغير به وسيله تركيبي از يك شناسه ، يك نوع و يك مقدار ده اوليه اختياري تعريف خواهد شد . علاوه بر اين ، كليه متغيرها داراي يك قلمرو هستند كه رويت پذيري آنها را تعريف مي كند و يك زمان حيات نيز دارند. متعاقبا" اين اجزائ را مورد بررسي قرار مي دهيم .

اعلان يك متغير Declaring a variable
در جاوا كليه متغيرها قبل از استفاده بايد اعلان شوند . شكل اصلي اعلان متغير بقرار زير مي باشد
کد:
  : type identifier [=value] [/identifier[=value]...];
مقدار شناسه مقدار شناسه نوع
نوع (type) يكي از انواع اتمي جاوا يا نام يك كلاس يا رابط است . ( انواع كلاس و رابط بعدا" بررسي خواهد شد . ) شناسه نام متغير است . مي توانيد با گذاشتن يك علامت تساوي و يك مقدار ، متغير را مقدار دهي اوليه نماييد . در ذهن بسپاريد كه عبارت مقدار دهي اوليه بايد منتج به يك مقدار از همان نوعي ( يا سازگار با آن نوع ) كه براي متغير مشخص شده ، گردد . براي اعلان بيش از يك نوع مشخص شده ، از فهرست كاماهاي (') جدا كننده استفاده نماييد . در زير مثالهايي از اعلان متغير از انواع گوناگون را مشاهده مي كنيد . دقت كنيد كه برخي از آنها شامل يك مقدار دهي اوليه هستند .

Code:
کد:
+ int a/ b/ c; // declares three  ints/ a/ b/ and c. 
+ int d = 3/ e/ f = 5; // declares three more ints/  initializing 
+ // d and f. 
+ byte z = 22; // initializes z. 
+ double  pi = 3.14159; // declares an approximation of pi. 
+ char x = 'x'; // the  variable x has the value 'x'.
شناسه هايي كه انتخاب مي كنيد هيچ عامل ذاتي در نام خود ندارند كه نوع آنها را مشخص نمايد . بسياري از خوانندگان بياد مي آورند زماني را كه FORTRAN كليه شناسه هاي از Iتا Nا را پيش تعريف نمود تا از نوع INTEGER باشند ، در حاليكه ساير شناسه ها از نوع REAL بودند . جاوا به هر يك از شناسه هاي متناسب شكل گرفته امكان اختيار هر نوع اعلان شده را داده است .

مقدار دهي اوليه پويا Dynamic intialization
اگر چه مثالهاي قبلي از ثابت ها بعنوان مقدار ده اوليه استفاده كرده اند اما جاوا امكان مقداردهي اوليه بصورت پويا را نيز فراهم آورده است . اين موضوع با استفاده از هر عبارتي كه در زمان اعلان متغير باشد ، انجام مي گيرد . بعنوان مثال ، در زير برنامه كوتاهي را مشاهده مي كنيد كه طول ضلع يك مثلث قائم الزاويه را با داشتن طول دو ضلع مقابل محاسبه مي كند :

Code:
کد:
+ // Demonstrate dynamic  initialization. 
+ class DynInit { 
+ public static void main(String  args[] ){ 
+ double a = 3.0/ b = 4.0; 
+ // c is dynamically initialized  
+ double c = Math.sqrt(a * a + b * b); 
+ 
+  System.out.println("Hypotenuse is " + c); 
+ } 
+  }
در اينجا سه متغير محلي a، b، c، اعلان شده اند . دو تاي اولي توسط ثابت ها مقدار دهي اوليه شده اند . اما متغير C بصورت پويا و بر حسب طول اضلاع مثلث قائم الزاويه ( بنابر قانون فيثاغورث ) مقدار دهي اوليه مي شود . اين برنامه از يكي از روشهاي توكار جاوا يعني ()sqrt كه عضوي از كلاس Math بوده و ريشه دوم آرگومانهاي خود را محاسبه ميكند استفاده كرده است . نكته كليدي اينجا
است كه عبارت مقدار دهي اوليه ممكن است از هر يك از اجزائ معتبر در زمان مقدار دهي اوليه ، شامل فراخواني روشها ، ساير متغيرها يا الفاظ استفاده نمايد.

قلمرو زمان حيات متغيرها
تابحال كليه متغيرهاي استفاده شده ، در زمان شروع روش ()main اعلان مي شدند. اما جاوا همچنين به متغيرها امكان مي دهد تا درون يك بلوك نيز اعلام شوند. همانطوريكه قبلا" توضيح داديم ، يك بلوك با يك ابرو باز و يك ابرو بسته محصور مي شود: يك بلوك تعريف كننده يك قلمرو است . بدين ترتيب هر بار كه يك بلوك جديد را شروع ميكنيد ، يك قلمرو جديد نيز بوجود مي آوريد . مانطوريكه احتمالا" از تجربيات برنامه نويسي قبلي بياد داريد ، يك قلمرو (scope) تعيين كننده آن است كه چه اشيائي براي ساير بخشهاي برنامه قابل رويت هستند . اين قلمرو همچنين زمان حيات (lifetime) آن اشيائ را تعيين مي كند . اكثر زبانهاي كامپيوتري دو طبقه بندي از قلمروها را تعريف مي كنند : سراسري (global) و محلي (local) . اما اين قلمروهاي سنتي بخوبي با مدل موكد شي ئ گرايي جاوا مطابقت ندارند . اگر چه در جاوا هم مي توان مقاديري را بعنوان قلمرو
سراسري ايجاد نمود ، اما اين فقط يك نوع استثنائ است و عموميت ندارد . در جاوا قلمرو اصلي همانهايي هستند كه توسط يك كلاس يا يك روش تعريف مي شوند . حتي همين تمايز نيز تا حدي ساختگي و مصنوعي است . اما از آنجاييكه قلمرو كلاس داراي مشخصات و خصلتهاي منحصر بفردي است كه قابل استفاده در قلمرو تعريف شده توسط روش نيست ، اين تمايز تا حدي محسوس خواهد بود . بخاطر تفاوتهاي موجود ، بحث قلمرو كلاس ( و متغيرهاي اعلان شده داخل آن ) اين مبحث بتعوق افتاده است . در حال حاضر فقط قلمروهاي تعريف شده توسط يك روش يا داخل يك روش را بررسي مي كنيم .
قلمرو تعريف شده توسط يك روش با يك ابروي باز شروع مي شود. اما اگر آن روش داراي پارامترهايي باشد ، آنها نيز داخل قلمرو روش گنجانده خواهند شد . بعدا" نگاه دقيقتري به پارامترها خواهيم داشت و فعلا" كافي است بدانيم كه پارامترها مشابه هر متغير ديگري در يك روش كار مي كنند .
بعنوان يك قانون عمومي ، متغيرهاي اعلان شده داخل يك قلمرو براي كدهايي كه خارج از قلمرو تعريف مي شوند ، قابل رويت نخواهند بود ( قابل دسترسي نيستند ). بدين ترتيب ، هنگاميكه يك متغير را درون يك قلمرو اعلان مي كنيد ، در حقيقت آن متغير را محلي دانسته و آن را در مقابل دستيابيها و تغييرات غير مجاز محافظت مي كنيد . در حقيقت ، قوانين قلمرو اساس كپسول سازي را فراهم مي كنند . قلمروها را مي توان بصورت تودرتو (nesting) محفوظ داشت . بعنوان مثال ، هر زمان يك بلوك كد ايجاد كنيد ، يك قلمرو جديد تودرتو ايجاد نموده ايد . هنگاميكه اين واقعه روي مي دهد ، قلمرو بيروني ، قلمرو دروني را دربرمي گيرد . اين بدان معني است كه اشيائ اعلان شده در قلمرو بيروني براي كدهاي داخل قلمرو دروني قابل رويت هستند اما عكس اين قضيه صادق نيست . اشيائاعلان شده داخل قلمرو دروني براي بيرون قلمرو قابل رويت نخواهند بود .
براي درك تاثير قلمروهاي تودرتو ، برناه ريز را در نظر بگيريد :

Code:
کد:
+ // Demonstrate block scope. 
+  class Scope { 
+ public static void main(String args[] ){ 
+ int x; //  known to all code within main 
+ 
+ x = 10; 
+ if(x == 10 ){ // start  new scope 
+ int y = 20; // known only to this bock 
+ 
+ // x and y  both known here. 
+ System.out.println("x and y :" + x + " " + y); 
+ x =  y * 2; 
+ } 
+ // y = 100 :// Error! y not known here 
+ 
+ // x is  still known here. 
+ System.out.println("x is " + x); 
+ } 
+  }
همانطوريكه توضيحات نشان مي دهند ، متغير x در ابتداي قلمروي ()main اعلان شده و براي كليه كدهاي متعاقب داخل ()main قابل دسترسي مي باشد . داخل بلوك if متغير y اعلان شده است . از آنجاييكه يك بلوك معرف يك قلمرو است ، y فقط براي ساير كدهاي داخل بلوك خود قابل رويت است . اين دليل آن است كه خارج بلوك مربوطه ، خط y=100 در خارج توضيح داده شده است . اگر نشانه توضيح راهنمايي را تغيير مكان دهيد ، يك خطاي زمان كامپايل (compile-time error) اتفاق مي افتد چون y براي بيرون از بلوك خود قابل رويت نيست . داخل بلوك if متغير x قابل استفاده است زيرا كدهاي داخل يك بلوك ( منظور يك قلمرو تودرتو شده است ) به متغيرهاي اعلان شده در يك قلمرو دربرگيرنده دسترسي دارند .
داخل يك بلوك ، در هر لحظه اي مي توان متغيرها را اعلان نمود ، اما فقط زماني
معتبر مي شوند كه اعلان شده باشند . بدين ترتيب اگر يك متغير را در ابتداي يك
روش اعلان مي كنيد، براي كليه كدهاي داخل آن روش قابل دسترس خواهد بود. بالعكس اگر يك متغير را در انتهاي يك بلوك اعلان كنيد ، هيچ فايده اي ندارد چون هيچيك از كدها به آن دسترسي ندارند . بعنوان مثال اين قطعه از برنامه غير معتبر است چون نمي توان از count قبل از اعلان آن استفاده نمود :

Code:
کد:
+ // This fragment is wrong! 
+  count = 100; // oops! cannot use count before it is declared! 
+ int  count;
يك نكته مهم ديگر در اينجا وجود دارد كه بايد بخاطر بسپاريد: متغيرها زماني
ايجاد مي شوند كه قلمرو آن ها وارد شده باشد ، و زماني خراب مي شوند كه قلمرو آنها ترك شده باشد . يعني يك متغير هربار كه خارج از قلمروش برود ، ديگر مقدار خود را نگهداري نخواهد كرد . بنابراين ، متغيرهاي اعلان شده داخل يك روش مقادير خود را بين فراخواني هاي آن روش نگهداري نمي كنند . همچنين يك متغير اعلان شده داخل يك بلوك ، وقتي كه بلوك ترك شده باشد ، مقدار خود را از دست خواهد داد .
بنابراين ، زمان حيات (lifetime) يك متغير محدود به قلمرو آن مي باشد . اگر اعلان يك متغير شامل مقدار دهي اوليه آن باشد ، آنگاه هر زمان كه به بلوك مربوطه وارد شويم ، آن متغير مجددا" مقدار دهي اوليه خواهد شد . بعنوان مثال برنامه زير را در نظر بگيريد :

Code:
کد:
+ // Demonstrate lifetime of a  variable. 
+ class LifeTime { 
+ public static void main(String args[] ){  
+ int x; 
+ 
+ for(x = 0; x < 3; x++ ){ 
+ int y =- 1; // y is  initialized each time block is entered 
+ System.out.println("y is :" + y);  // this always prints- 1 
+ y = 100; 
+ System.out.println("y is now :" +  y); 
+ } 
+ } 
+ }
خروجي توليد شده توسط اين برنامه بقرار زير است :


همانطوريكه مشاهده مي كنيد ، هر بار كه به حلقه for داخلي وارد مي شويم ، y همواره بطور مكرر مقدار اوليه 1- را اختيار مي كند . اگر چه بلافاصله به اين
متغير مقدار 100 نسبت داده مي شود، اما هر بار نيز مقدار خود را از دست ميدهد. و بالاخره آخرين نكته : اگر چه ميتوان بلوكها را تودرتو نمود، اما نميتوانيد
متغيري را اعلان كنيد كه اسم آن مشابه اسم متغيري در قلمرو بيروني باشد. از اين نظر جاوا با زبانهاي Cو C++و متفاوت است . در زير مثالي را مشاهده مي كنيد كه در آن تلاش شده تا دو متغير جدا از هم با اسم اعلان شوند . در جاوا اينكار مجاز نيست . در Cو C++و اين امر مجاز بوده و دو bar كاملا" جدا خواهند ماند .

Code:
کد:
+ // This program will not compile  
+ class ScopeErr { 
+ public static void main(String args[] ){ 
+ int  bar = 1; 
+ { // creates a new scope 
+ int bar = 2; // Compile-time error  -- bar already defined! 
+ } 
+ } 
+ }
تبديل خودكار و تبديل غير خودكار انواع
اگر تجربه قبلي برنامه نويسي داشته ايد ، پس مي دانيد كه كاملا" طبيعي است كه مقداري از يك نوع را به متغيري از نوع ديگر نسبت دهيم . اگر اين دو نوع سازگار باشند ، آنگاه جاوا بطور خودكار اين تبديل (conversion) را انجام مي دهد . بعنوان مثال ، همواره امكان دارد كه مقدار int را به يك متغير long نسبت داد . اما همه انواع با يكديگر سازگاري ندارند ، بنابراين هر گونه تبديل انواع مجاز
نخواهد بود . بعنوان نمونه ، هيچ تبديلي از doubleبه byte تعريف نشده است . خوشبختانه ، امكان انجام تبديلات بين انواع غير سازگار هم وجود دارد . براي انجام اينكار ، بايد از تبديل cast استفاده كنيد كه امكان يك تبديل صريح بين انواع غير سازگار را بوجود مي آورد . اجازه دهيد تا نگاه دقيقتري به تبديل خودكار انواع و تبديل cast داشته باشيم .

تبديل خودكار در جاوا Java's Automatic conyersions
هنگاميكه يك نوع داده به يك متغير از نوع ديگر نسبت داده مي شود ، اگر دو شرط زير فراهم باشد ، يك تبديل خودكار نوع انجام خواهد شد :
1.دو نوع با يكديگر سازگار باشند .
2.نوع مقصد بزرگتر از نوع منبع باشد .
هنگاميكه اين دو شرط برقرار باشد ، يك تبديل پهن كننده (widening) اتفاق مي افتد . براي مثال نوع int همواره باندازه كافي بزرگ است تا كليه مقادير معتبر byte را دربرگيرد، بنابراين نيازي به دستور صريح تبديل cast وجود ندارد. در تبديلات پهن كننده ، انواع رقمي شامل انواع عدد صحيح و عدد اعشاري با هر يك از انواع سازگاري دارند . اما انواع رقمي با انواع charو booleanو سازگار نيستند . همچنين انواع charو booleanو با يكديگر سازگار نيستند . همانطوريكه قبلا" ذكر شد ، جاوا هنگام ذخيره سازي يك ثابت عدد صحيح لفظي (Literal integer constant) به متغيرهاي از انواع byte، short،و longو ، يك تبديل خودكار نوع را انجام مي دهد .

تبديل غير خودكار انواع ناسازگار
اگر چه تبديلات خودكار انواع بسيار سودمند هستند ، اما جوابگوي همه نيازها نيستند . بعنوان مثال ، ممكن است بخواهيد يك مقدار int را به يك متغير byte نسبت دهيد. اين تبديل بطور خودكار انجام نمي گيرد، زيرا يك byteاز intز كوچكتر است .اين نوع خاص از تبديلات را گاهي تبديل باريك كننده (narrowing conversions) مي نامند ، زيرا بطور صريح مقدار را آنقدر باريك تر و كم عرض تر مي كنيد تا با نوع هدف سازگاري يابد .
براي ايجاد يك تبديل بين دو نوع ناسازگار ، بايد از cast استفاده نماييد . cast
يك تبديل نوع كاملا" صريح است . شكل عمومي آن بقرار زير مي باشد : ( target - type )value

نوع نوع مقصد يا هدف
در اينجا نوع هدف ، همان نوعي است كه مايليم مقدار مشخص شده را به آن تبديل كنيم . بعنوان مثال ، قطعه زير از يك برنامه تبديل غير خودكار از intبه byte
را اجرا مي كند . اگر مقدار integer بزرگتر از دامنه يك byte باشد ، اين مقدار به مدول ( باقيمانده تقسيم يك integer بر دامنه ) byte كاهش خواهد يافت .

Code:
کد:
+ int a; 
+ byte b; 
+ //...  
+ b =( byte )a;
هر گاه كه يك مقدار اعشاري به يك عدد صحيح نسبت داده شود ، شكل ديگري از تبديل اتفاق مي افتد : بريدن ، truncation . همانطوريكه مي دانيد ، اعداد صحيح داراي قسمت اعشاري نيستند . بنابراين هنگاميكه يك مقدار اعشاري به يك نوع عدد صحيح نسبت داده مي شود ، جزئ اعشاري از بين خواهد رفت ( بريده خواهد شد ) .
بعنوان مثال ، اگر مقدار 1.23 را به يك عدد صحيح نسبت دهيم ، مقدار حاصله فقط عدد 1 مي باشد . مقدار 0.23 بريده (truncated) خواهد شد . البته اگر اندازه اجزائ عدد كلي آنچنان بزرگ باشد كه در نوع عدد صحيح مقصد نگنجد ، آنگاه مقدار فوق به مدول دامنه نوع هدف كاهش خواهد يافت .
برنامه زير نشان دهنده برخي از تبديلات انواع است كه مستلزم تبديل cast
مي باشند :

Code:
کد:
+ // Demonstrate casts. 
+ class  Conversion { 
+ public static void main(String args[] ){ 
+ bytt b; 
+  int i = 257; 
+ double d = 323.142; 
+ 
+  System.out.println("\nConversion of int to byte."); 
+ b =( byte )i; 
+  System.out.println("i and b " + i + " " + b); 
+ 
+  System.out.println("\nConversion of double to int."); 
+ i =( int )d; 
+  System.out.println("d and i " + d + " " + i); 
+ 
+  System.out.println("\nConversion of double to byte."); 
+ b =( byte )d; 
+  System.out/println("d and b " + d + " " + b); 
+ } 
+  }
خروجي اين برنامه بقرار زير مي باشد :

Conversion of int to byte.
i and b 257 1

Conversion of double to int.
d and i 323.142 323

Conversion of double to byte.
d and b 323.142 67

به نقل از irandevelopers