-2

This question already has an answer here:

Is there really any actual use for private variables and specific moments where they would be your only possible option? Or can you just set all of your variables as public without any actual changes to the program? It seems like a pointless practice that doesn't really change much, from my perspective, so I'm wondering if I'm overlooking something.

marked as duplicate by gnat, amon, David Arno, Telastyn, Charles E. Grant Sep 21 '18 at 19:27

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 2
    You are overlooking encapsulation. – Nick Alexeev Sep 21 '18 at 16:46
  • 2
    Don't get discouraged by the downvotes, here they are just a way for the community to give feedback on the quality of the question, and on the fact that similar questions have been answered before, so follow the links provided in the comments above (and even the links you'll find there), and you'll get a whole bunch of answers. But let me put them in context - see my answer below. – Filip Milovanović Sep 21 '18 at 18:08
2

This has been asked many times before, so follow the links provided in the comment section under your quesion, and you'll get a whole bunch of answers. But let me put them in context.

If (1) people could write even a slightly complex piece of software perfectly on the first go, and if (2) the code is never ever going to change, then private variables are pointless. But (1) && (2) together are practically never the case in the real world. To write code that can be changed and maintained, you need to control the interdependencies between different pars of it, so that you can change each part in a way that requires no changes, or minimal changes to the other parts. One of the way to do this is to hide the implementation details of interacting classes. This is called encapsulation, and that's why you have private members. However, the point is not to make these members private and then expose them anyway with corresponding getters and setters. This 1-to-1 mapping between members and getters has little utility (yeah, there are some benefits, there is some level of encapsulation, but that's not how you do it, even though that's how you'll see it described in programming courses). What you do is you provide a set of member functions (methods) that exposes very little (if anything) about the internal structure of the class to the outside world (the other classes that call this code). These methods are formulated so that the external code doesn't ask the class for its internal data in order to do something with that data, but instead asks the class to complete some task for it. This then enables you to completely change the implementation of the class without affecting the external code at all, as long as you don't change the signature of the "outward facing" functions. And if your class implements a Java interface, and the external logic is coded against that interface, you can even swap the class for another completely (even at runtime).

Consider this (fairly contrived) example:

class Main {
  public static void main(String[] args) {
    Grower1 g1 = new Grower1();
    g1.value += 1;                    // must change
    if (g1.value < 10) {              // must change
      System.out.println(g1.value);   // prints out: 1
    }

    Grower2 g2 = new Grower2();
    g2.grow();
    if (g2.getValue() < 10) {                // must change
      System.out.println(g2.getValue());     // prints out: 1
    }

    Grower3 g3 = new Grower3();
    g3.grow();
    if (g3.isAlive()) {
      System.out.println(g3.toString());    // prints out: 1
    }
  }
}

class Grower1 {
  public int value = 0;
}

class Grower2 {
  private int value = 0;

  public int getValue() {
    return this.value;
  }

  public void grow() {
    this.value += 1;
  }
}

class Grower3 {
  private int value = 0;

  public void grow() {
    this.value += 1;
  }

  public boolean isAlive() {
    return this.value < 10;
  }

  public String toString() {
    return Integer.toString(this.value);
  }
}

Here, a "Grower" is a class that can "grow" in some sense, and it has up to 10 growth cycles. If I asked you to change Grower1 so that instead of incrementing a number it grows by appending the character 'a' to the initial string "a" (so, it goes "a" --> "aa" --> "aaa", etc.), you would have to change the code in Main. If you tried to do the same with Grower2, it would be a bit easier, but you'd still have to change the code in Main, although in fewer places. If you did it with Grower3, nothing in Main has to change (because the public members of Grower3 in no way reveal that value is an integer):

class Main {
  public static void main(String[] args) {

    // omitted code related to Grower1 & Grower2...

    // still works with no changes
    Grower3 g3 = new Grower3();
    g3.grow();
    if (g3.isAlive()) {
      System.out.println(g3.toString());    // prints out: aa
    }
  }
}

// omitted Grower1 & Grower2 classes...

class Grower3 {
  private String value = "a";

  public void grow() {
    this.value += "a";
  }

  public boolean isAlive() {
    return this.value.length() < 10;
  }

  public String toString() {
    return this.value;
  }
}

The trick is to figure out how to design the public methods so that you can do this kind of thing.

Not the answer you're looking for? Browse other questions tagged or ask your own question.