Как я могу использовать методы set и get и почему я должен их использовать? Они действительно полезны? А также можете ли вы привести примеры методов set и get?
Установить и получить методы в java?
Ответы (15)
Методы Set и Get — это шаблон инкапсуляции данных. Вместо прямого доступа к переменным-членам класса вы определяете get
методы для доступа к этим переменным и set
методы для их изменения. Инкапсулируя их таким образом, вы получаете контроль над общедоступным интерфейсом, если в будущем вам потребуется изменить внутреннюю работу класса.
Например, для переменной-члена:
Integer x;
У вас могут быть методы:
Integer getX(){ return x; }
void setX(Integer x){ this.x = x; }
чиккодоро также упомянул важный момент. Если вы хотите разрешить доступ на чтение к полю только для любых сторонних классов, вы можете сделать это, предоставив только общедоступный метод get
и оставив закрытым set
или вообще не предоставляя set
.
Я хочу добавить к другим ответам, что сеттеры можно использовать для предотвращения перевода объекта в недопустимое состояние.
Например, предположим, что мне нужно установить TaxId, смоделированный как строка. Первая версия сеттера может быть такой:
private String taxId;
public void setTaxId(String taxId) {
this.taxId = taxId;
}
Однако нам лучше предотвратить использование для установки объекта с недопустимым taxId, поэтому мы можем ввести проверку:
private String taxId;
public void setTaxId(String taxId) throws IllegalArgumentException {
if (isTaxIdValid(taxId)) {
throw new IllegalArgumentException("Tax Id '" + taxId + "' is invalid");
}
this.taxId = taxId;
}
Следующим шагом для улучшения модульности программы является создание самого TaxId как объекта, способного проверять себя.
private final TaxId taxId = new TaxId()
public void setTaxId(String taxIdString) throws IllegalArgumentException {
taxId.set(taxIdString); //will throw exception if not valid
}
Аналогично для геттера, что, если у нас еще нет значения? Может быть, мы хотим пойти другим путем, мы могли бы сказать:
public String getTaxId() throws IllegalStateException {
return taxId.get(); //will throw exception if not set
}
Я думаю, вы хотите что-то вроде этого:
public class Person {
private int age;
//public method to get the age variable
public int getAge(){
return this.age
}
//public method to set the age variable
public void setAge(int age){
this.age = age;
}
}
Вы просто вызываете такой метод для экземпляра объекта. Такие методы полезны, особенно если установка чего-либо должна иметь побочные эффекты. Например. если вы хотите реагировать на определенные события, такие как:
public void setAge(int age){
this.age = age;
double averageCigarettesPerYear = this.smokedCigarettes * 1.0 / age;
if(averageCigarettesPerYear >= 7300.0) {
this.eventBus.fire(new PersonSmokesTooMuchEvent(this));
}
}
Конечно, это может быть опасно, если кто-то забудет вызвать setAge(int)
там, где он должен, и установит age
напрямую с помощью this.age
.
Наличие методов доступа предпочтительнее прямого доступа к полям, поскольку они контролируют доступ к полям (может потребовать проверки данных и т. д.) и подходят для интерфейсов (интерфейсы не могут требовать присутствия полей, только методы).
Сеттеры и геттеры используются для замены прямого доступа к переменным-членам из внешних классов. если вы используете сеттер и геттер для доступа к свойству, вы можете включить инициализацию, проверку ошибок, сложные преобразования и т. д. Некоторые примеры:
private String x;
public void setX(String newX) {
if (newX == null) {
x = "";
} else {
x = newX;
}
}
public String getX() {
if (x == null) {
return "";
} else {
return x;
}
}
x
не может быть нулевым из-за setX
, поэтому getX
не нужно проверять на это. Но дело сделано, и любой, кто понимает этот комментарий, понимает всю суть геттеров и сеттеров. +1
- person Erick Robertson; 10.07.2011
x
просто не инициализируется ""
? Затем вы сохраняете чек в getX
.
- person Erick Robertson; 10.07.2011
Некоторые преимущества использования геттеров и сеттеров (известных как encapsulation
< /a> или data-hiding
):
(первоначально ответил здесь)
<сильный>1. Поля класса можно сделать доступными только для чтения (предоставив только геттер) или только для записи (только предоставив установщик). Это дает классу полный контроль над тем, кто может получить доступ к его полям или изменить их.
Пример:
class EncapsulationExample {
private int readOnly = -1; // this value can only be read, not altered
private int writeOnly = 0; // this value can only be changed, not viewed
public int getReadOnly() {
return readOnly;
}
public int setWriteOnly(int w) {
writeOnly = w;
}
}
<сильный>2. Пользователям класса не нужно знать, как класс фактически хранит данные. Это означает, что данные отделены и существуют независимо от пользователей, что позволяет легче изменять и поддерживать код. Это позволяет сопровождающим вносить частые изменения, такие как исправление ошибок, улучшение дизайна и производительности, не влияя при этом на пользователей.
Кроме того, инкапсулированные ресурсы одинаково доступны для каждого пользователя и имеют одинаковое поведение независимо от пользователя, поскольку это поведение внутренне определено в классе.
Пример (получение значения):
class EncapsulationExample {
private int value;
public int getValue() {
return value; // return the value
}
}
А что если вместо этого я хочу вернуть удвоенное значение? Я могу просто изменить свой геттер, и весь код, который использует мой пример, не нужно менять, и он получит удвоенное значение:
class EncapsulationExample {
private int value;
public int getValue() {
return value*2; // return twice the value
}
}
<сильный>3. Делает код чище, читабельнее и легче для понимания.
Вот пример:
Без инкапсуляции:
class Box {
int widthS; // width of the side
int widthT; // width of the top
// other stuff
}
// ...
Box b = new Box();
int w1 = b.widthS; // Hm... what is widthS again?
int w2 = b.widthT; // Don't mistake the names. I should make sure I use the proper variable here!
С инкапсуляцией:
class Box {
private int widthS; // width of the side
private int widthT; // width of the top
public int getSideWidth() {
return widthS;
}
public int getTopWIdth() {
return widthT;
}
// other stuff
}
// ...
Box b = new Box();
int w1 = b.getSideWidth(); // Ok, this one gives me the width of the side
int w2 = b.getTopWidth(); // and this one gives me the width of the top. No confusion, whew!
Посмотрите, насколько больше у вас контроля над тем, какую информацию вы получаете, и насколько это яснее во втором примере. Имейте в виду, что этот пример тривиален, и в реальной жизни классы, с которыми вы будете иметь дело, имеют множество ресурсов, к которым обращаются многие различные компоненты. Таким образом, инкапсуляция ресурсов делает более понятным, к каким из них мы обращаемся и каким образом (получаем или устанавливаем).
Вот good SO thread
по этой теме.
Вот good read
об инкапсуляции данных.
Приведенные выше ответы резюмируют роль геттеров и сеттеров лучше, чем я мог бы, однако я хотел добавить, что в идеале ваш код должен быть структурирован, чтобы уменьшить использование чистых геттеров и сеттеров, то есть без сложных конструкций, проверки и т. д., поскольку они нарушают инкапсуляцию. Это не означает, что вы никогда не сможете их использовать (ответ stivlo показывает пример хорошего использования геттеров и сеттеров), просто постарайтесь свести к минимуму частоту их использования.
Проблема в том, что геттеры и сеттеры могут действовать как обходной путь для прямого доступа к закрытым данным. Частные данные называются частными, потому что они не предназначены для совместного использования с другими объектами; это означает представление состояния объекта. Предоставление другим объектам доступа к приватным полям объекта сводит на нет всю цель сделать его приватным в первую очередь. Более того, вы вводите связанность для каждого геттера или сеттера, который вы пишете. Рассмотрим это, например:
private String foo;
public void setFoo(String bar) {
this.foo = bar;
}
Что произойдет, если где-то в будущем вы решите, что вам больше не нужен foo, или вы хотите сделать его целым? Каждый объект, использующий метод setFoo, теперь нужно изменить вместе с foo.
просто потому, что правило ООП: сокрытие данных и инкапсуляция. В большинстве случаев объявлять объект общедоступным и изменять его на лету — очень плохая практика. Также есть много других причин, но корень — инкапсуляция в ООП. и "купите книгу или идите читать по объектно-ориентированному программированию", вы все поймете по этому поводу после того, как прочитаете любую книгу по ООП.
Преимущества методов get() set() заключаются в следующем.
- Вы можете легко сериализовать свой объект.
- Вы можете создать постоянный объект из содержащего класса.
- Вы можете легко преобразовать свойства в JSON.
- На уровне DAO (фреймворки, такие как Hibernate) вы можете напрямую сохранить объект в БД.
- Легкое понимание объектно-ориентированной концепции.
- Требуется во всех шаблонах дизайна, за исключением, возможно, шаблона с одним тоном.
- Безопасность для свойств, защищающих прямой доступ.
- Полиморфизм, инкапсуляция могут быть легко поняты и реализованы этим типом класса.
Пример:
private String personName;
private int personId;
public void setPersonName(String name) throws Exception{
if(!(name.equals("")||name=="")){
this.personName = name;
}
}
public String getPersonName(){
return this.personName;
}
public void setPersonId(int id) throws Exception{
this.personId = id;
}
public int getPersonId(){
return this.personId;
}
Все вышеприведенные ответы предполагают, что рассматриваемый объект является объектом с поведением. Продвинутая стратегия в ООП состоит в том, чтобы разделить объекты данных (которые имеют zip, только поля) и объекты поведения.
С объектами данных совершенно нормально не использовать геттеры и вместо этого использовать общедоступные поля. У них обычно нет сеттеров, так как они чаще всего неизменяемы - их поля устанавливаются через конструкторы, и никогда больше. Взгляните на Clean Code Боба Мартина или Pryce. и Growing OO Software... Фримана для получения подробной информации. .
public class Person{
private int age;
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
}
Я думаю, это то, что вам нужно.. и это также называется pojo
это код для метода set
public void setAge(int age){
this.age = age;
}
Похоже, вы пытаетесь сделать что-то похожее на C#, если вам нужен метод setAge createsetAge(int age){
this.age = age;}
Я не вижу здесь простого ответа на второй вопрос (почему). Так вот.
Допустим, у вас есть общедоступное поле, которое очень часто используется в вашем коде. Всякий раз, когда вы решаете, что вам нужно сделать что-то дополнительное, прежде чем указать или установить это поле, у вас возникнет проблема. Вы должны создать специальный геттер и сеттер для этого поля и изменить свой полный код с прямого использования поля на использование геттера и сеттера.
Теперь представьте, что вы разрабатываете библиотеку, широко используемую многими людьми. Когда вам нужно внести изменения, как указано выше, и установить прямой доступ к полю как частный, код всех людей, использующих это поле, сломается.
Использование геттеров и сеттеров связано с будущим планированием кода, оно делает его более гибким. Конечно, вы можете использовать общедоступные поля, особенно для простых классов, которые просто содержат некоторые данные. Но всегда полезно просто сделать поле приватным и закодировать для него метод получения и установки.
Этот ответ объединен с другим вопросом.
Ваш метод getAge()
называется методом экземпляра в Java.
Чтобы вызвать метод экземпляра, у вас должен быть объект класса, в котором этот метод определен.
Например, если этот метод в классе называется Person
, то
Создайте объект Person, используя новый оператор
Person p = new Person();
Чтобы получить возраст объекта
Person
, используйте этот методp.getAge()