تعریف استاتیک و کلیدواژه ی static
با استفاده از کلیدواژه ی static در جاوا میتونیم فیلد، متد و کلاس های داخلی (Inner Class) استاتیک تعریف کنیم.
هنگامی که از کلید واژه ی static در جاوا برای یک عضو از کلاس استفاده بشه عضو مورد نظر وابسته به کلاس و مستقل از آبجکت (نمونه) های ایجاد شده از کلاس میشه و در طی زمان اجرای برنامه بدون نیاز به ایجاد آبجکت از کلاس مستقیم در دسترس است.
مقدار متغیر استاتیک در جاوا، بین تمام آبجکت های ایجاد شده از کلاس مشترک است. و متغیر تا پایان زمان اجرای برنامه وجود دارد.
برای صدا زدن اعضای استاتیک بهجای نوشتن اسم متغیر آبجکتی کافیه اسم کلاسی که عضو رو داخلش تعریف کردیم بنویسیم، نقطه بزاریم و عضو رو صدا بزنیم.
نکته
تمام اعضای کلاس Math در جاوا استاتیک هستند.
فیلد های استاتیک
این متغیر ها وابسته به کلاس هستند و مقدار آنها تا پایان زمان اجرای برنامه بین تمام آبجکت های ایجاد شده از کلاس مشترک است.
زمانی که در کلاس بخوایم یک متغیر با مقدار یکسان و مشترک بین تمام آبجکت ها تعریف کنیم، برای بهینهسازی در حافظه ی برنامه دیتا فیلد رو استاتیک (static) تعریف می کنیم. اینطوری تنها یک متغیر داریم که مقدار متغیر بین تمام آبجکت های ایجاد شده از کلاس مشترک است.
به عنوان مثال میتونیم فیلد PI رو در کلاس Math در نظر بگیریم، چون مقدار PI همیشه 3.14 است نیاز نیست در هر آبجکت این مقدار به طور مجزا ایجاد بشه بنابراین PI رو به صورت فیلد استاتیک در Math تعریف کرده اند.
تعریف فیلد
public class MyClass{
static Type myStaticField = ...;
}
صدا زدن فیلد
Type type = MyClass.myStaticField;
مثال
public class Log{
public static String label = "Log";
}
public static void main(String[] args){
System.out.println(label);
}
متد های استاتیک
متد main در جاوا استاتیک (static) است.
این متد ها مانند فیلد های استاتیک (static) وابسته به کلاس هستند و بدون نیاز به نمونه سازی با استفاده از اسم کلاس صداشون می زنیم.
تعریف متد
فرض کنیم میخوایم یک متد استاتیک با نام myStaticMethod تعریف کنیم، مانند زیر عمل میکنیم:
public class MyClass {
public static void myStaticMethod(Type0 p0, Type1 p1, …, TypeN pN){
...
}
}
صدا زدن متد
برای صدا زدن متد استاتیک نام کلاسی که متد داخلش تعریف شده رو مینویسیم، نقطه میزاریم و سپس مانند زیر متد رو صدا میزنیم.
Type0 type0 = new Type0();
Type1 type1 = new Type1();
...
TypeN typeN = new TypeN();
MyClass.myStaticMethodName(type0, type1, ... , typeN)
در بالا type0-typeN متغیر هایی هستند که به عنوان پارامتر به متد پاس میدیم.
مثال
public class Log{
private static String label = "Log";
public static void e(String message){
System.err.println(label + " error message: " + message)
}
public static void d(String message){
System.out.println(label + " debug message: " + message);
}
}
public static void main(String[] args){
Scanner input = newScanner(System.in);
System.out.println("Enter radius");
double radius = input.nextDouble();
if(radius < 0) Log.e("Radius must not be negative");
else Log.d("Radius is " + radius);
}
یک متد یا فیلد استاتیک رو میتونیم مستقیم داخل متد معمولی صدا بزنیم اما متد و فیلد های معمولی رو نمیتونیم مستقیم داخل متد استاتیک صدا بزنیم و باید استاتیک باشن.
class MyClass{
private Type myMemberField;
private Type1 myStaticField;
public myMemberMethod(){
...
}
public static myStaticSecondMethod(){
...
}
public static myStaticMethod(){
//خطای کامپایل
myMemberField = ...;
//خطای کامپایل
myMemberMethod();
//بدون خطا
myStaticField = ...;
//بدون خطا
myStaticSecondMethod();
}
}
مثال ها
در مثال زیر هربار یک آبجکت از کلاس دایره ایجاد بشه یک واحد به فیلد numberOfObjects اضافه میشه و با این کار تعداد آبجکت های ایجاد شده از کلاس Circle رو میشماریم.
public class Circle {
double radius;
private static int numberOfObjects = 0;
public Circle(){
this.radius = 1;
numberOfObjects ++;
}
public Circle(double radius){
this.radius = radius;
numberOfObjects++;
}
public double getArea(){
return radius * radius * Math.PI;
}
public static int getNumberOfObjects(){
return Circle.numberOfObjects;
}
}
TestCircle.java
public class TestCircle {
public static void main(String[] args){
System.out.println("Before creating new instance from Circle number of objects are " +
Circle.getNumberOfObjects());
Circle c0 = new Circle(4);
System.out.println("After creating c0: (radius: " + c0.radius + ", " + "area: " + c0.getArea() + ")"
+ " number of objects are " + Circle.getNumberOfObjects());
Circle c1 = new Circle();
System.out.println("After creating c1: (radius: " + c1.radius + ", " + "area: " + c1.getArea() + ")"
+ " number of objects are " + Circle.getNumberOfObjects());
}
}
در مثال بالا یک فیلد استاتیک داریم به اسم numberOfObjects که تعداد نمونه های ایجاد شده از کلاس Circle رو میشماره و با متد استاتیک getNumberOfObjects این فیلد رو صدا میزنیم.
نمونه های ایجاد شده از کلاس Circle هرکدوم ویژگی های مختص به خودشونو دارن اما مقدار فیلد numberOfObjects بین تمام نمونه ها مشترکه.
مثال
در زیر متغیر های استاتیک رو با final تعریف کردیم، متغیر هایی که با final تعریف میشن مقدارشون غیرقابل تغییر است.
public class TV {
public static final int MAXIMUM_VOLUME_LEVEL = 10;
public static final int MINIMUM_VOLUME_LEVEL = 0;
public static final int MAXIMUM_CHANNEL_NUMBER = 120;
public static final int MINIMUM_CHANNEL_NUMBER = 1;
private String panel;
private int channel = 1;
private int volume = 1;
private boolean on;
public TV(String panel){
this.panel = panel;
}
public TV(){
this("FLATIRON");
}
public void turnOn(){
on = true;
}
public void turnOff(){
on = false;
}
public void setChannel(int channel) {
if (on && channel >= MINIMUM_CHANNEL_NUMBER && channel <= MAXIMUM_CHANNEL_NUMBER)
this.channel = channel;
}
public void setVolume(int volume) {
if (on && volume >= MINIMUM_VOLUME_LEVEL && volume <= MAXIMUM_VOLUME_LEVEL)
this.volume = volume;
}
public String getPanel(){
return panel;
}
public int getChannel() {
return channel;
}
public int getVolume() {
return volume;
}
public void channelUp(){
if (on && channel < MAXIMUM_CHANNEL_NUMBER) channel++;
}
public void channelDown(){
if (on && channel > MINIMUM_CHANNEL_NUMBER ) channel --;
}
public void volumeUp(){
if (on && volume < MAXIMUM_VOLUME_LEVEL)
volume++;
}
public void volumeDown(){
if (on && volume > MINIMUM_VOLUME_LEVEL)
volume --;
}
public boolean isOn() {
return on;
}
public boolean isMuted(){
return volume == MINIMUM_VOLUME_LEVEL;
}
}
ساخت نمونه و استفاده از TV.
public static void main(String[] args){
TV tv1 = new TV();
tv1.turnOn();
tv1.setChannel(21);
tv1.setVolume(4);
TV tv2 = new TV();
tv2.turnOn();
tv2.channelUp();
tv2.channelUp();
tv2.volumeUp();
System.out.println("tv1 has been built by " + tv1.getPanel() + " panel");
System.out.println("tv1's channel is " + tv1.getChannel() + " and volume level is " + tv1.getVolume());
System.out.println("tv2 has been built by " + tv2.getPanel() + " panel");
System.out.println("tv2's channel is " + tv2.getChannel() + " and volume level is " + tv2.getVolume());
}
کلاس های استاتیک
میشه از کلید واژه ی استاتیک (static) برای تعریف کلاس های داخلی (inner class ها) نیز استفاده کرد.
نکته
فقط کلاس های داخلی در جاوا یا همون Inner Class ها رو میشه به صورت استاتیک تعریف کرد
فرم کلی:
public class MyOuterClass {
...
public static class MyInnerClass {
...
}
}
هنگامی که بخوایم از InnerClassName نمونه ی جدید درست کنیم به صورت زیر عمل می کنیم:
MyOuterClass.MyInnerClass inner = new MyOuterClass.MyInnerClass();
در مورد کلاس های داخلی استاتیک در قسمت کلاس های تو در تو بیشتر توضیح دادیم.
خلاصه
- کلید واژه ی استاتیک در جاوا برای اعضای داخل کلاس استفاده میشه
- اعضای استاتیک وابسته به نمونه های ساخته شده از کلاس نیستن و در طول زمان اجرای برنامه در دسترسن
- فیلدها ، متد ها و کلاس های داخل کلاس رو میتونیم به صورت استاتیک تعریف کنیم
- مقدار یک فیلد استاتیک میتونه بین تمام کلاس های پروژه تا زمان اجرای برنامه به اشتراک گذاشته بشه
- برای صدا زدن فیلد ها و متد های کلاس نام کلاس رو مینویسیم ، نقطه میزاریم و اسم متد یا فیلد رو می نویسیم
- برای نمونه سازی از کلاس های استاتیک new رو می نویسیم نام کلاس اصلی رو می نویسیم نقطه میزاریم و نام کلاس استاتیک داخل کلاس اصلی رو مینویسیم و مانند سایر کلاس ها نمونه سازی یا همون شی سازی می کنیم