آموزش برنامه نویسی جاوا (بخش بیستم: سازنده و مخرب در جاوا)

استاندارد

سازنده یا Constructor

در هنگام ساخت یک شی از یک نمونه کلاس، می توان متغیر های یک شی را مقداردهی اولیه کرد.

تابع سازنده (Constructor) تابعی است که در حین نمونه گرفتن از یک کلاس یک مرتبه اجرا می شود. زیرا بسیار ساده تر و دقیق تر آن است که کلیه تنظیمات در زمان ایجاد اولیه شی انجام شود.

از این تابع بیشتر برای مقداردهی کردن متغییر ها و فیلدهای یک کلاس در هنگام ساخت یک شی، استفاده می شود.

معمولا بعضی از اعضای کلاس قبل از استفاده نیاز به مقداردهی دارندکه همان طور که گفته شد، اين عمل توسط سازنده (constractor) انجام می گیرد که به شیء اين امکان را می دهد که هنگام ايجاد مقداردهی شود.

سازنده تابعی است هم اسم کلاس که وقتی یک نمونه از کلاس گرفته می شود اتوماتیک فراخوانی می شود.

سازنده نام همان کلاسی را که در آن قرار گرفته اختیار نموده و از نظر صرف و نحو مشابه یک روش است.

وقتی یکبار سازنده ای را تعریف نمایید، بطور خودکار بلافاصله پس از ایجاد یک شی و قبل از اینکه عملگر new تکمیل شود، فراخوانی خواهد شد.

سازندگان کمی بنظر عجیب می آیند زیرا فاقد نوع برگشتی و حتی فاقد void هستند.

در زبان های شی گرا مثل سی شارپ و جاوا چون همه چیز بر پایه شی گرایی و کلاس هست شما وقتی یک کلاس می سازید میتونید با استفاده از سازنده ها متغیر ها رو مقدار دهی کنید.

وقتی شما یکی شی از کلاس مورد نظرتون می سازین(new می کنید!) کامپایلر به سراغ سازنده ی شما می رود که اگه نباشه سازنده ی پیش فرض فراخونی میشه که بدون پارامتره و شما میتونید از سازنده استفاده کرده و اونطوری که دلتون می خواد متغیر هاتون رو مقدار دهی کنید و از همون اول برای شی ساخته شدتون بفرستید .

تابع سازنده می تواند دارای پارامتر باشد بنابراين زمان ايجاد شیء می توان به متغيرهای عضو مقادير اوليه داد. برای ارسال آرگومان به تابع سازنده بايد هنگام تعريف شیء مقدار آرگومان بعد از نام شیء درون پرانتز قرار گيرد.

یک کلاس می تواند دارای چند سازنده با پارامترهای مختلف باشد. بهتر است همیشه حداقل یک سازنده حتی اگر خالی باشد ساخته شود.

برای تابع سازنده مقدار برگشتی ذکر نمی شود (حتی Void).

برای درک بیشتر به مثال زیر توجه نمایید:

public class JavaApplication1 {

static class myClass{
    private int a;
    private char b;
// تابع سازنده
    myClass(){
    this.a=1; // مقدار دهی به متغیر در تابع سازنده
    this.b='a'; // مقدار دهی به متغیر در تابع سازنده
    }
}    
    public static void main(String[] args) {
        myClass newObject = new myClass(); // ایجاد شی
        System.out.print(newObject.a);
        System.out.print(newObject.b);
    } 
}

خروجی کد بالا، 1a می باشد. زیرا شی به هنگام ساخت توسط سازنده ی خودش مقدار دهی می شود.

همچنین سازنده می تواند مقادیری را نیز به صورت پارامتر ورودی در هنگام ساخت شی ، از شی بگیرد.

برای این کار کافیست، در تابع سازنده، پارامتر ورودی در داخل پرانتز، بنویسیم. سپس در هنگام ساخت شی، مقادیر ورودی به آن پارامتر ها را بدهیم تا سازنده بتواند مقدار دهی متغیرهای شی را انجام دهد.

مثال زیر، چگونگی ساخت سازنده با استفاده از پارامتر ورودی را به شما نشان می دهد:

