0

Stackoverflow is littered with articles on the purpose of private variables. Most of them say something to the effect that using private variables are 'safer'. Although, I have never found a truly concrete and satisfiable case of a private variable really making anything safer, besides maybe the fact that a user cannot accidentally modify a private variable from outside the class.

So what is the real extent to which a private variable is safer than a public variable? Does making a variable private simply protect code from your future self, and your fellow developers on the same project? Is it meant to protect it from other developers that are using your software as an API? Does the safety net which private variables provide extend as far as to prevent hackers and malicious users from changing highly important and sensitive parts of your code?

Community
  • 1
  • 1
chopper draw lion4
  • 12,401
  • 13
  • 53
  • 100

4 Answers4

6

Encapsulation is about loose coupling:

The benefit of encapsulation is not to hide the values, or really to prevent direct access to them.

The benefit is to hide the implementation so that it does not become tightly coupled with the public interface.

This makes it safe to change the implementation because no client is relying on implementation details or side effects.

If you expose that you are using an ArrayList to store items, client code becomes coupled to the ArrayList implementation. You can not safely change it to a TreeSet because the implementation is part of the public interface. If the public interface was Collection then you can change the implementation because you only promise to provide a Collection semantics.

Same with things like storing say a instance in time as a long: if you want to change it to a java.util.Date or Calendar or JodaTime something then you can't, because every client is expecting a long if that implementation is public.

Community
  • 1
  • 1
2

besides maybe the fact that a user cannot accidentally modify a private variable from outside the class

Well, that's already a benefit to start with.

The best thing with private variables, however, is that they are private for a reason; and that is, encapsulation.

You need to provide access to functionalities f1 and f2 for your class, and internally it relies on p1 and p2 which are private and should not be accessed so that your class can operate safely.

And that's all there is to it, really. Granting access to these variables to "outsiders" would compromise the safe operation of your class.

Sure, there are users with malicious intent who will use reflection to meddle with them, but they are not your primary target for your class, are they?

fge
  • 119,121
  • 33
  • 254
  • 329
0

If "safer" is supposed to refer to security, then it's not really true. There are many ways to access an object's private variables.

If "safer" is meant to refer to robust code, meaning code that is less likely to hit exceptions or otherwise fail to work properly, then yes, it is safer. The benefit is that your class has total control over the value.

The simplest example is null values. Consider this class:

public class Person {
    public String firstName;
    public String lastName;
    public List<Person> relatives;
}

If I want to write a method that accepts a Person instance, I have no guarantee that the fields are not null. I have to clutter my code with checks:

void populateFieldsWith(Person person) {
    firstNameField.setText(person.firstName != null ? person.firstName : "");
    lastNameField.setText(person.lastName != null ? person.lastName : "");

    if (person.relatives != null) {
        List<String> names = new ArrayList<>();
        for (Person relative : person.relatives) {
            if (relative != null
                && relative.firstName != null
                && relative.lastName != null) {

                names.add(relative.firstName + " " + relative.lastName);
            }
        }
        nameList.setData(names);
    } else {
        nameList.setData(Collections.emptyList());
    }
}

If the fields are private, the Person class is the only class who can modify them, which gives the Person class the power to ensure they are non-null:

public class Person {
    private String firstName;
    private String lastName;
    private final List<Person> relatives = new ArrayList<>();

    /**
     * Creates a new Person instance.
     *
     * @param firstName person's first name; cannot be null
     * @param lastName person's last name; cannot be null
     *
     * @throws RuntimeException if any argument is null
     */
    public Person(String firstName,
                  String lastName) {
        setFirstName(firstName);
        setLastName(lastName);
    }

    /**
     * Returns this person's first name.  This never returns null.
     */
    public String getFirstName() {
        return firstName;
    }

    /**
     * Sets this person's first name.
     *
     * @param name new non-null first name
     *
     * @throws RuntimeException if any argument is null
     */
    public void setFirstName(String name) {
        Objects.requireNonNull(name, "Name cannot be null");
        this.firstName = name;
    }

    /**
     * Returns this person's last name.  This never returns null.
     */
    public String getLastName() {
        return lastName;
    }

    /**
     * Sets this person's last name.
     *
     * @param name new non-null last name
     *
     * @throws RuntimeException if any argument is null
     */
    public void setLastName(String name) {
        Objects.requireNonNull(name, "Name cannot be null");
        this.lastName = name;
    }

    /**
     * Returns a list of this person's relatives.  This never returns null
     * but it may return an empty list.
     */
    public List<Person> getRelatives() {
        return new ArrayList<Person>(relatives);
    }

    public void setRelatives(List<Person> relatives) {
        Objects.requireNonNull(relatives, "List cannot be null");
        for (Person person : relatives) {
            Objects.requireNonNull(person, "List cannot contain null");
        }
        this.relatives.clear();
        this.relatives.addAll(relatives);
    }

    public void addRelative(Person relative) {
        Objects.requireNonNull(relative, "Person cannot be null");
        this.relatives.add(relative);
    }
}

Now we have a class that is unbreakable (unless someone uses reflection to get around the private access, but in that case you're dealing with malicious code and that enters the entirely different subject of runtime security).

There is no way firstName can be null, ever, because the only way any outside code can set it is to go through the setFirstName method, and that method will not allow the field to be set to a null value.

Now, let's return to the code that wanted to make use of a Person instance:

void populateFieldsWith(Person person) {
    firstNameField.setText(person.getFirstName());
    lastNameField.setText(person.getLastName());

    List<String> names = new ArrayList<>();
    for (Person relative : person.getRelatives()) {
        names.add(relative.getFirstName() + " " + relative.getLastName());
    }
    nameList.setData(names);
}

The method no longer needs to be cluttered with checks for null. Programmers can safely assume that the value is not null, because the javadoc guarantees it. The guarantee is an honest one because there is no code path that can cause the method to return null.

Null values is just one use. The same setFirstName method could also check that the string is non-empty, check that it doesn't exceed a maximum length, check that it only contains certain types of characters, and so on, all so the getFirstName method can provide a guarantee via its javadoc to other programmers that it will return valid data.

VGR
  • 40,506
  • 4
  • 48
  • 63
-1

Safer is a meaningless term used over and over. What all those books mean is that in terms of scalability on a big project, a private attribute should be considered as an entity univocally tied to a class so its value shall never be modified by other object in order to not alter its purpouse of existance (it's functionality). It's more a design matter than an implementation matter.

Think of an object which methods will return correct results only if their attributes are only modified by its very determinated methods: it couldn't guarantee that its method will return the expected result if an attribute is modified with a random value.

Furthermore, If you are coding an API library, the private elements won't be exposed in your binaries, making it more difficult to crack from a malicious user trying to instantiate objects not meant to be instantiated by the users.

Alex
  • 975
  • 10
  • 24
  • saying `safer` is meaningless was a good start, all the rest is off the mark, `private` has nothing to do with `immutability`, which is a nice goal, but has nothing to do with `private` scope. You can have `immutable` data that is `public` or `package private`. And if you think `private` makes your code harder to *crack* you need to read up on **reflection**, because you can discover and modify `private` members all day long, even if they are `static final`. –  Dec 13 '14 at 00:46
  • I disagree. And I see both of us are saying practically the same. Well... – Alex Dec 13 '14 at 00:52
  • My definition of private, as valid as yours, is not the definition of immutability, which is irrelevant for the question and I don't see how you associate it with my answer. Different objects can alter the references to immutable attributes amongs themselves if they are not private. You caught me on reflection. – Alex Dec 13 '14 at 01:00