Подтвердить что ты не робот

Почему переменные экземпляра в Java всегда являются частными?

Я новичок в Java, и я узнаю об инкапсуляции и увидел пример, когда переменные экземпляра объявляются как частные в классе.

http://www.tutorialspoint.com/java/java_encapsulation.htm

У меня есть 2 вопроса:

  • Почему переменные экземпляра являются частными? Почему не публично?
  • Что делать, если переменные экземпляра становятся общедоступными и доступны напрямую? Существуют ли какие-либо ограничения?

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

4b9b3361

Ответ 1

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

Использование методов позволит вам, например, ограничить доступ только для чтения, то есть поле может быть прочитано, но не написано, если нет сеттера. Это было бы невозможно, если бы поле было общедоступным.

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

Если phone был закрытым:

Рассмотрим этот случай:

class Address {
  private String phone;

  public void setPhone(String phone) {
    this.phone = phone;
  }
}

//access:
Address a = new Address();
a.setPhone("001-555-12345");

Если бы мы начали с класса, подобного этому, и позже потребовалось бы выполнить проверки на номер телефона (например, минимальная длина, только цифры и т.д.), вам просто нужно изменить установщик:

class Address {
  private String phone;

  public void setPhone(String phone) {
    if( !isValid( phone) ) { //the checks are performed in the isValid(...) method
     throw new IllegalArgumentException("please set a valid phone number");
    }

    this.phone = phone;
  }
}

//access:
Address a = new Address();
a.setPhone("001-555-12345"); //access is the same

Если phone был общедоступным:

Кто-то может установить phone как это, и вы ничего не могли с этим поделать:

Address a = new Address();
a.phone="001-555-12345";

Если теперь вы хотите принудительно выполнить проверки проверки, вам придется сделать это частным, и кто бы ни написал эти строки, должен был бы изменить вторую строку:

a.setPhone("001-555-12345");

Таким образом, вы не могли просто добавить проверки без нарушения другого кода (он больше не компилируется).

Кроме того, если вы обращаетесь ко всем полям/свойствам класса с помощью методов, вы обеспечиваете согласованность доступа, и пользователю не нужно беспокоиться о том, хранится ли свойство (т.е. поле экземпляра) или вычисляется (есть только методы и нет полей экземпляра).

Ответ 2

Они не должны быть частными, но они должны быть. Поле - это деталь реализации, поэтому вы должны держать его в тайне. Если вы хотите разрешить пользователям извлекать или устанавливать его значение, вы используете для этого свойства (get и set methods) - это позволяет сделать это безопасно (например, проверку ввода), а также позволяет вам изменять детали реализации (например, для делегирования некоторые из значений для других объектов и т.д.), не теряя обратной совместимости.

Ответ 3

Во-первых, неверно, что все переменные экземпляра являются частными. Некоторые из них защищены, что все еще сохраняет инкапсуляцию.

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

Например, если у вас есть два логических поля, и класс может нормально функционировать только в трех случаях: [false, false], [false, true] и [true, false]. Если вы сделаете поля общедоступными, другой объект может установить [true, true], не зная внутренних ограничений, а следующий метод, вызванный исходным объектом, вызовет неожиданные результаты.

Ответ 4

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

Белая книга Oracle

Ответ 5

Как уже отмечалось несколькими респондентами, переменные экземпляра не обязательно должны быть private, но они обычно, по крайней мере, не сделаны public, чтобы сохранить инкапсуляцию.

Я видел пример в (я думаю) Clean Code, что очень хорошо иллюстрирует это. Если я правильно помню, это было сложное число (как в a+bi); в любом случае, что-то очень похоже на то, что у меня нет книги. Он разоблачил методы получения значения реальной и мнимой частей, а также метод для установки значения экземпляра. Большим преимуществом этого является то, что он позволяет полностью заменить реализацию, не нарушая потребителей кода. Например, комплексные числа могут храниться в одной из двух форм: в виде координат на комплексной плоскости (a+bi) или в полярной форме (φ и |z|). Сохраняя внутренний формат хранения, деталь реализации позволяет вам переключаться взад и вперед, сохраняя при этом номер в обеих формах, тем самым позволяя пользователю выбирать класс, который более удобен для выполняемой ими операции.

В других ситуациях у вас может быть набор связанных полей, например, поле x должно иметь определенные свойства, если поле y попадает в заданный диапазон. Простой пример: где x должно находиться в диапазоне от y до y+z, для числовых значений и некоторого произвольного значения z. Выставляя аксессуры и мутаторы, вы можете принудительно применять эту взаимосвязь между двумя значениями; если вы напрямую подвергаете переменные экземпляра, инвариант немедленно разваливается, так как вы не можете гарантировать, что кто-то не будет устанавливать один, а не другой, или установите их так, чтобы инвариант больше не выполнялся.

Конечно, учитывая рефлексию, все равно можно получить доступ к тем членам, которых вы не должны, но если кто-то отражает ваш класс для доступа к закрытым членам, им лучше понять, что то, что они делают, может очень сильно нарушить. Если они используют открытый интерфейс, они могут подумать, что все в порядке, а затем они заканчиваются неприятными ошибками, потому что они неосознанно не полностью соответствуют деталям реализации вашей конкретной реализации.

Ответ 6

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

В последние несколько лет (к лучшему или худшему) стало более популярным использовать где класс - это не что иное, как кучу полей и соответствующих геттеров и сеттеров. Я бы сказал, что в этом дизайне вам будет лучше с публичными полями, поскольку геттеры и сеттеры не обеспечивают реального инкапсуляции, а просто обманывают вас, думая, что вы делаете настоящую OO.

UPDATE: пример, приведенный в ссылке в вопросе, является прекрасным примером этой вырожденной инкапсуляции. Я понимаю, что автор пытается представить простой пример, но при этом не может передать каких-либо реальных преимуществ инкапсуляции (по крайней мере, не в примере кода).

Ответ 7

  • Потому что, если вы измените структуру класса (удаление полей и т.д.); это вызовет ошибки. Но если у вас есть метод getX(), вы можете вычислить необходимое значение там (если поле было удалено).

  • У вас возникла проблема в том, что класс не знает, что-то изменилось и не может гарантировать целостность.

Ответ 8

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

Уровень по умолчанию избегает помех в вашем собственном коде и не позволяет клиентам вашего кода устанавливать недопустимые значения.

Ответ 9

Для пользователя класса

  We, who are using ide like eclipse, netbins.....

увидел, что он предлагает нам общедоступный метод, поэтому, если создатель класса предоставляет getter и setter для частной переменной экземпляра, вам не нужно запоминать имя переменной. просто напишите set press ctrl + space, вы получаете весь метод setter, созданный создателем этого класса, и выберите желаемый метод, чтобы установить значение переменной.

Для создателя класса

  Sometimes you need to specify some logic to set variable value.

"предположим, что у вас есть целочисленная переменная, которая должна хранить 0