public class JavaApplication1 {

static class myClass{
    int a;
    char b;
// ساخت تابع سازنده
    myClass(int m, char n){
        a = m;
        b = n;
    }
}    
    public static void main(String[] args) {
        myClass newObject = new myClass(5,'m'); // مقدار دهی اولیه فیلدهای شی با استفاده از سازنده
        System.out.print(newObject.a); // خروجی مقدار 5 را نشان می دهد
        System.out.print(newObject.b); را نشان می دهد m خروجی مقدار

    } 
}

constructor مشخص می کند که هنگام ایجاد شیئی از نوع کلاس ، چه اتفاقی رخ می دهد . constructor های خاص خودشان را در تعریف کلاس مشخص می کنند. اما ، اگر constructor به طور صریح مشخص نشود ، در آن صورت جاوا آن را به طور خودکار تامین می کند. در خصوص کلاس ذکر شده در بخش قبل نیز، همین طور است.

مخرب یا Destructor

تابع مخرب کلاس (destructor) کم و بیش عکس سازنده عمل می کند. یک مخرب وقتی فراخوانی می شود که یک شی از بین می رود.

در ++C یک مخرب مشابه سازنده ساخته می شود فقط قبل از اسم آن علامت مد (~)قرار می گیرد.

تابع مخرب اتوماتیک وقتی متغیر شیء از حوزه دسترسی خارج می شود (برای متغیرهای سراسری وقتی از تابع اصلی خارج می شود و برای متغیر محلی هنگام خروج از بلاک تابع) فراخوانی می شود.

مشابه سازنده ها تابع مخرب نيز نوع برگشتی ندارد.

توابع مخرب یا destructor کاربرد زیادی در مدیریت حافظه برنامه های نوشته شده در ++C دارند.

عموما در مورد کلاسهای طراحی شده، با استفاده از این متد به آزاد سازی حافظه پرداخته میشود.

اما در زبانی مانند جاوا که مدیریت حافظه در اختیار ماشین مجازی میباشد، استفاده از این تابع چندان منطقی نیست، با این حال امکان پیاده سازی آن با استفاده از تابع finalize فراهم شده است.

برای انجام این کار در کلاس مربوطه یک تابع به نام finalize پیاده سازی گشته و سیستم Garbage Collector در زمان اتمام استفاده از کلاس و آزاد سازی تمام ارجاعات آن، تابه finalize را فراخوانی مینماید.

از آنجا که زمان عملکرد Grabage Collector نا مشخص است، با استفاده از دستورات gc و runFinalization میتوان ماشین مجازی را ملزم به آزاد سازی حافظه (جمع آوری زباله ها از حافظه) نمود.

مثال زیر نحوه انجام این کار را نشان میدهد:

import java.util.ArrayList;
 
public class Samples  {
    public static void main(String[] args){
        long mem = Runtime.getRuntime().freeMemory();
 
        SampleClass c1 = new SampleClass();
        SampleClass c2 = new SampleClass();
        SampleClass c3 = new SampleClass();
 
        System.out.println(String.format("Used memory: %d KB", (mem - Runtime.getRuntime().freeMemory())/1024));
        mem = Runtime.getRuntime().freeMemory();
 
        c1 = c2 = c3 = null;
 
        System.gc();
        System.runFinalization();
 
        System.out.println(String.format("Released memory: %d KB", (Runtime.getRuntime().freeMemory() - mem)/1024));
    }
}
 
class SampleClass {
    private ArrayList<Double> _obj;
 
    public SampleClass() {
        _obj = new ArrayList<Double>();
        for (int i=0; i<1000000; i++)
            _obj.add(Math.random());
 
        System.out.println("Created");
    }
 
    public void finalize() {
        _obj.clear();
        _obj = null;
        System.out.println("Finalized");
    }
 
}

آموزش برنامه نویسی جاوا (بخش هفتم: معرفی کلاس ها در جاوا)

استاندارد

کلاس هسته اصلی جاوا است. کلاس یک ساختار منطقی است که تمامیت زبان جاوا بر آن استوار شده ، زیرا شکل (Shape) و طبیعت یک شی را روشن می کند. کلاس همچنین شکل دهنده اساس برنامه نویسی شی ئ گرا در جاوا می باشد.

