Цель лабораторной работы: изучить теоретические вопросы, связанные с использованием статических полей в классах Java. Создать класс, позволяющий хранить уникальные данные в одном или нескольких полях.
В Java есть статические поля и статические методы. Для указания того, что поле или метод являются статическими, используется описатель static перед именем типа поля или метода. Например,
class SomeClass { static int t = 0; // статическое поле . . . public static void f() { // статический метод . . . } }
Для поля описатель static означает, что такое поле создается в единственном экземпляре вне зависимости от количества объектов данного класса. Статическое поле существует даже в том случае, если не создано ни одного экземпляра класса. Статические поля класса размещаются VM Java отдельно от объектов класса в некоторой области памяти в момент первого обращения к данному классу.
Рассмотрим это на примере 1
// Демонстрация статических полей класса public class Proba2 { int a = 10; // обычное поле static int cnt = 0; // статическое поле public void print() { System.out.println("cnt=" + cnt); System.out.println("a=" + a); } public static void main(String args[]) { Proba2 obj1 = new Proba2(); cnt++; // увеличим cnt на 1 obj1.print(); Proba2 obj2 = new Proba2(); cnt++; // увеличим cnt на 1 obj2.a = 0; obj1.print(); obj2.print(); } }
В данном примере поле cnt является статическим. При печати обоих объектов в конце метода main (...) будет отпечатано одно и то же значение поля cnt . Это объясняется тем, что оно присутствует в одном экземпляре.
По аналогии со статическими полями, статические методы не привязаны к конкретному объекту класса. При вызове статического метода перед ним можно указать не ссылку, а имя класса. Например,
class SomeClass { static int t = 0; // статическое поле . . . public static void f() { // статический метод . . . } }. . . SomeClass.f();. . .
Поскольку статический метод не связан с каким либо объектом, внутри такого метода нельзя обращаться к нестатическим полям класса без указания объекта перед именем поля. К статическим полям класса такой метод может обращаться свободно.
Это легко продемонстрировать на примере 1. Попробуем описать метод print(...) как статический. При трансляции измененной программы мы получим сообщение об ошибке в строке
System.out.println("a=" + a);
Действительно, здесь идет обращение к нестатическому полю a и, поскольку метод print(...) является статическим, то неизвестно к какому объекту относится это поле.
Если мы хотим сделать метод print(...) статическим (что, в общем-то, не соответствует общим принципам построения объектно-ориентированных программ), то мы должны определить в нем параметр типа Proba2 и использовать его для доступа к полю a .
// Демонстрация статических полей и методов класса public class Proba3 { int a = 10; // обычное поле static int cnt = 0; // статическое поле public static void print(Proba3 obj) { System.out.println("cnt=" + cnt); System.out.println("a=" + obj.a); } public static void main(String args[]) { Proba3 obj1 = new Proba3(); cnt++; // увеличим cnt на 1 Proba3.print(obj1); Proba3 obj2 = new Proba3(); cnt++; // увеличим cnt на 1 obj2.a = 0; print(obj1); print(obj2); } }
Обратим внимание на то, что при первом вызове print(...) перед ним указано имя класса, а в двух других случаях print(...) вызывается без каких-либо уточнителей. В действительности и при первом вызове мы могли не ставить префикс "Proba3.", поскольку мы вызываем статический метод класса из другого метода класса, а при этом указывать имя объекта или класса не обязательно.
Статические методы используются достаточно часто. В составе стандартной библиотеки Java есть целые классы, в которых все методы статические (Math, Arrays, Collections).
Теперь рассмотрим примеры, связанные со статическими полями. Например, приведем простой класс Body, предназначенный для хранения сведений о небесных телах:
Class Body {public long idNum;public String nameFor;public Body orbits; public static long nextID=0;
Наша задача – обеспечить уникальность номеров небесных тел. Для этого, например, придется использовать следующие конструкции:
Body Sun = new Body ();Sun.idNum=Body.nextID++;Sun.nameFor=”Sol”;Sun.orbits=null; Body Earth=new Body();Earth.idNum=Body.nextID++;Earth.nameFor=”Earth”;Earth.orbits=sun;
Наша цель уже достигнута. Можете проверить: все создаваемые небесные тела будут иметь уникальный идентификатор idNum. Однако приведенная методика довольно громоздкая. Мы уже знаем, что можно создать конструктор, в котором полям будут присваиваться необходимые значения:
Body(){IdNum=nextID++;}
Таким образом, одно из применений статических полей – уникальные идентификаторы для определенного класса.
ЗАДАНИЕ: создать два класса. В первом классе реализовать хотя бы один статический метод (можно реализовать вычисление какой-либо формулы). Во втором классе реализовать уникальный идентификатор при помощи статического поля. Создать экземпляры класса, сохранять создаваемые экземпляры класса в текстовом файле. Реализовать во втором классе не менее двух методов (возвращающих либо не возвращающих значение).
Примеры заданий:
Создать класс, описывающий абонента телефонной книги в сотовом телефоне. Свойства: порядковый номер, Фамилия, Имя, номер телефона. Порядковый номер абонента должен быть уникальным (автоинкрементным), его реализация должна быть выполнена с помощью статического поля. Увеличение номера рекомендуется производить в конструкторе. Создать экземпляры класса. Реализовать добавление вновь создаваемого абонента в текстовый файл “абоненты.txt”.
Создать класс, описывающий mp3-плеер. Свойства класса: уникальный идентификатор, емкость памяти, марка, комплектация наушниками (логическое поле). Уникальный идентификатор должен иметь следующий вид: PlayerIDxxx, где xxx – уникальный цифровой порядковый номер (i.e. первый плеер имеет идентификатор PlayerID1, второй – PlayerID2, etc.). Реализация идентификатора должна быть выполнена в конструкторе с помощью статического поля. Создать экземпляры класса. Сделать добавление сведений о вновь создаваемом объекте в текстовый файл.
Создать класс, описывающий беспроводной адаптер. Свойства: уникальный идентификатор, интерфейс (USB, PCI, etc.), цена, скорость работы (Mbit/s), протокол передачи. Уникальный идентификатор должен иметь вид WFIDxxx, где xxx – уникальный цифровой порядковый номер (i.e. первый адаптер имеет идентификатор WFID1, второй – WFID2, etc.). Реализация идентификатора должна быть выполнена в конструкторе с помощью статического поля. Создать экземпляры класса. Сделать добавление сведений о вновь создаваемом объекте в текстовый файл.
Создать класс, описывающий выпускаемые прямоугольные конструкционные листы стали. Подразумеваем, что у каждого листа будет свойство, описывающее уникальный идентификатор, соответствующий порядковому номеру и имеющий вид: LISTxxx, где xxx – цифровой идентификатор – номер (i.e. первый лист имеет идентификатор LIST1, второй – LIST2, etc.). Реализация идентификатора должна быть выполнена в конструкторе с помощью статического поля. Остальные свойства – длина и ширина. Реализовать метод, вычисляющий площадь и возвращающий значение. Создать экземпляры класса. Записывать информацию о каждом вновь создаваемом объекте в текстовый файл.
Создать класс, описывающий сотовый телефон. Подразумеваем, что у каждого телефона будет свойство, описывающее уникальный идентификатор, соответствующий порядковому номеру и имеющий вид: IMEIxxx, где xxx – цифровой идентификатор – номер (i.e. первый телефон имеет идентификатор IMEI1, второй – IMEI 2, etc.). Реализация идентификатора должна быть выполнена в конструкторе с помощью статического поля. Остальные свойства – модель, масса, заряд батарей телефона. Реализовать метод звонка, уменьшающий значение заряда батарей. Создать экземпляры класса. Записывать информацию о каждом вновь создаваемом объекте в текстовый файл.