Basic OOP Concepts (Repetition)

Lecture



Basic OOP Concepts (Repetition)

Attention! At this stage of training you should already have knowledge of this topic. If they are not, and materials for repetition are incomprehensible or insufficient, you will not cope with tasks! It is urgent to refer to the literature on this topic.

Related Literature:

1. Grady Buch. Object-oriented analysis and design.

Object Oriented Programming in Java

Classes and objects

Java is a completely object-oriented language, therefore, as we have already noted, all actions performed by the program are in the methods of various classes.

The class description begins with the class keyword, followed by an identifier - the name of the class. Then in curly brackets are listed attributes and methods of the class. Attributes in the Java language are called fields (we will use this name in the following). Fields and methods are called class members .

Fields are described as ordinary variables.

The rules for writing methods were discussed in the previous lesson.

For example, we describe the class Dog . He will have two fields: the nickname and age. When describing the behavior of a dog in this simple example, we limit ourselves to barking. Of course, our dog will not really bark (after all, this is just a software design), it will output the woo-woof console. To make it more interesting, suppose that all the dogs with which our program deals are so smart that when they are forced to bark, they say “woof-woof” as many times as they are.

Note that the program already has one class (the one in which the main() method is described). Since this class has nothing to do with dogs, the Dog class should be described beyond its limits.