هر مفهومی که مایلید در یکد برنامه جاوا پیاده سازی نمایید باید ابتدا داخل یک کلاس کپسول سازی شود. از این پس می آموزید چگونه یک کلاس را برای تولید اشیا استفاده کنید. همچنین درباره روشها (methods) و سازنده ها (constructors) و وازه کلیدی this ، مطالبی می آموزید.

کلاسهای تولید شده در بحثهای گذشته فقط برای کپسول سازی روش ()main ، استفاده می شد، که برای نشان دادن اصول دستور زبان جاوا مناسب بودند.

شاید بهترین چیزی که باید درباره یک کلاس بدانید این است که کلاس یک نوع جدید داده را تعریف می کند. هربار که این نوع تعریف شود، می توان از آن برای ایجاد اشیائی از همان نوع استفاده نمود.

بنابراین، یک کلاس قالبی (template)، برای یک شی است. و یک شی نمونه ای از یک کلاس است. به شی، object نیز می گویند. که می توان کلمه نمونه (instance) را نیز برای آن به کار برد.

شکل عمومی یک کلاس

هنگامی که یک کلاس را تعریف می کنید، در حقیقت شکل و طبیعت دقیق آن کلاس ر ا اعلان می کنید. این کار را با توصیف داده های موجود در آن کلاس و کدهایی که روی آن داده ها عمل می کنند، انجام می دهید. در حالیکه کلاسها ممکن است خیلی ساده فقط شامل داده یا فقط کد باشند، اکثر کلاسهای واقعی هردو موضوع را دربرمیگیرند.

بعدا می بینیم که کد یک کلاس، رابط آن به داده های همان کلاس را توصیف می کند.

یک کلاس را با واژه کلیدی Class اعلام می کنند. کلاس ها می توانند بسیار ساده و یا خیلی پیچیده باشند.

شکل عمومی توصیف یک کلاس را می توانید در کد زیر مشاهده نمایید:

type methodname2(parameter-list ){
// body of method
}
//...
type methodnameN(parameter-list ){
// body of method
}

داده یا متغیرهایی که داخل یک کلاس تعریف شده اند را متغیرهای نمونه (instance variables) می گویند. کدها نیز داخل روش ها (methods) قرار می گیرند.

روشها و متغیرهای تعریف شده داخل یک کلاس را اعضای (members) یک کلاس می نامند.

در اکثر کلاسها، متغیرهای نمونه یا روی روشهای تعریف شده برای آن کلاس عمل کرده یا توسط این روشها مورد دسترسی قرار می گیرند. بنابراین، روشها تعیین کننده چگونگی استفاده از داده های یک کلاس هستند.

متغیرهای تعریف شده داخل یک کلاس، متغیرهای نمونه خوانده شده زیرا هر نمونه از کلاس ( یعنی هر شی، یک کلاس ) شامل کپی خاص خودش از این متغیرهاست. بنابراین داده مربوط به یک شی، جدا و منحصر بفرد از داده مربوط به شی دیگری است. ما بزودی این نکته را بررسی خواهیم نمود، اما فعلا باید این نکته بسیار مهم را بیاد داشته باشید. کلیه روش ها نظیر ()main ، همان شکل عمومی را دارند که تاکنون استفاده کرده ایم. اما اکثر روش ها را به عنوان static یا public توصیف نمی کنند.

بررسی خود را با یک نمونه ساده از کلاسها شروع می کنیم. در اینجا کلاسی تحت عنوان Box وجود دارد که سه متغیر نمونه را تعریف می کند: Width , Height , Depth

class Box {
double width;
double height;
double depth;
}

همان طور که قبلا گفتیم، یک کلاس نوع جدیدی از داده را توصیف می کند. در مثال بالا نوع جدید از داده را Box نامیده ایم. از نام Box برای اعلان اشیایی که می خواهیم از نوع داده Box باشند، استفاده می کنیم. در نظر داشته باشید، که اعلان یک کلاس یک شی چدید به وجود نمیاورد. بلکه یک قالب به وجود میاورد. پس برای ایجاد یک شی از نوع کلاس Box به ترتیب زیر عمل می کنیم:

Box mybox = new Box(); // create a Box object called mybox

پس از اجرای این دستور ، mybox نمونه ای از کلاس Box خواهد بود. بدین ترتیب، هر شی Box در برگیرنده کپی های خود از متغیرهای نمونه width, height,depth می باشد.

برای دسترسی به این متغیرها از عملگر نقطه (.) استفاده می کنید. عملگر نقطه، نام یک شی را با نام یک متغیر نمونه پیوند می دهد. بعنوان مثال ، برای منتسب کردن مقدار 100 به متغیر width در mybox، از دستور زیر استفاده نمایید:

mybox.width = 100;

این دستور به کامپایلر می گوید که کپی width که داخل شی mybox قرار گرفته است، را معادل 100 قرار بدهد.

به طور کلی، از عملگر نقطه ای برای دسترسی هم به متغیرهای نمونه و هم به روشهای موجود در یک شی استفاده می شود.

حال در اینجا برنامه ای را مشاهده می کنید که از کلاس Box استفاده کرده است:

/* A program that uses the Box class.
Call this file BoxDemo.java
/*
class Box {
double width;
double height;
double depth;
}
// This class declares an object of type Box.
class BoxDemo {
public static void main(String args[] ){
Box mybox = new Box();
double vol;
// assign values to mybox's instance variables
mybox.width = 10;
mybox.height = 20;
mybox.depth = 15;
// compute volume of box
vol = mybox.width * mybox.height * mybox.depth;
System.out.println("Volume is " + vol);
}
}

فایلی را که دربرگیرنده این برنامه است باید با نام BoxDemo.java بخوانید. زیرا روش ()main در کلاس BoxDemo و نه در کلاس Box قرار گرفته است. هنگامیکه این برنامه را کامپایل می کنید، می بینید که دو فایل .class ایجاد شده است. یکی برای Box و دیگری برای BoxDemo . کامپایلر جاوا به طور خودکار، هر کلاس را در فایل .class مربوط به خودش، قرار می دهد. ضرورتی ندارد که هر دو کلاس Box و BoxDemo در یک فایل منبع قرار بگیرند. می توانید هر کلاس را در فایل خاص خودش گذاشته و آنها را به ترتیب Box.java و BoxDemo.java بنامید. برای اجرای این برنامه باید BoxDemo.class را اجرا کنید. پس از این کار، حاصل زیر به دست می آید:

Volume is 3000

 

قبلا هم گفتیم که هر شی ئ دارای کپی های خاص خودش از متغیرهای نمونه است. یعنی اگر دو شی Box داشته باشید، هرکدام  نسخه ای از width,height,lenght خواهند داشت. تغییرات در متغیرهای نمونه یک شی به تغییرات در متغیرهای نمونه شی دیگر، اثر نمی گذارد.

خلاصه:

پس تا به اینجا یاد گرفتیم که کلاس، می تواند ترکیبی از متغیرهای مختلف باشد. و یک قالب است. پس می توانیم به عنوان مثال کلاس ماشین را طبق کد زیر داشته باشیم:

class car{
int height;
int lenght;
string model;
string color;
bool dande;
}

در کلاس car که در بالا معرفی نمودیم، ما ارتفاع و طول ماشین، مدل و رنگ و دنده ای بودن یا اتوماتیک بودن ماشین را برای قالب کلاس تعریف نمودیم. دقت کنید که می توان از متغیرهای مختلف برای قالب کلاس، استفاده کرد.

برای تعریف شی از نوع کلاس ماشین می توانیم به ترتیب زیر عمل نماییم:

car car1 = new car();
car car2 = new car();

برای مقدار دهی به شی car1 و شی car2 به ترتیب زیر عمل می کنیم:

car1.height=100;
car1.lenght=250;
car1.model="pride";
car1.color="white";
car1.dande=true;

car2.height=120;
car2.lenght=280;
car2.model="206";
car2.color="black";
car2.dande=false;

دقت نمایید که car1 شی ای با خصوصیات خودش، و car2 شی ای با خصوصیات دیگری نیز می باشد که این دو ارتباطی با هم ندارند به حز این که هر دو از قالب کلاس car استفاده می نمایند.