Как переопределить метод equals java
Перейти к содержимому

Как переопределить метод equals java

  • автор:

Метод equals в Java: основные принципы и использование

Метод equals является одним из основных методов в языке программирования Java. Он позволяет сравнить два объекта на их эквивалентность. Это значит, что метод позволяет определить, являются ли два объекта одинаковыми или разными. В основе работы метода лежит сравнение значений полей объектов.

В Java все классы наследуются от класса Object, который содержит дефолтную реализацию метода equals. Однако в большинстве случаев необходимо переопределить этот метод для своих классов. Это связано с тем, что дефолтная реализация сравнивает ссылки на объекты, а не их содержимое.

Для переопределения метода equals необходимо следовать определенным правилам. Во-первых, метод должен принимать в качестве аргумента объект типа Object, так как это сигнатура метода из класса Object. Во-вторых, метод должен возвращать булево значение — true, если объекты равны, и false в противном случае.

В переопределенном методе equals необходимо сравнивать значения всех полей объектов, которые считаются важными для определения их равенства. Обычно для сравнения используются методы equals полей или операторы == для примитивных типов. Также метод должен быть устойчивым к передаче значений null, чтобы избежать исключений.

Класс Object в Java

Класс Object определяет набор методов, которые доступны для всех объектов в Java. Некоторые из наиболее часто используемых методов класса Object включают:

  • equals(): метод используется для сравнения двух объектов на равенство. По умолчанию, метод equals() сравнивает объекты по ссылке, но его можно переопределить в подклассе для определения критериев сравнения;
  • hashCode(): метод возвращает целочисленный хеш-код объекта. Хеш-код используется для оптимизации процесса поиска объектов в коллекциях данных;
  • toString(): метод возвращает строковое представление объекта. По умолчанию, возвращается строка, состоящая из имени класса и хеш-кода объекта;
  • getClass(): метод возвращает ссылку на объект класса Class, который представляет тип объекта.

Благодаря классу Object можно выполнять общие операции с любыми объектами в Java. Наследование от класса Object также позволяет использовать полиморфизм и работать с объектами разных типов единообразным способом. Например, объекты разных классов могут быть добавлены в одну коллекцию, если их типы являются подтипами типа Object.

Следует отметить, что класс Object является абстрактным классом, поэтому нельзя создать его экземпляр как таковой. Однако, любой объект созданного класса автоматически наследует методы и функционал класса Object.

Смотрите также: Дата в формате SQL: преобразование и использование

Принцип работы метода equals

Однако разработчик имеет возможность переопределить этот метод в своих классах, чтобы задать собственную логику сравнения объектов. При переопределении метода equals нужно учитывать следующие принципы:

1. Рефлексивность

Метод equals должен быть рефлексивным, то есть для любого объекта obj, вызов obj.equals(obj) должен возвращать true. Это означает, что объект всегда равен самому себе.

2. Симметричность

Если объект A равен объекту B, то и объект B должен быть равен объекту A. То есть a.equals(b) должно возвращать true тогда и только тогда, когда b.equals(a) также возвращает true.

3. Транзитивность

Если объект A равен объекту B, и объект B равен объекту C, то объект A должен быть равен объекту C. Если a.equals(b) возвращает true и b.equals(c) возвращает true, то a.equals(c) также должен возвращать true.

Все эти принципы гарантируют, что сравнение объектов будет происходить корректно и предотвращает логические ошибки при работе с объектами. При переопределении метода equals также необходимо переопределить метод hashCode, чтобы гарантировать согласованность этих двух методов.

Использование метода equals

Для переопределения метода equals в пользовательском классе нужно следовать определенным правилам. Во-первых, метод должен быть публичным и принимать в качестве аргумента тип Object. Во-вторых, он должен возвращать логическое значение true или false. И наконец, внутри метода нужно сравнивать поля объектов на равенство и возвращать результат сравнения.

При использовании метода equals важно следить за тем, чтобы объекты сравнивались корректно. Если класс имеет несколько полей, необходимо проверить равенство каждого поля. Кроме того, нужно учитывать особенности сравнения ссылочных типов данных, например, использовать метод equals для сравнения строк.

