درک مفاهیم بلوک و میدان دید در جاوا
تعریف:
در یک کلاس یا یک متد، به کدهایی که بین آکولادها قرار می گیرد، یک بلوک یا قطعه کد گفته می شود.
بعنوان مثال، متد نشان داده شده در عکس 4.1 حاوی دو بلوک کد می باشد. به طوری که یک بلوک در یک بلوک دیگر قرار گرفته است. بنابراین به بلوک اول (که یک بلوک دیگر در داخل آن قرار دارد) بلوک بیرونی گفته می شود. این بلوک دقیقا پس از عنوان متد مورد نظر شروع می شود و سپس در انتهای متد پایان می یابد. به بلوک دوم، که در عکس 4.1 به صورت رنگی نشان داده شده است، بلوک درونی گفته می شود. این بلوک کد، در داخل دومین جفت از آکولادها قرار دارد، و در داخل آن مقداری کد تعریف شده است.
یک بلوک می تواند کاملا در داخل یک بلوک دیگر قرار داشته باشد و یا اینکه کاملا در بیرون از دیگر بلوک ها قرار داشته باشد. اما بلوک ها نمی توانند بر رو هم بیافتند.
(شماره 1: شروع بلوک بیرونی. شماره 2: پایان بلوک بیرونی. شماره 3: شروع بلوک درونی. شماره 4: پایان بلوک درونی)
(شماره 5: تعریف متغیر aNumber. شماره 6: تعریف متغیر anotherNumber. شماره 7: پایان میدان دید متغیر anotherNumber. شماره 8: پایان میدان دید متغیر aNumber)
هنگامی که شما یک متغیر (را در داخل یک بلوک) تعریف می کنید، قادر نیستید تا در بیرون از این بلوک، به این متغیر دسترسی داشته باشید. همان طور که در فصل 3 آموختید، به بخشی از یک برنامه که شما می توانید در آن به یک متغیر دسترسی داشته باشید، میدان دید آن متغیر گفته می شود. میدان دید یک متغیر،تنها در بیرون از بلوکی که در آن تعریف شده است، به پایان می رسد.
در متد ()methodWithNestedBlocks که در عکس 4.1 نشان داده شده است،میدان دید متغیر aNumber تا پایان این متد، تعریف شده می باشد. این یعنی متغیر aNumber هم در بلوک بیرونی و هم در بلوک درونی و در هرجای متد مذکور می تواند مورد استفاده قرار بگیرد.
متغیر anotherNumber در داخل بلوک درونی تعریف شده است، و میدان دید این متغیر در پایان این بلوک درونی، به پایان می رسد، و در خارج از این بلوک، نمی توانیم از آن استفاده کنیم. عکس 4.2 متد عکس 4.1 را نشان می دهد به طوری که از داخل یک متد دیگر مورد فراخوانی قرار گرفته است.
شما نمی توانید که متغیر را که در میدان دید قرار ندارد، مورد استفاده قرار دهید. بعنوان مثال، در عکس 4.3 یک متد نشان داده شده است که حاوی دو بلوک می باشد. در این عکس، مکان هایی که رنگی شده اند، دستورات نامعتبری هستند. همان طور که مشاهده می کنید، آکولادهای باز و بسته، به طور عمودی با یکدیگر تراز شده اند. شما مجبور نیستید آکولادهای باز و بسته ی یک بلوک را به طور عمودی با یکدیگر تراز کنید. اما با انجام این کار، خوانایی کدهای شما افزایش پیدا خواهد نمود.
(شماره 1 و شماره 2: این کار را انجام ندهید زیرا این متغیر هنوز تعریف نشده است. شماره 3: این کار را انجام ندهید، زیرا این متغیر هنوز تعریف نشده است. شماره 4 و شماره 5: این کار را انجام ندهید زیرا این متغیر در خارج از میدان دید قرار دارد.)
در تصویر بالا، در ابتدای اولین بلوک بیرونی، عبارت aNumber = 75 نامعتبر است زیرا متغیر aNumber هنوز تعریف نشده است. به طور مشابه، دستوراتی که در تصویر بالا می خواهند مقدار 489 و 165 را در متغیر anotherNumber ذخیره کنند، نامعتبر هستند، زیرا متغیر anotherNumber هنوز تعریف نشده است. پس از اینکه متغیر anotherNumber تعریف شد، می تواند در اواخر بلوک درونی مورد استفاده قرار گیرد. اما دستوری که می خواهد مقدار 34 را به متغیر anotherNumber انتساب دهد خارج از بلوکی است که متغیر anotherNumber در آن تعریف شده است. آخرین دستور رنگی شده در عکس 4.3، یعنی دستور aNumber = 29 نیز کار نمی کند زیرا خارج از بلوکی است که متغیر aNumber در آن تعریف شده است. این دستور در بیرون از متد ()methodWithInvalidStatements قرار دارد.
شما می توانید در داخل یک متد، یک متغیر با یک نام مشابه را، چندین بار تعریف کنید. این کار را زمانی می توانید انجام دهید که هر یک از این تعریف ها در داخل بلوک خودش قرار داشته باشد و این بلوک ها با یکدیگر تداخل نداشته باشند.
بعنوان مثال به عکس 4.4 دقت کنید. همان طور که مشاهده می کنید، دو متغیر با نام someVar تعریف شده اند و معتبر هستند. زیرا هر یک از آنها در داخل بلوک مخصوص به خود قرار دارند. و قبل از اینکه دومین متغیر به میدان دید وارد شود، اولین متغیر یعنی اولین someVar از میدان دید خارج می شود.
شما نمی توانید در داخل یک بلوک، بیش از یک متغیر با یک نام یکسان تعریف کنید. حتی اگر این بلوک، حاوی بلوک های دیگری باشد. اگر یک متغیر را در داخل یک بلوک بیش از یک بار تعریف کنید، انگار که این متغیر را دوباره تعریف کرده اید. (و یک عمل غیرقانونی انجام داده اید). بعنوان مثال، در عکس 4.5 در جایی که برای دومین بار متغیر aValue را تعریف کرده ایم، یک خطا ایجاد خواهد شد، زیرا شما نمی توانید یک متغیر را در داخل یک بلوک (یعنی بلوک بیرونی متد ) دو بار تعریف کنید. به همین دلیل، سومین تعریف متغیر aValue نیز نامعتبر است، حتی اگر در داخل یک بلوک جدید باشد. بلوکی که حاوی سومین تعریف aValue است، کاملا در داخل بلوک بیرونی قرار دارد، بنابراین اولین تعریف aValue از میدان دید خارج نمی شود. (بنابراین تعریف آن نامعتبر است).
با اینکه شما نمی توانید در داخل یک بلوک، یک متغیر را دو بار تعریف کنید، اما قادر هستید تا یک متغیر را در داخل یک متد از یک کلاس تعریف کنید و سپس آن را در یک متد دیگر از همان کلاس نیز تعریف کنید. در اینجا، هر یک از این متغیرها، در یک موقعیت جداگانه در حافظه ذخیره می شوند. و با یکدیگر متفاوت هستند( و تنها نام آنها یکسان است). به این متغیرها، متغیرهای محلی گفته می شود.
بعنوان مثال، به کلاس درون عکس 4.6 توجه کنید.
همان طور که مشاهده می کنید، در داخل متد ()main از کلاس OverridingVariable، یک متغیر به نام aNumber تعریف شده است و برابر با مقدار 10 قرار گرفته است.
وقتی که در داخل متد ()main متد ()firstMethod فراخوانی می شود، یک متغیر جدید با همین نام(یعنی aNumber ) تعریف می شود اما آدرس آن در حافظه با متغیر قبلی متفاوت است و مقداری که به آن انتساب داده ایم نیز متفاوت است. این متغیر جدید، تنها در داخل متد ()firstMethod تعریف شده است و برابر با مقدار 77 قرار گرفته است.
پس از اینکه متد ()firstMethod اجرا می شود، و دوباره به داخل متد ()main برمی گردیم، در خط کد بعدی، مقدار aNumber اصلی(که در خود متد ()main تعریف شده بود) در خروجی نشان داده خواهد شد. سپس مقدار این متغیر(یعنی 10) بعنوان آرگومان به متد ()secondMethod داده می شود و در داخل پارامتر int aNumber کپی می شود.
نام این پارامتر، با نام متغیر اصلی aNumber (در داخل متد ()main) یکسان است اما با یکدیگر متفاوت هستند، زیرا آدرس آنها در حافظه با یکدیگر متفاوت می باشد.
بنابراین وقتی که در داخل متد ()secondMethod متغیر aNumber برابر با مقدار 862 قرار می گیرد، بر روی متغیر aNumber اصلی در داخل متد ()main هیچ تاثیری نمی گذارد.
پس وقتی که متد ()secondMethod اجرا شد و دوباره به متد ()main برگشتیم، در خط بعدی کدها، دوباره همان مقدار اصلی متغیر aNumber چاپ خواهد شد. نتیجه ی کدهای تصویر 4.6 در تصویر 4.7 نشان داده شده است.
مجموعه نکات:
نکته: در برنامه نویسی شیء گرا یک اصطلاح به نام override(بازنویسی) وجود دارد که برنامه نویسان از آن استفاده می کنند. از این اصطلاح زمانی استفاده می شود که یک کلاس فرزند( child class) حاوی یک متغیر یا یک متد باشد و کلاس والد(parent class) آن نیز همان متغیر یا متد را با همان نام در داخل خود داشته باشد.
در فصول بعدی با این مفاهیم به خوبی آشنا خواهید شد.
نکته: فرض کنید که در خانه ی شما فردی به نام احسان وجود داشته باشد. و نام پسر همسایه ی شما نیز احسان باشد. حالا وقتی که خانواده ی شما در مورد فردی به نام احسان صحبت می کنند، منظور آنها احسان پسر همسایه نیست بلکه منظور آنها همان احسان در خانه ی خودشان است(متغیر محلی). متغیرهای محلی نیز همین طور استنباط می شوند. حالا اگر خانواده ی شما بخواهند به احسان پسر همسایه اشاره کنند، باید نام همسایه را نیز ذکر کنند. (متغیرهای غیرمحلی).
نکته مهم:
اگر یک متغیر محلی یا یک پارامتر که در داخل یک متد قرار دارد، با یک متغیر کلاس، نام یکسانی داشته باشد، در داخل بلوک متد، متغیر کلاس نادیده گرفته می شود. به این روش در جاوا shadowing گفته می شود.
بنابراین وقتی که یک متغیر کلاس داشته باشیم، و در داخل یک متد از همان کلاس، یک متغیر با همان نام تعریف کنیم، می گوییم متغیری که در داخل متد قرار دارد، بر روی متغیر کلاس بازنویسی(رونویسی) می شود. یا به عبارت فنی تر، می گوییم می گوییم متغیر داخل متد، بر روی متغیر کلاس override می شود.
در عکس 4.8 یک کلاس به نام Employee مشاهده می کنید که حاوی دو متغیر نمونه(instance variable) است. همچنین دو متد void نیز در داخل آن قرار دارند.
همان طور که مشاهده می کنید، متد ()setValues مقادیر متغیرهای کلاس که دو عدد هستند را تنظیم می کند.
حالا اگر از کلاس Employee یک شیء ایجاد کنیم و سپس متد ()methodThatUsesInstanceAttributes را فراخوانی کنیم، از مقادیر متغیرهای empNum و empPayRate استفاده می شود و در خروجی چاپ می شوند.
اما وقتی که متد ()methodThatUsesLocalVariables را فراخوانی کنیم(صدا بزنیم) مقادیر دو متغیر محلی تعریف شده در آن، یعنی 33333 و 555.55 بر روی متغیرهای نمونه بازنویسی(override) می شوند.
در عکس 4.9 از کلاس Employee یک شیء ایجاد کرده ایم و سپس تمام متدهای آن را مورد استفاده قرار داده ایم. عکس 4.10 خروجی را نشان می دهد.
(تصویر 4.8 کلاس Employee )
(شماره 1: این متد از متغیرهای کلاس، استفاده می کند. شماره 2: این متد هم از متغیرهای کلاس استفاده می کند. شماره 3: این متد از متغیرهای محلی تعریف شده در آن استفاده می کند که نامی مشابه با نام متغیرهای کلاس، دارند.)
(تصویر 4.9 اپلیکیشن TestEmployeeMethods)
(تصویر 4.10 خروجی اپلیکیشن TestEmployeeMethods)
هنگامی که دارید برنامه ای می نویسید، ممکن است بخواهید ازانجام کارهای گیج کننده اجتناب کنید. یعنی ممکن است بخواهید از دادن یک نام مشابه به یک متغیر نمونه و یک متغیر محلی درون یک متد اجتناب کنید. اما اگر تصمیم گرفتید که برای موارد مذکور نام مشابهی تعریف کنید، به یاد داشته باشید که متغیر محلی تعریف شده در آن متد، بر روی متغیر نمونه، رونویسی(override) خواهد شد.
نکته:
برنامه نویسان معمولا برای یک متغیر نمونه و یک پارامتر که در داخل یک متد از همان کلاس قرار دارد، نام مشابهی تعریف می کنند. بنابراین اگر بخواهند در داخل آن متد، متغیر نمونه را صدا بزنند، از کلمه ی کلیدی this استفاده می کنند. بعدا در این فصل، در مورد کلمه ی کلیدی this بحث خواهیم نمود.
اینکه تاثیر بلوک ها و متدها بر روی متغیرها را درک کنید، بسیار اهمیت دارد.
متغیرهای درون متد و متغیرهای عضوی، هنگامی که تعریف شوند، در مکان های متفاوتی از حافظه قرار می گیرند. پس از اینکه شما مفهوم میدان دید متغیرها را فراگرفتید، قادر خواهید بود تا از خطاهای بسیاری در برنامه های خود جلوگیری کنید.
- نوشته شده توسط احسان عباسی
- بازدید: 4452