class Dog { int age; // возраст int age; // возраст String name; // кличка String name; // кличка public void voice() { for (int i = 1; i <= age; i++) { System.out.println("гав-гав"); } } }

The most important thing is to understand what it means when some variables (fields) and functions (methods) are collected (described) in a class .

The class should describe some complete concept. This may be a concept from the program domain (dog, bicycle, aquarium, session) or a concept necessary for the program itself (queue, list, line, window, button, program *).

The fields of the class must be data related to this concept. For a dog, this is age, name, breed, etc., and for a session, the start date, duration, etc.

Class methods usually work with data of this class. For example, the voice() method in our example refers to the age field.

When a class is described, objects of this class can be created and you can work with them by calling their methods (to feed the dog, to walk, to ask him to bark - to do everything that the behavior of the class, that is, the totality of its methods) allows.

To refer to objects, it is convenient to use variables that have a class type . For example, to work with dogs, we will describe a variable of type Dog :

Dog x;

The variable of the class type is a reference variable; it does not store data (as variables of simple types int, char, etc.), but points to the place in memory where this data is stored (as variables of an array type). The data pointed to by the variable x just described can be an object of the class Dog . You must first create it with the new command:

x = new Dog();

Now the variable x points to a certain object of the class Dog that stores its data (age and name) in the memory. In addition, this dog can be forced to bark by calling the appropriate method with the command:

x.voice();

In order to access a member of a class, you must specify its name after the object name through a dot.

Notice that the dog that was pointed to by the variable x “barked”. If other dogs were created in the program, they will be silent until their voice() method has been called.

Thus, when data (fields) and commands (methods) are described in the same class, they are closely related to each other in the objects of this class. The method is not called by itself, but for a specific object and works with the fields of this particular object.

Therefore teams

voice(); age += 1;

do not make any sense if used outside the methods of the class Dog . It is necessary to indicate the specific object with which the action is performed. Inside the method, an indication of a specific object is not at all necessary: ​​in the considered example, the entry

for (int i = 1; i <= age; i++)
about the keyword this

means that to determine the “duration” of a barking, the age of the very object for which this method will be called will be checked. This object is denoted by the this keyword.

The voice() method could be described like this:

public void voice() { for (int i = 1; i <= this.age; i++) { System.out.println("гав-гав"); } }

The keyword this in this example clearly indicates that the age attribute is used for the very object of the Dog class for which the voice() method is called.

When the name of a method or attribute is written without specifying an object, this is always implied.

Class constructors

A constructor is a special class method that is automatically called when objects of this class are created. The name of the constructor is the same as the class name.

For example, in the class Dog can be a constructor with two parameters, which, when creating a new dog, allows you to immediately set its nickname and age.

public Dog(String n, int a) { name = n; age = a; }

The constructor is called after the new keyword at the time the object is created. Now that we have such a constructor, we can use it:

Dog dog1 = new Dog("Тузик", 2);

As a result, the variable dog1 will indicate a “dog” named Tuzik, which is 2 years old. By the way, this age can be found by forcing the dog to bark as a team.

dog1.voice();*

Constructors are added to a class if at the time of creating an object you need to perform some actions (initial setup) with its data (fields). Immediately ask the nickname and age of the dog more naturally than spawn a nameless puppy each time, and then give it a name and quickly grow to the desired age (given that the program most likely processes data about dogs that have actually been born for a long time). Although before the PLO, programmers often did just that.

Inheritance

Inheritance is a relationship between classes, in which one class extends the functionality of another. This means that he automatically adopts all of his fields and methods, and also adds some of his own.

Inheritance usually occurs when all objects of one class are at the same time objects of another class (public / private relation). For example, all objects of the class Студент are objects of the class Человек . In this case, it is said that the class Студент inherits from the class Человек . Similarly, the Собака class can inherit from the Животное class, and the Далматинец class from the Собака class. A class that inherits is called a subclass or descendant , and a class from which it is inherited is called a superclass or ancestor .

Note that if class No. 2 is a descendant of class No. 1, and class No. 3 is a descendant of class No. 2, then class No. 3 is also a descendant of class No. 1.

Inheritance saves the programmer from unnecessary work. For example, if in the program it is necessary to introduce a new Далматинец class, it can be created on the basis of the already existing class Собака , without re-programming all the fields and methods, but only adding those that were not enough in the superclass.

In order for one class to be a descendant of another, it is necessary, when declaring it, after the class name, indicate the keyword extends and the name of the superclass.

For example:

class Dalmatian extends Dog { // дополнительные поля и методы ... }
about class Object

If the extends keyword is not specified, it is assumed that the class is inherited from the generic Object class.

The inheritance hierarchy begins with the Object class. Any other class is a descendant of the Object class and inherits three methods from it:

equals(Object obj) - allows you to compare two objects. Returns true if objects are equal. For example, we compared strings (objects of class String ):

if (s1.equals(s2)) { ... }

toString() - "translates" an object into a string (which can be displayed in the println() method).

hashCode() - returns an integer that is unique for all objects of this class (there cannot be two objects for which this number is the same).

When inheriting, these methods most often need to be redefined in order for them to work as the programmer needs. For details on overriding, see below.

Visibility modifiers

Access to any class member — field or method — may be restricted. To do this, before his announcement is put the keyword private. It means that this member of the class cannot be accessed from the methods of other classes.

The public keyword can be used in the same cases, but it has the opposite meaning. It means that the given member of the class is available. If it is a field, it can be used in expressions or modified by assignment, and if it is a method, it can be called.

The protected keyword means that the class and all its descendants have access to the field or method.

If when declaring a member of a class, none of the listed modifiers is specified, the default modifier is used. It means that all classes declared in the same package have access to the class member.

Rewrite the Dog class as follows:

class Dog { private int age;// возраст private String name; // кличка private String name; // кличка public Dog(String n, int a) { name = n; age = a; name = n; age = a; } public void voice() { for(int i = 1; i <= age; i++) { System.out.println("гав-гав"); } } }

Fields age and name will be hidden. This means that we cannot change them (or read their meaning) anywhere outside the class *. We can’t create an object of the Dog class in the main() method and then assign it a new value to the age or name field, as in the following example:

public static void main(String[] args) { Dog dog1 = new Dog("Тузик", 4); dog1.age = 10; // нельзя, поле age скрыто dog1.age = 10; // нельзя, поле age скрыто dog1.name = "Жучка"; // переименовать собаку тоже нельзя, поле name скрыто dog1.name = "Жучка"; // переименовать собаку тоже нельзя, поле name скрыто dog1.voice(); // это можно, метод voice() открытый dog1.voice(); // это можно, метод voice() открытый }

The ability to hide fields and class methods is used to save the programmer from possible errors, to make the classes clearer and easier to use. In this case, the principle of encapsulation is implemented.

about encapsulation

Encapsulation means hiding the details of a class implementation. The class is divided into two parts: internal and external. The external part (interface) is carefully thought out on the basis of how other program objects can interact with objects of this class. The interior is closed to strangers, it is needed only by the class itself to ensure the correct operation of the open methods.

For example, in the class Dog there is an integer field age (age). You can leave it open, then it can be changed if necessary by a simple assignment (very convenient). But at the same time, nothing prevents you from assigning a deliberately incorrect value to this field (for example, 666 or -5 or 3000). This may occur due to an error in the program. Or, for example, the user enters the age of the dog in the text field, and the program assigns it in response to a button click (and the user may be mistaken). This is an undesirable case. It is better to make the age field closed (private) and add two public methods: getAge() and setAge() . The first method will simply return the value of the hidden field:

public int getAge() { return age; }

The second method will allow you to specify the new age of the dog, while checking the assigned value.

public void setAge (int newAge) { if (newAge < 0) System.out.println("Как это понимать? Собака еще не родилась?"); else if (newAge > 30) System.out.println("Они столько не живут"); else age = newAge; }

Now we see that the age can be changed only by calling the setAge() method, which in the case of an inappropriate parameter will output a message to the console and will not change anything.

Professional programmers who develop programs using an object-oriented methodology hide all fields of their classes, creating open methods for each of them with the get and set prefixes, and all the necessary checks are carried out in the set methods.

Finally, we note that in our example, the wrong age can “break through” through the constructor when creating a new object. No one bothers to write:

Dog dog1 = new Dog("Тузик", 2000);

To prevent this from happening, you need to rewrite the constructor:

public Dog(String n, int a) { name = n; age = setAge(a); }

Now the check is carried out in the constructor. An attempt to get a dog with obviously incorrect data in the program will not be crowned with success. If the age is less than 0 or greater than 30, the assignment will not be executed and the age attribute will have a default value (for the type int it is 0). Such a little doggy ...

Exercise

Our class Dog contains a fundamental error. It has a hidden name field, which can be assigned an initial value during the creation of an object, but cannot be changed or even found out afterwards. Write the getName() and setName() methods. No checks are needed.

Overload

In one class, you can create several methods with the same name, differing in their parameters. This technique is called method overloading. When one of these methods is called, a comparison of the parameters passed to it (their number and types) with the parameters of all the methods of the class with the same name will occur. If a suitable method is found, it will be executed.

For example, in addition to the constructor that is already in the Dog class, we can describe a constructor without parameters:

public Dog() { name = "Незнакомец"; }

In this constructor, the object of the class Dog (obviously, a dog with an unknown nickname) is assigned the name "Stranger" when registering in the program. Now we can use one of two constructors:

Dog dog1 = new Dog("Тузик", 2); // Собака по кличке Тузик, возраст 2 года Dog dog1 = new Dog("Тузик", 2); // Собака по кличке Тузик, возраст 2 года Dog dog2 = new Dog(); // Собака по кличке «Незнакомец», возраст 0 Dog dog2 = new Dog(); // Собака по кличке «Незнакомец», возраст 0 Dog dog3 = new Dog(10); // Неверно! Не существует конструктора с такими параметрами Dog dog3 = new Dog(10); // Неверно! Не существует конструктора с такими параметрами

You cannot create several methods of the same name with the same number and type of parameters.

Exercise

Add a third constructor to the Dog class for cases where the age is known, but the unknown dog's nickname so that the third command in the example makes sense.

Polymorphism

Polymorphism is the ability of a class to act as any of its ancestors in a program, despite the fact that the implementation of any method can be changed in it.

To change the operation of any of the methods inherited from the ancestor class, the descendant class can, by describing a new method with the exact same name and parameters. This is called overriding . When calling such a method for a descendant class object, a new implementation will be executed.

Suppose, for example, we want to extend our Dog class to the BigDog class in order for our program to model in a special way the behavior of big evil dogs. In particular, large dogs bark differently. First, louder, and secondly, they do not know how to count. Therefore, we will override the voice() method:

class BigDog extends Dog { public void voice() { for (int i = 1; i <= 30; i++) { System.out.print("ГАВ-"); } } }

Now we’ll create two different dogs in the main() method: normal and big and make them bark.

Dog dog = new Dog("Тузик", 2); dog.voice(); BigDog bigdog = new BigDog(); bigdog.voice();

An object of a subclass will always be simultaneously an object of any of its superclasses. Therefore, in the same example, we could manage with one variable:

Dog dog = new Dog("Тузик", 2); dog.voice(); dog = new BigDog(); dog.voice();
about the impressive possibilities of polymorphism

Those. The dog variable is of type Dog , but in the third line it starts pointing to an object of class BigDog , that is, a BIG dog, which, when calling the voice() method, will bark like a BIG dog. This is one of the impressive features of object-oriented programming.

Programming techniques: inheritance and polymorphism

The main advantage of polymorphism is the ability to work with objects of different classes, originating from one common ancestor, as if they belonged to the same class.

Consider a typical example.

Suppose we are developing a drawing program. In this program, the user can create various shapes: triangles, rectangles, circles, points. At the same time, it is not known in advance how many and what kind of figures he will create. *

From time to time the program must perform some actions on these figures. For example, when the program window is minimized, and then unfolds again, you need to re-draw all these shapes. When the user clicks on the figure with the mouse, it must be highlighted, and when the user drags the borders of the shape, resize it.

Adhering to the methodology of object-oriented programming, we conclude that each figure must draw itself "itself." That is, the commands for drawing a circle are executed in one of the methods of the Circle class, for example, in the paint() method. Indeed, all the parameters of the figure should be stored in the fields of its class, so you can easily write such a method. Similarly, the figure "itself" draws a selection for itself - for this there is a paintSelection() method - and it moves - the move(int x, int y) method. The task of the main program is to simply refer to these methods if necessary.

The program must somewhere store the objects that the user creates. Since it is not known in advance how many of these objects there will be, it is necessary to use some structure to store a set of objects, for example, an array. But when creating an array, you need to specify the type of its elements. And in our program, the user can create a variety of objects. So you have to get several arrays: one for points, one for circles, and so on. If you need to re-draw all the objects on the screen, you will need to loop through all the elements in each of these arrays:

for (int i = 0; i < points.length; i++) { points[i].paint(); } for (int i = 0; i < circles.length; i++) { circles[i].paint(); }

... and so on, for each type of shape.

Moreover, if the user clicks the screen to select a shape, the program that receives the coordinates of the mouse must find the shape in which these coordinates fall. Suppose each shape itself can check using the checkPoint(int x, int y) method, which returns true if the point with x, y coordinates is inside this shape. But in order to call this method, you will have to loop through all the arrays again. And so for each operation, which is very inconvenient.

Thanks to inheritance, we have two excellent possibilities. In order to use them, we need to create a class Figure and describe in it methods common to all shapes: paint() , checkPoint(int x, int y) and so on. It is not necessary to program these methods, we will not contact them anyway. * It is important that they be.

First possibility: we can assign objects of descendant classes to variables of any of the ancestor classes .

This is quite logical. After all, if the Кошка class is inherited from the Животное class, then the object Мурзик is both an object of the Кошка class and an object of the Животное class.

Therefore, we can create one large array * for storing objects of the class Figure :

Figure[] figures = new Figure[100]; // создаем массив для хранения 100 фигур

Теперь мы можем помещать в этот массив любые фигуры:

figures[0] = new Point(30, 30); // добавили в массив точку с координатами 30, 30 figures[1] = new Circle(60, 20, 10); // добавили круг с координатами 60, 20 радиуса 10 figures[2] = new Rectangle(0, 0, 30, 40); // добавили прямоугольник ...

Вторая возможность. Мы можем обращаться к методам, объявленным в классе-предке, но вызываться будет перегруженный метод, в зависимости от того, к какому классу на самом деле относится объект, к которому мы обратились .

Мы можем нарисовать все фигуры, хранящиеся в нашем массиве:

for (int i = 0; i < figures.length; i++) { if (figures[i] != null) figures[i].paint(); }

В массиве хранятся элементы типа Figure . В этом классе есть метод paint() , поэтому мы вполне можем к нему обратиться. Но в самом классе Figure этот метод не делает ничего (ведь мы не могли разработать процедуру рисования, подходящую для всех без исключения фигур). Зато в классе Point , унаследованном от класса Figure , мы переопределили этот метод — написали его заново так, чтобы он рисовал точку (координаты точки хранятся в скрытых атрибутах класса Point ). А в первом элементе массива figures[0] у нас хранится именно точка. Хотя мы обращаемся с ней как с просто фигурой, Java знает, что при вызове метода paint() нужно использовать именно тот вариант, который переопределен в классе Point . Аналогично команда figures[1].paint(); нарисует круг, а figures[2].paint(); нарисует прямоугольник.

Мы рассмотрели очень подробный пример, поскольку описанный прием является одним из наиболее часто используемых средств в арсенале объектно-ориентированного программирования.

Конструктор по умолчанию

Если в классе не описан ни один конструктор, для него автоматически создается конструктор по умолчанию. Этот конструктор не имеет параметров, все что он делает — это вызывает конструктор без параметров класса-предка.

Поэтому мы и смогли создать объект класса BigDog в примере с большой собакой, хотя не описывали в классе никаких конструкторов. Если вспомнить конструктор без параметров, который у нас есть в классе Dog , мы поймем, что переменная bigdog в предыдущем примере ссылалась на собаку по кличке "Незнакомец".

Вызов конструктора суперкласса

In the example with a large dog, we managed to create it using a constructor without parameters, i.e. without specifying her name and age. It turns out that if we tried to do it differently, we would not have succeeded. The fact is that constructors are not considered members of the class and, unlike other methods, are not inherited.

BigDog bigdog = new BigDog("Полкан", 8); // Ошибка. Такого конструктора в классе нет

In order for us to create large dogs with a name and age that interests us, it is necessary to write a suitable constructor. In this case, it is not necessary to repeat the commands that we wrote in the class constructor Dog(there are only two of them, but there could have been much more). Instead, we can write:

BigDog (String n, int a) { super(n, a); }

The keyword super means superclass (in our case it is a class Dog). In the example, we call with it the superclass constructor. In this case, we pass two parameters — a string and a number — so that of all the constructors, the one that interests us will be chosen.

The call to the superclass constructor should occur at the very beginning of the constructor.

Instead of calling the superclass constructor, you can call one of the constructors of the same class. This is done using a keyword this()- with parameters in brackets, if needed.

If there is neither a call this()nor a call at the beginning of the constructor , the super()constructor of the superclass without arguments is automatically called .

Cast

Объект класса-потомка можно присвоить переменной типа класса-предка. При этом Java производит автоматическое преобразование типа, называемое расширением. Расширение — это переход от более конкретного типа к менее конкретному. Переход от byte к int — это тоже расширение.

Рассмотрим пример, имеющий отношение к основному заданию. В программе есть класс User , предназначенный для обработки информации о пользователях системы. В этом классе есть метод enter(String login, String password) , который возвращает true, если переданные в метод логин и пароль совпадают с логином и паролем, скрытым в полях класса.

Мы наследуем от класса User два подкласса: Admin и, к примеру, Member (для программы координации участников встречи, см. задание 13). Класс Admin может понадобиться нам впоследствии для каких-то специфичных действий, связанных с управлением системой, а класс Member моделирует участников проекта, которые с помощью программы пытаются выбрать оптимальное место для встречи. Открытый метод addRequest(String place, int day, int from, int to) вызывается, когда участник проекта предлагает новый вариант времени и места встречи.

В главном классе программы мы храним массив* users , содержащий всех пользователей системы. Элементы этого массива имеют тип User , но мы можем присваивать им ссылки на объекты как класса Member , так и класса Admin . В этот момент и будет происходить расширение типа.

Member member = new Member(...); users[3] = member; // Java проводит автоматическое преобразование типа Member к типу User, чтобы поместить переменную member в массив users

Для того, чтобы найти пользователя с введенными логином и паролем программа выполняет запрос:

for (int i = 0; i < users.length; i++) { if (users[i].enter(log, passw)) currentUser = users[i]; }

Несмотря на то, что все объекты, добавленные в массив, сохраняют свой "настоящий" класс, программа работает с ними как с объектами класса User . Этого вполне достаточно, чтобы можно было найти нужного пользователя по логину и паролю (ведь метод enter() у них общий) и присвоить найденный объект переменной currentUser типа User . В этой переменной хранится текущий пользователь, авторизовавшийся в системе.

Предположим, нам известно, что переменная currentUser сейчас ссылается на объект класса Member и текущий пользователь предлагает встретиться у фонтана в среду с 17 до 19 часов. Необходимо вызвать метод addRequest() , но у нас не получится сделать это командой

currentUser.addRequest("Фонтан", 3, 17, 19);

поскольку в классе User нет метода addRequest() .

Однако мы можем осуществить явное преобразование переменной currentUser к типу Member . Такое преобразование (переход от менее конкретного типа к более конкретному) называется сужением . Явное преобразование делается с помощью оператора, представляющего собой имя целевого типа в скобках.

((Member)currentUser).addRequest("Фонтан", 3, 17, 19);

Здесь мы, прежде чем вызвать метод addRequest() , преобразовали переменную currentUser к типу Member . Нам было позволено сделать это, поскольку Member является потомком User . Однако, если бы во время выполнения программы оказалось, что на самом деле переменная currentUser не ссылалась на объект класса Member , в программе возникла бы ошибка.

Оператор instanceof

Чтобы уточнить, соответствует ли текущее значение переменной конкретному типу, используется оператор instanceof.

Проверим, не является ли текущий пользователь администратором (в этом случае программа должна перейти в режим управления):

if (currentUser instanceof Admin) {...}

Анонимные и вложенные классы

о вложенных классах

Внутри фигурных скобок, заключающих в себе тело одного класса, помимо описания его полей и методов можно поместить описание другого класса. Он будет называться вложенным классом .

Эта возможность иногда используется, чтобы подчеркнуть отношение агрегации между классами. Например, нам может понадобиться класс Eye , чтобы описать сложную структуру и поведение глаза (он может открываться и закрываться). Но объекты этого класса не будут создаваться сами по себе, они являются неотъемлемой частью объектов класса Dog и только их. Поэтому мы помещаем описание класса Eye в класс Dog :

class Dog { ... class Eye { private boolean opened; public void close() { opened = false; System.out.println("глаз закрыт"); } public void open() { opened = true; System.out.println("глаз открыт"); } public boolean isOpened() { return opened; } } Eye rightEye = new Eye(), leftEye = new Eye(); }

Мы сразу же добавили в класс Dog два поля класса Eye и проинициализировали их вновь созданными объектами (это можно было сделать и в конструкторе). Теперь у собаки есть два глаза и она может открывать их и закрывать. Например, предположим, что все собаки лают с закрытым правым глазом. Тогда метод voice() надо переписать так:

public void voice() { rightEye.close(); for (int i = 1; i <= age; i++) { System.out.println("гав-гав"); } rightEye.open(); }

Обратиться ко вложенному классу нужно с помощью составного имени (в нашем случае это Dog.Eye ). Если обращение происходит из содержащего его класса, имя можно сократить (как и было сделано выше).

Класс можно объявить внутри метода другого класса. В этом случае класс "виден" только внутри метода (за пределами метода нельзя объявить переменную типа этого класса).

Анонимным классом называется класс, не имеющий имени. Очевидно, если у класса имени нет, к нему нельзя обратиться из программы. Точнее, это можно сделать только один раз — в том месте, где класс объявляется.

Описание анонимного класса начинается с вызова конструктора его суперкласса, после чего в фигурных скобках описывается тело класса.

Анонимные классы используются в том случае, когда нужен единственный объект такого класса на всю программу.

Пусть, например, в нашей программе собачьего питомника имеется массив dogs объектов типа Dog . И мы хотим добавить в этот массив совершенно уникальную собаку, которая не лает, а разговаривает. Необходимо описать класс, унаследованный от класса Dog , в котором будет соответствующим образом переопределен метод voice() . Но поскольку нам гарантированно понадобится только одна такая собака, мы можем описать анонимный класс прямо в месте добавления собаки в питомник (посадим ее в клетку № 10):

dogs[10] = new Dog(){ public void voice() { System.out.println("Я уникальная говорящая собака."); } };

И, несмотря на то, что мы не сможем создавать переменных этого класса, мы спокойно можем пользоваться новой собакой как объектом класса Dog . А благодаря полиморфизму вызов метода

dogs[10].voice();

приведет к тому, что уникальная собака будет уникально подавать голос.

Модификатор static

Любой член класса можно объявить статическим, указав перед его объявлением ключевое слово static. Статический член класса «разделяется» между всеми его объектами.

Для поля это означает, что любое изменение его значения, сделанное одним из объектов класса, сразу же «увидят» все остальные объекты.

Метод, объявленный с модификатором static, "дает обещание" не изменять никаких полей класса, кроме статических.

Для обращения к статическому члену класса можно использовать любой объект этого класса. Более того, это обращение можно осуществлять даже тогда, когда не создано ни одного такого объекта. Вместо имени объекта можно просто указывать имя класса.

Упражнение

Модифицируйте класс Dog таким образом, чтобы можно было считать собак, созданных во время работы программы. Для этого введите статический атрибут count (изначально равный нулю) и увеличивайте его на единицу в каждом конструкторе. Создайте в методе main() несколько объектов класса Dog , а затем выполните для проверки команду:

System.out.println("Всего было создано собак: " + Dog.count);

Модификатор final

о модификаторе final

Любое поле класса можно объявить неизменяемым, указав перед его объявлением ключевое слово final. Неизменяемому полю можно присвоить значение только один раз (обычно это делается сразу при объявлении).

Константы в языке Java очевидным образом описываются путем совмещения модификаторов static и final. Например, мы можем объявить константу PI (лучше это делать в основном классе, а не в классе Dog *), написав:

final static double PI = 3.14;

Если ключевое слово final указать перед объявлением метода, это будет обозначать, что метод нельзя переопределять при наследовании (т.е. данная версия метода будет окончательной).

Перед объявлением класса модификатор final ставится в том случае, если необходимо запретить от него наследование.

Диаграммы классов в языке UML

Attention! На данном этапе обучения вы уже должны владеть знаниями по этой теме. Если их нет, а материалы для повторения непонятны или недостаточны, вы с заданиями не справитесь! Необходимо срочно обратиться к литературе по данной теме.

Литература по теме:

1. Терри Кватрани. Rational Rose 2000 и UML. Визуальное моделирование.


additional literature

1. Вязовик Н.А. Программирование на Java. (главы 6—8)

2. Хабибуллин И.Ш. Самоучитель Java 2. (глава 2)

The task

Proceed to implement the classes of your task in accordance with the proposed diagram. In each class, write the constructors necessary to fill the class attributes (if necessary, implement a check of the parameters passed to the constructor). You should report on this assignment in session five.

created: 2014-12-11
updated: 2021-12-18
132824



Rating 9 of 10. count vote: 2
Are you satisfied?:



Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

OOP and Practical JAVA

Terms: OOP and Practical JAVA