Метод equals часто используется вместе с методом hashCode, который определяет хеш-код объекта. Вместе они позволяют реализовать равенство и сохранять объекты в коллекциях, таких как HashSet или HashMap.

Сравнение ссылочных и значимых типов данных

В языке программирования Java типы данных можно разделить на ссылочные и значимые. При работе с типами данных уместно задать вопрос: как выполняется сравнение значений этих типов между собой? В Java для этого используется метод equals().

Ссылочные типы данных, такие как классы и интерфейсы, сравниваются по значению ссылки, то есть путем проверки, указывают ли две переменные на один и тот же объект или нет. Если две ссылочные переменные указывают на один объект, то метод equals() возвращает true, иначе — false.

Смотрите также: Как отключить IPv6 в Linux

Значимые типы данных, такие как примитивы (int, double, boolean и др.), сравниваются по значению, при этом метод equals() переопределен для каждого примитивного типа, чтобы выполнить адекватное сравнение значений.

Важно заметить, что ссылочный тип данных может принимать значение null, что означает отсутствие ссылки на объект. При сравнении ссылочного типа с null результат будет зависеть от реализации метода equals(). Обычно считается, что ссылка на null не равна непустой ссылке, поэтому метод equals() возвращает false для сравнения ссылочного типа с null.

Напротив, значимые типы данных не могут принимать значение null и всегда хранят какое-то значение. Поэтому, при сравнении значимого типа с null метод equals() сразу возвращает false.

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

Тип данных Сравнение с null Примеры метода equals()
Ссылочный тип данных Возвращает false String str1 = «abc»;
String str2 = null;
System.out.println(str1.equals(str2)); // false
Значимый тип данных Возвращает false int num = 10;
System.out.println(num.equals(null)); // false

Переопределение метода equals

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

Переопределение метода equals должно удовлетворять следующим условиям:

  • Метод должен быть объявлен как public и иметь возвращаемый тип boolean .
  • Метод должен принимать в качестве аргумента объект типа Object .
  • Метод должен сравнивать поля объектов и возвращать true , если поля совпадают, и false в противном случае.

Пример переопределения метода equals

Рассмотрим пример класса Person , который содержит поля name и age . Для корректного сравнения объектов этого класса по их содержимому нужно переопределить метод equals :

public class Person < private String name; private int age; // Конструкторы и методы класса @Override public boolean equals(Object obj) < if (this == obj) < return true; >if (obj == null || getClass() != obj.getClass()) < return false; >Person person = (Person) obj; return age == person.age && Objects.equals(name, person.name); > >

В данном примере мы сначала проверяем, является ли объект, с которым сравнивается текущий объект, ссылкой на самого себя. Затем сравниваем классы объектов: если они не совпадают или переданный объект является null , возвращаем false .

Если объекты принадлежат к одному классу, выполняем приведение типа и сравниваем их поля. В данном примере мы используем вспомогательный метод Objects.equals , который сравнивает строки, учитывая возможность значения null для полей имени.

Смотрите также: Python hh: разбираемся с основами

Оператор Описание
this == obj Проверка ссылок на объекты
obj == null || getClass() != obj.getClass() Проверка на null и сравнение классов объектов
return age == person.age && Objects.equals(name, person.name) Сравнение полей объектов

Теперь при использовании метода equals для объектов класса Person мы получим корректное сравнение по содержимому, а не по ссылкам на объекты.

Вопрос-ответ:

Какой принцип работы у метода equals в Java?

Метод equals в Java используется для сравнения двух объектов на равенство. Он может быть переопределен в классе и позволяет определить, что объекты эквивалентны, идентичны или отличаются.

В чем разница между оператором «==» и методом equals?

Оператор «==» сравнивает две переменные на идентичность, то есть проверяет, являются ли они ссылками на один и тот же объект. Метод equals сравнивает два объекта на равенство, то есть проверяет их содержимое.

Как правильно переопределить метод equals в классе?

Для правильного переопределения метода equals в классе необходимо выполнить несколько шагов: 1) Проверить, является ли переданный объект ссылкой на самого себя; 2) Проверить, является ли переданный объект ссылкой на null; 3) Проверить, является ли переданный объект объектом того же класса; 4) Сравнить поля классов на равенство.

Как использовать метод equals для сравнения объектов?

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

