java – Use get and set or declare the public variable?

Question:

Many times the variables of a class in java are declared as private to have encapsulation.

Other issues to declare a variable as private is so that it can only be accessible from the class itself, but finally in most cases it ends up doing set and get methods to modify the variable or to obtain it outside the class.

So what I'm wondering is if there is any good reason to declare a private variable and put set and get on it instead of declaring it public and avoiding a set and a get .

Answer:

Allowing free access to class attributes is not a doomed design, just different. This is usually avoided so that the class internally handles any business logic that it can associate with the fields. For example:

public class Foo {
    public List<String> listaNombres;
    public Foo() {
        listaNombres = new ArrayList<>(Arrays.asList("Friky", "Luiggi"));
    }
}

public class Otro {
    public List<String> listaNombresOtro;
    public void obtieneDeFoo(Foo foo) {
        listaNombresOtro = foo.listaNombres;
    }

    public static void main(String[] args) {
        Foo foo = new Foo();
        System.out.println(foo.listaNombres);
        Otro otro = new Otro();
        otro.obtieneDeFoo(foo);
        otro.listaNombresOtro.set(0, "Cambio");
        System.out.println(foo.listaNombres);
        System.out.println(otro.listaNombresOtro);
    }
}

If we later want to add validations for this code, the situation is complicated. Sure, in the previous example you can't see it because there are only about 3 calls to Foo#listaNombres , but if it were spread through dozens of methods the situation is complicated. In addition, it also complicates if the definition of the attribute (name, type, etc.) were changed, due to all the changes that would be made. An additional problem is that when getting the list from Foo#listaNombres we don't want to pass the list directly, instead we want a copy of it. We could do the copy in each location of foo.listaNombres but that leads to duplicate code (well, multiplied rather than doubled).


The use of the get and set methods (preferably public) is in accordance with the JavaBean specification :

7 Properties

Properties are discrete, named attributes of a Java Bean that can affect its appearance or its behavior. For example, a GUI button might have a property named “Label” that represents the text displayed in the button.

Properties show up in a number of ways:

Properties may be exposed in scripting environments as though they were fields of objects. So in a Javascript environment I might do "b.Label = foo" to set the value of a property. Properties can be accessed programmatically by other components calling their getter and setter methods (see Section 7.1 below). (…)

7.1 Accessor methods

Properties are always accessed via method calls on their owning object. For readable properties there will be a getter method to read the property value. For writable properties there will be a setter method to allow the property value to be updated.

Translated:

7 Properties

Properties are named, discrete attributes of a Java Bean that can affect its appearance or behavior. For example, a GUI button might have a property called "Label" that represents the text that is displayed on the button.

Properties are displayed in several ways:

Properties can be exposed in script environments as if they were object fields. So in a JavaScript environment you could do "b.Label = foo" to assign the value of a property. The properties can be accessed programmatically by other components that call their get and set methods (see section 7.1 below). (…)

7.1 Access methods

Properties are always accessed through method calls on the owning object. For readable properties, there will be a get method to read the property's value. For writable properties, there will be a set method that allows you to update the property's value.

This means that the get and set methods allow access to the properties (attributes) of a class. Many frameworks benefit from this definition. To name a few:

  • Spring, CDI, Guice (IoC, dependency injection)
  • Hibernate, MyBatis (data access)
  • XStream, Jackson, Gson (conversion between objects and JSON, XML and other formats)
  • Spring MVC, JSF, Expression Language, JSTL, etc (web MVC)
  • JavaFX (desktop GUI)
  • Metro, Apache CXF, Apache Axis (Web services implementation / consumption)
  • Etc. Or rather: any framework that works with objects using reflection (reflection) that is normally based on using classes with default constructors and access to attributes through get and set methods.

Placing an example of Spring with XML configuration:

<bean id="fooBean" class="paquete.de.mis.clases.Foo">
    <property name="listaNombres">
        <list>
            <value>Friky</value>
            <value>Luiggi</value>
        </list>
    </property>
</bean>

The Java class associated with this bean:

package paquete.de.mis.clases;

public class Foo {
    private List<String> listaNombres;
    public List<String> getListaNombres() {
        return this.listaNombres;
    }
    //permite a Spring asignar el valor de la lista mediante reflexión
    public void setListaNombres(List<String> listaNombres) {
        this.listaNombres = listaNombres;
    }
}

Example in JSF for field association using Expression Language:

<!-- permite a JSF llamar al getter mediante reflexión -->
<h:dataTable value="#{foo.listaNombres}" var="nombre">
    <h:column>
        #{nombre}
    </h:column>
</h:dataTable>

The associated Java class:

package paquete.de.mis.managedbeans;

@ManagedBean
@ViewScoped
public class Foo {
    private List<String> listaNombres;
    @PostConstruct
    public void init() {
        listaNombres = new List<>();
        listaNombres.add("Friky");
        listaNombres.add("Luiggi");
    }
    public List<String> getListaNombres() {
        return this.listaNombres;
    }
    public void setListaNombres(List<String> listaNombres) {
        this.listaNombres = listaNombres;
    }
}

Also, the "good" (?) Of using these methods is that you can add business logic to them to avoid direct contact with the objects you interact with. From the previous case that we indicated that we want to obtain a copy of the list instead of obtaining the list directly, we could add this logic in the get method:

public class Foo {
    private List<String> listaNombres;
    public List<String> getListaNombres() {
        //en lugar de devolver la lista directamente
        //devolvemos una nueva lista con los elementos
        //de mi lista actual
        return new ArrayList<>(this.listaNombres);
    }
}

If it seems like a lot of effort to generate the code of these methods, you can use lombok that offers facilities to add these methods through annotations in your code, among other benefits.


Adapted from Private List with Getter / Setter vs Public List

Scroll to Top