تاریخ امروز:30 فروردین 1403

درس 2 : قلمرو زمان حیات متغیرها

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

بقیش تو ادامه ی مطلب

// 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 eror) اتفاق میافتد چون y برای بیرون از بلوک خود قابل رویت نیست . داخل بلوک if متغیر x قابل استفاده است زیرا کدهای داخل یک بلوک ( منظور یک قلمرو تودرتو شده است ) به متغیرهای اعلان شده در یک قلمرو دربرگیرنده دسترسی دارند . داخل یک بلوک ، در هر لحظه ای می توان متغیرها را اعلان نمود ، اما فقط زمانی معتبر می شوند که اعلان شده باشند . بدین ترتیب اگر یک متغیر را در ابتدای یک روش اعلان می کنید، برای کلیه کدهای داخل آن روش قابل دسترس خواهد بود. بالعکس اگر یک متغیر را در انتهای یک بلوک اعلان کنید ، هیچ فایده ای ندارد چون هیچیک از کدها به آن دسترسی ندارند . بعنوان مثال این قطعه از برنامه غیر معتبر است چون نمی توان از count قبل از اعلان آن استفاده نمود :

// This fragment is wrong!
count = 100; // oops! cannot use count before it is declared!
int count;

یک نکته مهم دیگر در اینجا وجود دارد که باید بخاطر بسپارید: متغیرها زمانی ایجاد می شوند که قلمرو آن ها وارد شده باشد ، و زمانی خراب می شوند که قلمرو آنها ترک شده باشد . یعنی یک متغیر هربار که خارج از قلمروش برود ، دیگر مقدار خود را نگهداری نخواهد کرد . بنابراین ، متغیرهای اعلان شده داخل یک روش مقادیر خود را بین فراخوانی های آن روش نگهداری نمی کنند . همچنین یک متغیر اعلان شده داخل یک بلوک ، وقتی که بلوک ترک شده باشد ، مقدار خود را از دست خواهد داد . بنابراین ، زمان حیات (lifetime) یک متغیر محدود به قلمرو آن می باشد . اگر اعلان یک متغیر شامل مقدار دهی اولیه آن باشد ، آنگاه هر زمان که به بلوک مربوطه واردشویم ، آن متغیر مجددا” مقدار دهی اولیه خواهد شد . بعنوان مثال برنامه زیر را در نظر بگیرید :

// 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);
}
}
}

خروجی تولید شده توسط این برنامه بقرار زیر است :

y is- :1
y is now:100
y is- :1
y is now:100
y is- :1
y is now:100

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

// 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 استفاده کنید که امکان یک تبدیل صریح بین انواع غیر سازگار را بوجود می آورد . در درس 3 نگاه دقیق تری به این نوع تبدیل خواهیم داشت.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *