فصل 14: کلمات کلیدی static و this در جاوا

24 مرداد 1397
java-static-this-keyword

از کلمه کلیدی static برای مدیریت حافظه استفاده می شود؛ می توان گفت که کلمه کلیدی static بیشتر با خود کلاس ارتباط دارد تا با نمونه های ساخته شده از آن. از این کلمه کلیدی می توان در موارد زیر استفاده کرد:

  • متغیر (به نام متغیر کلاس هم شناخته می شود)
  • متد (به عنوان متد کلاس هم شناخته می شود)
  • بلوک
  • کلاس داخلی

1- متغیر استاتیک در جاوا

در صورتی که موقع ساخت یک متغیر از کلمه کلیدی static استفاده شود آنگاه

  • از این متغیر باید برای خصوصیات مشترکی که بین تمام نمونه های یک کلاس می باشد استفاده کرد، به عنوان مثال نام دانشگاه دانشجویان و یا نام شرکت کارکنان یک شرکت
  • متغیر استاتیک تنها یک بار هنگام لود شدن کلاس، حافظه دریافت می کند.

مزیت استفاده از متغیر استاتیک این است که در مصرف حافظه صرفه جویی میشود.

class Student{  
     int rollno;  
     String name;  
     String college="ITS";  
}  

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

مثال:

//Program of static variable  
  
class Student8{  
   int rollno;  
   String name;  
   static String college ="ITS";  
     
   Student8(int r,String n){  
   rollno = r;  
   name = n;  
   }  
 void display (){System.out.println(rollno+" "+name+" "+college);}  
  
 public static void main(String args[]){  
 Student8 s1 = new Student8(111,"Karan");  
 Student8 s2 = new Student8(222,"Aryan");  
   
 s1.display();  
 s2.display();  
 }  
}

خروجی:

Output:111 Karan ITS
       222 Aryan ITS

مقایسه شمارنده استاتیک و غیر استاتیک

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

مثال:

class Counter{  
int count=0;//will get memory when instance is created  
  
Counter(){  
count++;  
System.out.println(count);  
}  
  
public static void main(String args[]){  
  
Counter c1=new Counter();  
Counter c2=new Counter();  
Counter c3=new Counter();  
  
 }  
}

خروجی:

Output:1
       1
       1

متغییر استاتیک در جاوا

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

مثال:

class Counter2{  
static int count=0;//will get memory only once and retain its value  
  
Counter2(){  
count++;  
System.out.println(count);  
}  
  
public static void main(String args[]){  
  
Counter2 c1=new Counter2();  
Counter2 c2=new Counter2();  
Counter2 c3=new Counter2();  
  
 }  
}

خروجی:

Output:1
       2
       3

2- متد استاتیک در جاوا

در صورت استفاده از static هنگام ساخت یه متد، آن متد:

  • به کلاس تعلق دارد نه یک نمونه خاص ساخته شده از آن کلاس
  • آن را می توان بدون ساخت نمونه‌ای از آن کلاس صدا زد و ازش استفاده کرد.
  • می تواند به متغیرهای استاتیک دسترسی داشته باشد و مقادیر آنها را تغییر دهد.

مثال:

//Program of changing the common property of all objects(static field).  
  
class Student9{  
     int rollno;  
     String name;  
     static String college = "ITS";  
       
     static void change(){  
     college = "BBDIT";  
     }  
  
     Student9(int r, String n){  
     rollno = r;  
     name = n;  
     }  
  
     void display (){System.out.println(rollno+" "+name+" "+college);}  
  
    public static void main(String args[]){  
    Student9.change();  
  
    Student9 s1 = new Student9 (111,"Karan");  
    Student9 s2 = new Student9 (222,"Aryan");  
    Student9 s3 = new Student9 (333,"Sonoo");  
  
    s1.display();  
    s2.display();  
    s3.display();  
    }  
}

خروجی:

Output:111 Karan BBDIT
       222 Aryan BBDIT
       333 Sonoo BBDIT

حال یک مثال دیگر

مثال:

//Program to get cube of a given number by static method  
  
class Calculate{  
  static int cube(int x){  
  return x*x*x;  
  }  
  
  public static void main(String args[]){  
  int result=Calculate.cube(5);  
  System.out.println(result);  
  }  
}

خروجی:

Output:125

محدودیت های متد استاتیک

دو محدودیت اصلی برای متدهای استاتیک وجود دارند که عبارتند از:

  1. به متغیرهای غیراستاتیک دسترسی ندارد و نمیتواند متدهای غیراستاتیک را مستقیما صدا بزند.
  2. از کلمات کلیدی this و super نمی توان در آن استفاده کرد.

مثال:

class A{  
 int a=40;//non static  
   
 public static void main(String args[]){  
  System.out.println(a);  
 }  
}

خروجی:

Output:Compile Time Error

سوال: چرا متد main یک متد static است؟

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

3- بلوک استاتیک در جاوا

  • برای مقداردهی اولیه به اعضای استاتیک استفاده می شود.
  • قبل از اجرای متد main در مرحله لود شدن کلاس ها اجرا میشود.

مثال:

class A2{  
  static{System.out.println("static block is invoked");}  
  public static void main(String args[]){  
   System.out.println("Hello main");  
  }  
}

خروجی:

Output:static block is invoked
       Hello main

سوال: آیا می توان یک برنامه را بدون متد main اجرا کرد؟

در JDK های قبل از ورژن 1.7، اینکار توسط بلوک های استاتیک قابل انجام بود. توجه کنید:

مثال:

class A3{  
  static{  
  System.out.println("static block is invoked");  
  System.exit(0);  
  }  
}

خروجی:

Output:static block is invoked (if not JDK7)

خروجی در ورژن‌های جدید:

Output:Error: Main method not found in class A3, please define the main method as:
public static void main(String[] args)

کلمه کلیدی this در جاوا

این کلمه کلیدی کاربردهای فراوانی در جاوا دارد. به طور معمول this متغیر رفرنسی‌ است که به شی کنونی و بالایی خود اشاره میکند.

کاربردهای کلمه کلیدی this

  1. برای اشاره به متغیر نمونه کلاس مذکور خود مورد استفاده قرار میگیرد.
  2. برای صدا زدن متدهای کلاس به شکل ضمنی استفاده می شود
  3. برای صدا زدن کانستراکتور کلاس استفاده می شود.
  4. به عنوان آرگومان هنگام صدا زدن متد استفاده می شود.
  5. به عنوان آرگومان در کانستراکتور مورد استفاده قرار میگیرد.
  6. برای بازگرداندن نمونه ساخته شده از کلاس از درون متد همچنین از this استفاده می شود.

معرفی کلمه کلیدی this

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

1- اشاره به متغیرهای نمونه ساخته شده از کلاس

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

مثال:

class Student{  
int rollno;  
String name;  
float fee;  
Student(int rollno,String name,float fee){  
rollno=rollno;  
name=name;  
fee=fee;  
}  
void display(){System.out.println(rollno+" "+name+" "+fee);}  
}  
class TestThis1{  
public static void main(String args[]){  
Student s1=new Student(111,"ankit",5000f);  
Student s2=new Student(112,"sumit",6000f);  
s1.display();  
s2.display();  
}}

خروجی:

0 null 0.0
0 null 0.0

حالا به کد زیر که این مشکل را حل کرده است، نگاه بندازید.

مثال:

class Student{  
int rollno;  
String name;  
float fee;  
Student(int rollno,String name,float fee){  
this.rollno=rollno;  
this.name=name;  
this.fee=fee;  
}  
void display(){System.out.println(rollno+" "+name+" "+fee);}  
}  
  
class TestThis2{  
public static void main(String args[]){  
Student s1=new Student(111,"ankit",5000f);  
Student s2=new Student(112,"sumit",6000f);  
s1.display();  
s2.display();  
}}

خروجی:

111 ankit 5000
112 sumit 6000

شما می توانید برنامه را به گونه‌ای بنویسید که به کل نیاز به این پیچیدگی‌ها نباشد. نگاه کنید:

مثال:

class Student{  
int rollno;  
String name;  
float fee;  
Student(int r,String n,float f){  
rollno=r;  
name=n;  
fee=f;  
}  
void display(){System.out.println(rollno+" "+name+" "+fee);}  
}  
  
class TestThis3{  
public static void main(String args[]){  
Student s1=new Student(111,"ankit",5000f);  
Student s2=new Student(112,"sumit",6000f);  
s1.display();  
s2.display();  
}}

خروجی:

111 ankit 5000
112 sumit 6000

البته توصیه میشود که از نام‌های معنی دار برای آرگومان‌ها و متغیرهای خودتان استفاده کنید و در صورت نیاز از کلمه کلیدی this استفاده کنید.

2- صدا زدن متد در کلاس

برای زدن متدهای یک کلاس می توانید از کلمه کلیدی this استفاده کنید. البته خوب است بدانید که در صورت ننوشتن این کلید واژه، کامپایلر به طور اتوماتیک این کلیدواژه را اضافه می کند.

مثال:

class A{  
void m(){System.out.println("hello m");}  
void n(){  
System.out.println("hello n");  
//m();//same as this.m()  
this.m();  
}  
}  
class TestThis4{  
public static void main(String args[]){  
A a=new A();  
a.n();  
}}

خروجی:

hello n
hello m

استفاده از کلاس برای تعریف کلمه کلیدی this

3- صدا زدن کانستراکتور کلاس

موقعیتی را تصور کنید که کلاس شما دارای چندین کانستراکتور می باشد و می خواهید از یکی از کانستراکتورهای خود در کانستراکتور دیگر برای صرفه‌جویی در نوشتن کد استفاده کنید؛ در این صورت می توانید از this() استفاده کنید.

مثال:

class A{  
A(){System.out.println("hello a");}  
A(int x){  
this();  
System.out.println(x);  
}  
}  
class TestThis5{  
public static void main(String args[]){  
A a=new A(10);  
}}

خروجی:

hello a
10

در مثال زیر کانستراکتور صدازده شده چندپارامتری است:

مثال:

class A{  
A(){  
this(5);  
System.out.println("hello a");  
}  
A(int x){  
System.out.println(x);  
}  
}  
class TestThis6{  
public static void main(String args[]){  
A a=new A();  
}}

خروجی:

5
hello a

همانطور که گفته شد، معمولا از this() برای تشکیل زنجیری میان کانستراکتورها استفاده می شود تا در نوشتن کد صرفه‌جویی شود و کد زیباتری نوشته شود. در مثال زیر بهتر این کاربرد مشخص می شود:

مثال:

class Student{  
int rollno;  
String name,course;  
float fee;  
Student(int rollno,String name,String course){  
this.rollno=rollno;  
this.name=name;  
this.course=course;  
}  
Student(int rollno,String name,String course,float fee){  
this(rollno,name,course);//reusing constructor  
this.fee=fee;  
}  
void display(){System.out.println(rollno+" "+name+" "+course+" "+fee);}  
}  
class TestThis7{  
public static void main(String args[]){  
Student s1=new Student(111,"ankit","java");  
Student s2=new Student(112,"sumit","java",6000f);  
s1.display();  
s2.display();  
}}

خروجی:

111 ankit java null
112 sumit java 6000

نکته بسیار مهم این است که this() باید در اولین خط از کانستراکتور باشد.

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

مثال:

class Student{  
int rollno;  
String name,course;  
float fee;  
Student(int rollno,String name,String course){  
this.rollno=rollno;  
this.name=name;  
this.course=course;  
}  
Student(int rollno,String name,String course,float fee){  
this.fee=fee;  
this(rollno,name,course);//C.T.Error  
}  
void display(){System.out.println(rollno+" "+name+" "+course+" "+fee);}  
}  
class TestThis8{  
public static void main(String args[]){  
Student s1=new Student(111,"ankit","java");  
Student s2=new Student(112,"sumit","java",6000f);  
s1.display();  
s2.display();  
}}

خروجی:

Compile Time Error: Call to this must be first statement in constructor

4- استفاده از this به عنوان آرگومان ورودی متد

در مبحث Event Handling که در فصل‌های آتی به آن خواهیم پرداخت، پیش میاید که از this به عنوان آرگومان ورودی متد استفاده شود.

مثال:

class S2{  
  void m(S2 obj){  
  System.out.println("method is invoked");  
  }  
  void p(){  
  m(this);  
  }  
  public static void main(String args[]){  
  S2 s1 = new S2();  
  s1.p();  
  }  
}

خروجی:

method is invoked

همانطور که گفته شد، از این کاربرد در بحث Event Handling و در موقعیتی که نیاز باشد رفرنس یک کلاس را فراهم کرد استفاده می شود. در واقع از یک شی به طریق مختلف بهره میبریم.

5- استفاده از this در هنگام صدا زدن کانستراکتور

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

مثال:

class B{  
  A4 obj;  
  B(A4 obj){  
    this.obj=obj;  
  }  
  void display(){  
    System.out.println(obj.data);//using data member of A4 class  
  }  
}  
  
class A4{  
  int data=10;  
  A4(){  
   B b=new B(this);  
   b.display();  
  }  
  public static void main(String args[]){  
   A4 a=new A4();  
  }  
}

خروجی:

Output:10

6- استفاده از this برای بازگرداندن نمونه ساخته شده

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

سینتکس:

return_type method_name(){  
return this;  
}

مثال:

class A{  
A getA(){  
return this;  
}  
void msg(){System.out.println("Hello java");}  
}  
class Test1{  
public static void main(String args[]){  
new A().getA().msg();  
}  
}

خروجی:

Hello java

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

مثال:

class A5{  
void m(){  
System.out.println(this);//prints same reference ID  
}  
public static void main(String args[]){  
A5 obj=new A5();  
System.out.println(obj);//prints the reference ID  
obj.m();  
}  
}

خروجی:

A5@22b3ea59
A5@22b3ea59

 

نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.