زمینه های استاتیک
وقتی یک متغیر سطح کلاس را نشان می دهیم، نشان می دهیم که مقدار متعلق به یک کلاس است. اگر این کار را انجام ندهید، مقدار متغیر به یک شیء ایجاد شده با استفاده از این کلاس محدود می شود. چه مفهومی داره؟ و واقعیت این است که اگر متغیر ثابت نباشد، هر شیء جدید از این کلاس مقدار خاص خود را از این متغیر خواهد داشت که با تغییر آن، آن را منحصراً در یک شی تغییر می دهیم: به عنوان مثال، ما یک کلاس Car با یک غیر داریم. -متغیر استاتیک:public class Car {
int km;
}
سپس در اصل:
Car orangeCar = new Car();
orangeCar.km = 100;
Car blueCar = new Car();
blueCar.km = 85;
System.out.println("Orange car - " + orangeCar.km);
System.out.println("Blue car - " + blueCar.km);
خروجی ای که به دست می آوریم این است:
Orange car - 100
Blue car - 85
همانطور که مشاهده می کنید، هر شیء متغیر مخصوص به خود را دارد که تغییر آن فقط برای این شیء اتفاق می افتد. خوب، اگر یک متغیر استاتیک داشته باشیم، این مقدار جهانی برای همه یکسان است: حالا یک ماشین با یک متغیر استاتیک داریم:
public class Car {
static int km;
}
سپس همان کد اصلی به کنسول خروجی خواهد شد:
Orange car - 85
Blue car - 85
از این گذشته، ما برای همه ما یک متغیر داریم و هر بار آن را تغییر می دهیم. متغیرهای استاتیک معمولاً نه با یک مرجع شی - orangeCar.km، بلکه با نام کلاس - Car.km قابل دسترسی هستند.
بلوک استاتیک
دو بلوک اولیه وجود دارد - منظم و استاتیک. این بلوک برای مقداردهی اولیه متغیرهای داخلی در نظر گرفته شده است. اگر بلوک نرمال باشد، متغیرهای داخلی شی با آن مقدار دهی اولیه می شوند، اما اگر ثابت باشد، متغیرهای استاتیک (یعنی متغیرهای کلاس) به آنها اختصاص داده می شود. مثالی از یک کلاس با یک بلوک اولیه سازی استاتیک:public class Car {
static int km;
static {
km = 150;
}
}
روش استاتیک
متدهای استاتیک از این جهت با متدهای معمولی متفاوت هستند که به جای یک شیء، به یک کلاس محدود می شوند. ویژگی مهم یک روش استاتیک این است که فقط می تواند به متغیرها/روش های استاتیک دسترسی داشته باشد. به عنوان مثال، بیایید به کلاسی نگاه کنیم که نوعی شمارنده است که فراخوانی های متد را پیگیری می کند:public class Counter {
static int count;
public static void invokeCounter() {
count++;
System.out.println("Current counter value - " + count);
}
}
بیایید آن را به طور اصلی بنامیم:
Counter.invokeCounter();
Counter.invokeCounter();
Counter.invokeCounter();
و خروجی را به کنسول دریافت می کنیم:
Текущее meaning счётчика - 1
Текущее meaning счётчика - 2
Текущее meaning счётчика - 3
کلاس استاتیک در جاوا
فقط یک کلاس داخلی می تواند یک کلاس ثابت باشد. باز هم این کلاس به طبقه بیرونی گره خورده است و اگر خارجی به کلاس دیگری به ارث برسد، این یکی ارثی نخواهد بود. علاوه بر این، این کلاس می تواند به ارث برده شود، همانطور که می توان آن را از هر کلاس دیگری به ارث برد و یک رابط را پیاده سازی کرد. اساساً، یک کلاس تودرتو ایستا تفاوتی با هیچ کلاس داخلی دیگری ندارد، به جز اینکه شیء آن حاوی ارجاع به شیء کلاس خارجی که آن را ایجاد کرده است، نیست. با این حال، این یک کلاس استاتیک را شبیه به یک کلاس غیر تودرتوی معمولی می کند، زیرا تنها تفاوت آن این است که در کلاس دیگری پیچیده شده است. در برخی موارد، این یک مزیت برای ما است، زیرا از طریق آن به متغیرهای استاتیک خصوصی کلاس خارجی دسترسی داریم. مثالی از یک کلاس استاتیک تو در تو:public class Vehicle {
public static class Car {
public int km;
}
}
ایجاد یک نمونه از این کلاس و تعیین مقدار متغیر داخلی:
Vehicle.Car car = new Vehicle.Car();
car.km = 90;
برای استفاده از متدها/متغیرها/کلاس استاتیک، نیازی به ایجاد یک شی از آن کلاس نداریم. البته باید اصلاح کننده های دسترسی را نیز در نظر گرفت. به عنوان مثال، فیلدها private
فقط در کلاسی که در آن اعلان شده اند قابل دسترسی هستند. فیلدها protected
برای همه کلاسهای داخل بسته ( بسته ) و همچنین برای همه کلاسهای فرعی خارج از بسته در دسترس هستند. برای جزئیات بیشتر، مقاله " خصوصی در مقابل محافظت شده در مقابل عمومی " را بررسی کنید. increment()
فرض کنید یک متد استاتیک در کلاس وجود دارد Counter
که وظیفه آن افزایش شمارنده است count
. برای فراخوانی این متد، می توانید از فراخوانی فرم استفاده کنید Counter.increment()
. Counter
برای دسترسی به یک فیلد یا متد استاتیک نیازی به نمونه سازی کلاس نیست . این تفاوت اساسی بین اشیاء ثابت و غیر استاتیک (اعضای کلاس) است. اجازه دهید یک بار دیگر به شما یادآوری کنم که اعضای کلاس استاتیک مستقیماً به کلاس تعلق دارند، نه به نمونه آن. یعنی مقدار یک متغیر استاتیک count
برای همه اشیاء از نوع یکسان خواهد بود Counter
. در ادامه این مقاله، به جنبههای اساسی استفاده از اصلاحکننده استاتیک در جاوا و همچنین برخی از ویژگیهایی که به شما در درک مفاهیم کلیدی برنامهنویسی کمک میکنند، نگاهی خواهیم انداخت.
آنچه هر برنامه نویسی باید در مورد اصلاح کننده Static در جاوا بداند
در این بخش، به اصول استفاده از روشها، فیلدها و کلاسهای استاتیک میپردازیم. بیایید با متغیرها شروع کنیم.-
شما نمی توانید به اعضای غیر استاتیک یک کلاس در یک زمینه ایستا، مانند یک متد یا بلوک، دسترسی پیدا کنید. کامپایل کد زیر با خطا مواجه می شود:
public class Counter{ private int count; public static void main(String args[]){ System.out.println(count); //compile time error }}
این یکی از رایج ترین اشتباهات برنامه نویسان جاوا، به خصوص تازه کارها است. از آنجایی که متد
main
ثابت است، اما متغیرcount
نیست، در این حالت متدprintln
داخل متدmain
"خطای زمان کامپایل" را ایجاد می کند. -
В отличие от локальных переменных, статические поля и методы НЕ потокобезопасны (Thread-safe) в Java. На практике это одна из наиболее частых причин возникновения проблем связанных с безопасностью мультипоточного программирования. Учитывая что каждый экземпляр класса имеет одну и ту же копию статической переменной, то такая переменная нуждается в защите — «залочивании» классом. Поэтому при использовании статических переменных, убедитесь, что они должным образом синхронизированы (synchronized), во избежание проблем, например таких How «состояние гонки» (race condition).
-
Статические методы имеют преимущество в применении, т.к. отсутствует необходимость каждый раз создавать новый an object для доступа к таким методам. Статический метод можно вызвать, используя тип класса, в котором эти методы описаны. Именно поэтому, подобные методы How нельзя лучше подходят в качестве методов-фабрик (
factory
), и методов-утorт (utility
). Классjava.lang.Math
— замечательный пример, в котором почти все методы статичны, по этой же причине классы-утorты в Java финализированы (final
). -
Другим важным моментом является то, что вы НЕ можете переопределять (
Override
) статические методы. Если вы объявите такой же метод в классе-наследнике (subclass
), т.е. метод с таким же именем и сигнатурой, вы лишь «спрячете» метод суперкласса (superclass
) instead of переопределения. Это явление известно How сокрытие методов (hiding methods
). Это означает, что при обращении к статическому методу, который объявлен How в родительском, так и в дочернем классе, во время компиляции всегда будет вызван метод исходя из типа переменной. В отличие от переопределения, такие методы не будут выполнены во время работы программы. Рассмотрим пример:class Vehicle{ public static void kmToMiles(int km){ System.out.println("Inside parent class/static method"); } } class Car extends Vehicle{ public static void kmToMiles(int km){ System.out.println("Inside child class/static method "); } } public class Demo{ public static void main(String args[]){ Vehicle v = new Car(); v.kmToMiles(10); }}
Вывод в консоль:
Внутри родительского класса/статического метода
Код наглядно демонстрирует: несмотря на то, что an object имеет тип
Car
, вызван статический метод из классаVehicle
, т.к. произошло обращение к методу во время компиляции. И заметьте, ошибки во время компиляции не возникло! -
Объявить статическим также можно и класс, за исключением классов верхнего уровня. Такие классы известны How «вложенные статические классы» (
nested static class
). Они бывают полезными для представления улучшенных связей. Яркий пример вложенного статического класса —HashMap.Entry
, который предоставляет структуру данных внутриHashMap
. Стоит заметить, также How и любой другой внутренний класс, вложенные классы находятся в отдельном файле .class. Таким образом, если вы объявor пять вложенных классов в вашем главном классе, у вас будет 6 файлов с расширением .class. Ещё одним примером использования является объявление собственного компаратора (Comparator
), например компаратор по возрасту (AgeComparator
) в классе сотрудники (Employee
). -
Модификатор static также может быть объявлен в статичном блоке, более известным How «Статический блок инициализации» (
Static initializer block
), который будет выполнен во время загрузки класса. Если вы не объявите такой блок, то Java соберёт все статические поля в один список и выполнит его во время загрузки класса. Однако, статичный блок НЕ может пробросить перехваченные исключения, но может выбросить не перехваченные. В таком случае возникнет «Exception Initializer Error». На практике, любое исключение возникшее во время выполнения и инициализации статических полей, будет завёрнуто Java в эту ошибку. Это также самая частая причина ошибки «No Class Def Found Error», т.к. класс не находился в памяти во время обращения к нему. -
Полезно знать, что статические методы связываются во время компиляции, в отличие от связывания виртуальных or не статических методов, которые связываются во время исполнения на реальном an objectе. Следовательно, статические методы не могут быть переопределены в Java, т.к. полиморфизм во время выполнения не распространяется на них. Это важное ограничение, которое необходимо учитывать, объявляя метод статическим. В этом есть смысл, только тогда, когда нет возможности or необходимости переопределения такого метода классами-наследниками. Методы-фабрики и методы-утorты хорошие образцы применения модификатора static. Джошуа Блох выделил несколько преимуществ использования статичного метода-фабрики перед конструктором, в книге «Effective Java», которая является обязательной для прочтения каждым программистом данного языка.
-
Важным свойством статического блока является инициализация. Статические поля or переменные инициализируются после загрузки класса в память. Порядок инициализации сверху вниз, в том же порядке, в Howом они описаны в исходном файле Java класса. Поскольку статические поля инициализируются на потокобезопасный манер, это свойство также используется для реализации паттерна
Singleton
. Если вы не используется списокEnum
HowSingleton
, по тем or иным причинам, то для вас есть хорошая альтернатива. Но в таком случае необходимо учесть, что это не «ленивая» инициализация. Это означает, что статическое поле будет проинициализировано ещё ДО того How кто-нибудь об этом «попросит». Если an object ресурсоёмкий or редко используется, то инициализация его в статическом блоке сыграет не в вашу пользу. -
در طول سریال سازی، درست مانند
transient
متغیرها، فیلدهای استاتیک سریالی نمی شوند. در واقع، اگر هر دادهای را در یک فیلد ثابت ذخیره کنید، پس از سریالزدایی، شی جدید حاوی مقدار اولیه (پیشفرض) خود خواهد بود، برای مثال، اگر فیلد استاتیک یک متغیر از نوع باشدint
، مقدار آن پس از سریالزدایی صفر خواهد بود، اگر نوعfloat
0.0 است، اگر نوعObject
-null
. راستش این یکی از سوالات متداول در مورد سریال سازی در مصاحبه های جاوا است. مهم ترین داده های مربوط به یک شی را در یک میدان ثابت ذخیره نکنید! -
و در نهایت، اجازه دهید در مورد صحبت کنیم
static import
. این اصلاحکننده شباهتهای زیادی با عملگر استاندارد داردimport
، اما بر خلاف آن، به شما اجازه میدهد یک یا همه اعضای ثابت یک کلاس را وارد کنید. هنگام وارد کردن متدهای استاتیک، می توان به آنها دسترسی پیدا کرد که انگار در همان کلاس تعریف شده اند، به طور مشابه هنگام وارد کردن فیلدها، می توانیم بدون تعیین نام کلاس به آنها دسترسی داشته باشیم. این ویژگی در نسخه 1.5 جاوا معرفی شد و در صورت استفاده صحیح، خوانایی کد را بهبود می بخشد. این ساختار اغلب در تست های JUnit یافت می شود ، زیرا تقریباً همه برنامهنویسان آزمایشی ازstatic import
روشهای ادعایی، به عنوان مثال،assertEquals()
و موارد تکراری بیش از حد آنها استفاده میکنند. اگر چیزی روشن نیست، برای اطلاعات بیشتر خوش آمدید .
GO TO FULL VERSION