Что произойдет, если не переопределить метод equals в классе?

Если не переопределить метод equals в классе, то при его вызове будут сравниваться ссылки на объекты, а не их содержимое. Это может привести к неправильным результатам сравнения объектов.

Метод equals() в Java

Основные принципы при проектировании метода equals :

  1. Рефлексивность: для любых не-null объектов x, x.equals(x) должен возвращать true .
  2. Симметричность: для любых не-null объектов x и y, x.equals(y) должен возвращать true , если и только если y.equals(x) возвращает true .
  3. Транзитивность: для любых не-null объектов x, y, и z, если x.equals(y) возвращает true и y.equals(z) возвращает true , тогда x.equals(z) должен возвращать true .
  4. Постоянство: повторный вызов метода equals() должен возвращать одно и тоже значение до тех пор, пока какое-либо значение свойств объекта не будет изменено. То есть, если два объекта равны, то они будут равны пока их свойства остаются неизменными.
  5. Для любых не-null объектов x, x.equals(null) должно возвращать false .

Также стоит обратить внимание на то, что аргументом метода equals всегда является объект класса Object . Например, переопределяя метод для класса Person , мы должны использовать следующую сигнатуру: public boolean equals(Object person) . Зачастую начинающими допускается ошибка и используется сигнатура public boolean equals(Person person) , что приводит к перегрузке метода equals .

Метод equals взаимосвязан с методом hashCode : для одинаковых объектов значение, возвращаемое методом hashCode , должно быть одинаково. Поэтому зачастую переопределяются оба метода.

Отслеживать
ответ дан 20 янв 2016 в 10:25
Pavel Parshin Pavel Parshin
9,239 1 1 золотой знак 27 27 серебряных знаков 48 48 бронзовых знаков

Приведу пример, по которому все будет понятно, также не надо забывать, что при переопределении метода equals() необходимо переопределить метод hashCode(). Если метод equals() возвращает истину для двух объектов, то их хэш-код должен быть одинаковым. Обратное утверждение не верно.

TestClass < private int id; public boolean equals(Object other) < if(!super.equals(other)) return false; if (this == other) return true; if (other == null) return false; if(this.getClass() != other.getClass()) return false; TestClass otherObj = (TestClass)other; return this.id == otherObj.id; >public int hashCode() < return 76+133*id; >> 

Отслеживать
ответ дан 8 дек 2010 в 19:25
Nicolas Chabanovsky Nicolas Chabanovsky
51.4k 87 87 золотых знаков 267 267 серебряных знаков 508 508 бронзовых знаков

Имеем простой класс такой структуры:

class A

Такой метод определения метода equals будет подойдет во многих ситуациях:

public boolean equals(Object other) < // Не строго необходимо, но обычно неплохо для оптимизации if (this == other) return true; if (!(other instanceof A)) return false; A otherA = (A) other; return (someNonNullField.equals(otherA.someNonNullField)) && ((someOtherField == null) ? otherA.someOtherField == null : someOtherField.equals(otherA.someOtherField))); >

Действительно нельзя забывать о методе hashCode. сойдет такая его реализация:

public int hashCode()

Более подробно написано с этой статье от ibm deweloperworks.

Отслеживать
ответ дан 21 янв 2011 в 18:50
1,036 8 8 серебряных знаков 27 27 бронзовых знаков

Вариант использования equals при наследовании. Пусть есть класс точка

public class Point < private int x; private int y; public Point(int x, int y) < this.x = x; this.y = y; >public boolean equals(Object obj) < if (obj == null) return false; // проверка на случай, если сравнение с самим собой if (obj == this) return true; if (obj.getClass() == this.getClass()) < Point point = (Point) obj; if (point.x == this.x && point.y == this.y) return true; >return false; > > 

Теперь пришла в голову мысль написать расширение Point3D и для него также переопределить метод equals

public class Point3D extends Point < private int z; public Point3D(int x, int y, int z) < super(x, y); this.z = z; >public boolean equals(Object obj) < if (super.equals(obj)) < /* * строки не нужны: эти проверки выполняется в базовом классе * if (this == other) return true; * if (other == null) return false; * if(this.getClass() != other.getClass()) return false; */ Point3D p3d = (Point3D) obj; if (p3d.z == this.z) return true; >return false; > > 

Отслеживать
51.4k 87 87 золотых знаков 267 267 серебряных знаков 508 508 бронзовых знаков
ответ дан 20 дек 2010 в 8:09
530 3 3 серебряных знака 4 4 бронзовых знака

Прошу пояснить код. В частности, вот эту строку

if (!super.equals(other)) return false; 

Основной вопрос состоит в следующем. Как Вы думаете, что делает эта строчка процитированного кода? Да, там вызывается метод equals родительского класса. А кто у нас у класса в данном случае родитель? Если верить спецификации, то это java.lang.Object. Значит сначала мы в первой строке Вашего кода вызываем метод equals класса Object. Как Вы думаете, что он делает? Вроде как это известная информация, но для большей достоверности вот цитата из исходников

public boolean equals(Object obj)

То есть он возвращает true только в том случае, когда у нас ссылки на объект совпадают. Если же у нас 2 отдельных объекта, которые хранятся в памяти в разных местах (пусть у них содержимое одинаковое), ссылки на них не совпадают! А что это значит? Это значит, что благодаря строке if(!super.equals(other)) return false; Ваш метод equals будет возвращать true , только если мы будем сравнивать объект сам с собой! Наверное, это не то, чего бы всем хотелось, не так ли? Думаю, эту строку надо убрать и тогда это будет больше похоже на правду. Но вообще каждый раз при написании своего equals надо принимать во внимание тот факт, что когда-то создатели Java и класса java.lang.Object в частности написали условия, которым должен удовлетворять переопределённый метод equals, найти их можно в исходниках, либо здесь.

И ещё заметка относительно hashCode . Вы упомянули только одно из требований котракта по hashCode : если 2 объекта считаются равными (equals возвращает true), то hashCode для них должен возвращать одинаковое значение. Дальше

на самом деле в контракте, найти можно — здесь стоит продолжение: «However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables». То есть надо принимать этот факт во внимание, как и ещё один пункт из этого же контракта.

Как переопределить метод equals java

Мне одному кажется, что в Уровне 3 Лекции 9, было более чем предостаточно информации на эту тему? Но большое спасибо автору за старание!�� И в самом конце статьи узнал что-то новое.

17 марта 2024

Тоже не понял почему автор переопределяет метод equals() и почему у него первый раз вывело false при сравнении «днк». В целом материал статьи полностью копирует информацию из лекции Уровень 3 Лекция 9. Единственное что в кратце автор написал про intern. ��‍♂️

Сергей Дубакин Уровень 13 Expert
17 марта 2024
Молодец. Отличная статья ������
23 января 2024
Евгений Уровень 6 Expert
18 января 2024

Не совсем понятно. В начале автор говорит, что «Внутри метода equals() класса Object лежит то же самое сравнение ссылок, ==. » — поэтому сравнивая строки он получает false. Потом он переопределяет метод. А далее пишет, что метод equals сравнивает не адреса в памяти, поэтому следует использоваиь его. Как, блин, так? о_О

16 октября 2023

Для прояснения ситуации для себя (не всё было разобрано в лекции) — попробовал выполнить такой код: String s1 = new String(«JavaRush — лучший сайт для изучения Java!»); String s2 = «JavaRush — лучший сайт для изучения Java!»; System.out.println(s1 == s2.intern()); System.out.println(s2 == s1.intern()); В первом случае будет false, во втором true. Это просто взрыв мозга, я не понял, почему. С equals в обоих случаях true.

23 сентября 2023

Я не понял, почему для сравнения строк, лучше всегда использовать .equals() ?? если intern() через ==, вроде как делает тоже самое?

ThisKRuT Уровень 12
8 сентября 2023
В каком случае в реальных проектах может использоваться intern() ?
25 августа 2023

вроде все понятно, но есть вопрос, почему String text = «Привет»; String text1 = «Привет»; String s1 = text.toUpperCase(); String s2 = text.toUpperCase(); System.out.println(text == text1); System.out.println(text == s1); System.out.println(s1 == s2); то: true false false почему System.out.println(s1 == s2); выдает false. ведь у него такой же метод, как и у s1? как я понял — использование toUpperCase() это также как и использование оператора new и создает новую область в StringPool?

M K Уровень 32
2 мая 2023

Вторая половина понятна. Не понятно почему в самом начале тогда когда мы сравнивали и ссылки строк и через equals их сравнивали значение было false? Если дальше мы делаем то же самое и сам автор пишет: Каждый раз, когда ты пишешь String = “. ”, программа проверяет, есть ли строка с таким текстом в пуле строк. Если есть — новая создана не будет. И новая ссылка будет указывать на тот же адрес в пуле строк, где эта строка хранится. Но в первом коде это не работало. Почему? Получается автор сначала пишет одно, а потом прямо противоположное. Объясните пожалуйста как так получается.

Метод equals в java – реализация на примерах

Фундаментальным аспектом любого класса Java является его определение равенства. Он определяется методом равных классов, и для правильной реализации есть несколько вещей. Давайте определим их, чтобы правильно понимать метод equals в java.

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

public boolean equals(Object o)

Метод возвращает значение True, если аргумент не равен null и является объектом того же типа и с тем же числовым значением.

Существуют некоторые дополнительные требования для объектов Double и Float, которые описаны в документации API Java.

Обратите внимание, что реализация equals всегда означает, что hashCode также должен быть реализован!

метод equal

Идентичность в сравнении с равенством в Java

Посмотрите на этот фрагмент кода:

[java]String some = «some string»;
String other = «other string»;[/java]

У нас две строки и они разные.

Теперь разберем эти:
String some = «some string»;
String other = some;
boolean identical = some == other;

Здесь мы имеем только один экземпляр String, some и other ссылаются на него. В Java some и other идентичны и, соответственно, identical есть true.

Теперь посмотрите на такой пример:
String some = «some string»;
String other = «some string»;
boolean identical = some == other;
Теперь some и other указывают на разные экземпляры и больше не идентичны, поэтому identical является ложным.

В терминах Java они равны, что проверяется с помощью equals:
String some = «some string»;
String other = «some string»;
boolean equal = some.equals(other);
Здесь equals есть true.

Идентификатор переменной (также называемый ссылочным равенством) определяется ссылкой, которую он содержит. Если две переменные содержат одну и ту же ссылку, они идентичны. Это проверяется с помощью ==.

Равенство переменной определяется значением, на которое оно ссылается. Если две переменные ссылаются на одно и то же значение, то они равны. Это проверяется с помощью equals.

Но что означает «то же значение»? По сути, именно реализация равных определяет “одинаковость”. Метод equals определен в Object, и так как все классы наследуются от него, у всех есть этот метод.

Реализация в Object проверяет identity (обратите внимание, что одинаковые переменные также равны), но многие классы переопределяют его чем-то более подходящим. Для строк, например, он сравнивает последовательность символов, а для дат он гарантирует, что оба указывают на один и тот же день.

Когда же стоит делать перегрузку метода equals? Это стоит делать только тогда, когда для вашего класса определено понятие логической эквивалентности, которая не совпадает с тождественностью объектов.

Например, для классов Integer и String данное понятие можно применить.

Переопределение метода equals позволяет использовать экземпляры класса в качестве ключей в некой схеме или элементов в неком наборе, имеющих необходимое и предсказуемое поведение.

переопределение equals

Многие структуры данных используют Equals для проверки того, содержат ли они элемент.
Например:

List list = Arrays.asList(«a», «b», «c»);
boolean contains = list.contains(«b»);

Переменная contains имеет значение true, хотя “b” не идентичны, но они равны. (Здесь начинает работать hashCode.)
Для лучшего понимания работы equals в java рассмотрим такой пример. Допустим, мы сравниваем ноутбуки и считаем их равными, если они имеют одинаковые характеристики.

Одно свойство настолько тривиально, что его вряд ли стоит упоминать: каждая вещь равна самой себе.
Если есть 2 объекта: если одна вещь равна другой, другая также равна первой. Очевидно, если мой ноутбук равен вашему, ваш равен моему.

Если если у нас есть три вещи, первая и вторая равны, вторая и третья равны, то первая и третья также равны. Опять же, это очевидно на нашем примере с ноутбуками.
Мы просто рассмотрели некоторые основные алгебраические свойства отношений эквивалентности. Нет, подождите, не уходи! Это уже все, что нам нужно. Потому что любое отношение, которое имеет три свойства как выше, можно назвать равенством.

equals-это не что иное, как формализация того, что мы видели выше.

Метод equals реализует отношение эквивалентности для ненулевых ссылок на объекты:

  1. Рефлексивно: для любого ненулевого ссылочного значения x, x.equals (x) должен возвращать true.
  2. Симметричено: для любых ненулевых ссылочных значений x и y, x.equals (y) должен возвращать true тогда и только тогда, когда y.equals (x) возвращает true.
  3. Транзитивно: для любых ненулевых ссылочных значений X, Y и Z, если x.equals(Y) возвращает True и Y.equals(Z) возвращает True, то x.equals(Z) должен возвращать True.
  4. Непротиворечиво: для любых ненулевых значений x и y множественные вызовы x.equals (y) последовательно возвращается true или последовательно возвращается false при условии, что информация, используемая в сравнениях equals для объектов не изменяется.
  5. Для любого ненулевого значения x, x.equals (null) должен возвращать false.

Реализация метода equals

Для класса Person со строковыми полями firstName и lastName общий вариант для реализации equals:

@Override
public boolean equals(Object o) // self check
if (this == o)
return true;
// null check
if (o == null)
return false;
// type check and cast
if (getClass() != o.getClass())
return false;
Person person = (Person) o;
// field comparison
return Objects.equals(firstName, person.firstName)
&& Objects.equals(lastName, person.lastName);
>

Очень важно, что equals принимает Object! В противном случае возникает непредвиденное.

Например, предположим, что мы будем реализовывать equals (Person) так:
public boolean equals(Person person) return Objects.equals(firstName, person.firstName)
&& Objects.equals(lastName, person.lastName);
>

Посмотрим на простом примере:

Person elliot = new Person(«Elliot», «Alderson»);
Person mrRobot = new Person(«Elliot», «Alderson»);
boolean equal = elliot.equals(mrRobot);

equal принимает значение true, а теперь:

Person elliot = new Person(«Elliot», «Alderson»);
Object mrRobot = new Person(«Elliot», «Alderson»);
boolean equal = elliot.equals(mrRobot);

Теперь это ложь. Может, не совсем то, что мы ожидали.

Причина в том, что Java вызывает Person.equals(Object) (наследуется от объекта, который проверяет идентичность). Почему?

Стратегия Java в выборе метода основана не на типе среды выполнения параметров, а на его объявленном типе.Поэтому, если Mr Robot объявлен как объект, Java вызывает Person.equals(Object) вместо нашего Person.equals(Person).

hashcode java

Самопроверка

Равенство является фундаментальным свойством любого класса, и оно может в конечном итоге вызываться очень часто, например, в циклах. Таким образом, его производительность имеет значение! И самоконтроль в начале нашей реализации – это просто оптимизация производительности.

java if (this == o) возвращает true;

Может показаться, что он должен реализовывать рефлексивность, но проверки дальше были бы очень странными, если бы они не делали этого.

Проверка NULL значения.
Ни один экземпляр не должен быть равен null, поэтому здесь мы убедимся в этом. В то же время он защищает код от Nullpointerexception.
if (o == null)
return false;

Фактически он может быть включен в следующую проверку, например:
if (o == null || getClass() != o.getClass())
return false;

Заключение

Мы выяснили разницу между идентичностью (должна быть одна и та же ссылка, проверена с помощью ==) и равенством (могут быть разные ссылки на «одно и то же значение»).

  • Обязательно переопределите equals (Object), чтобы наш метод всегда вызывался.
  • Включите проверку self и null.
  • Используйте getClass, чтобы позволить подтипам выполнять свою собственную реализацию (но не сравнивать по подтипам) или использовать instanceof и make
  • equals final (и подтипы могут быть равны).
  • Сравните нужные поля с помощью Objects.equals.
  • Или пусть ваша IDE генерирует все для вас и редактирует там, где это необходимо.

Средняя оценка 4.8 / 5. Количество голосов: 4

Спасибо, помогите другим — напишите комментарий, добавьте информации к статье.

Или поделись статьей

Видим, что вы не нашли ответ на свой вопрос.

Помогите улучшить статью.

Напишите комментарий, что можно добавить к статье, какой информации не хватает.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *