الحقول الثابتة
عندما نشير إلى متغير على مستوى الفئة، فإننا نشير إلى أن القيمة تنتمي إلى فئة ما. إذا لم تقم بذلك، فسيتم ربط قيمة المتغير بكائن تم إنشاؤه باستخدام هذه الفئة. ماذا يعني ذلك؟
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
متاحة لجميع الفئات داخل الحزمة ( package )، وكذلك لجميع الفئات التابعة خارج الحزمة. لمزيد من التفاصيل، راجع المقالة " خاص مقابل محمي مقابل عام ". لنفترض أن هناك طريقة ثابتة increment()
في الفصل Counter
تتمثل مهمتها في زيادة العداد count
. لاستدعاء هذه الطريقة، يمكنك استخدام استدعاء النموذج Counter.increment()
. ليست هناك حاجة لإنشاء مثيل لفئة Counter
للوصول إلى حقل أو طريقة ثابتة. هذا هو الفرق الأساسي بين الكائنات الثابتة وغير الثابتة (أعضاء الفئة). اسمحوا لي أن أذكرك مرة أخرى أن أعضاء الفصل الثابت ينتمون مباشرة إلى الفصل، وليس إلى مثيله. أي أن قيمة المتغير الثابت count
ستكون هي نفسها لجميع الكائنات من النوع Counter
. لاحقًا في هذه المقالة، سنلقي نظرة على الجوانب الأساسية لاستخدام المعدل الثابت في Java، بالإضافة إلى بعض الميزات التي ستساعدك على فهم مفاهيم البرمجة الأساسية.
ما يجب أن يعرفه كل مبرمج عن المعدل الثابت في Java
في هذا القسم، سنلقي نظرة على أساسيات استخدام الأساليب والحقول والفئات الثابتة. لنبدأ بالمتغيرات.-
لا يمكنك الوصول إلى الأعضاء غير الثابتين في الفصل ضمن سياق ثابت، مثل الطريقة أو الكتلة. سيؤدي تجميع الكود أدناه إلى حدوث خطأ:
public class Counter{ private int count; public static void main(String args[]){ System.out.println(count); //compile time error }}
وهذا أحد الأخطاء الأكثر شيوعًا التي يرتكبها مبرمجو Java، وخاصة المبتدئين. نظرًا لأن الطريقة
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
. بصراحة، يعد هذا أحد الأسئلة الأكثر شيوعًا فيما يتعلق بالتسلسل في مقابلات Java. لا تقم بتخزين البيانات الأكثر أهمية حول كائن ما في حقل ثابت! -
وأخيرا، دعونا نتحدث عن
static import
. يحتوي هذا المعدل على الكثير من القواسم المشتركة مع العامل القياسيimport
، ولكن على عكسه، فهو يسمح لك باستيراد واحد أو كل الأعضاء الثابتين للفئة. عند استيراد الأساليب الثابتة، يمكن الوصول إليها كما لو تم تعريفها في نفس الفئة، وبالمثل عند استيراد الحقول، يمكننا الوصول إليها دون تحديد اسم الفئة. تم تقديم هذه الميزة في Java الإصدار 1.5، وعند استخدامها بشكل صحيح، تعمل على تحسين إمكانية قراءة التعليمات البرمجية. غالبًا ما يتم العثور على هذا البناء في اختبارات JUnit ، لأن يستخدم جميع مطوري الاختبارات تقريبًاstatic import
أساليب التأكيد، على سبيل المثال،assertEquals()
والنسخ المكررة المحملة بشكل زائد. إذا لم يكن هناك شيء واضح، مرحبا بكم للحصول على معلومات إضافية .
GO TO FULL VERSION