Question

I was coding up my own implementation of a LinkedList yesterday. I was doing something like this:

public class Node
{
    Node next;
    int value;

    public Node()
    {
       next = null
       value = 0;
    }
}

Then when using the Node I was doing node.next and node.value. Then I realized - wait, what the heck am I doing? These instance variables should be private and then I should be accessing with getters() and setters() like getNext() and setValue().

This led me to wonder, when is anything other than a private instance variable desired?

Was it helpful?

Solution

Technically, you're asking two questions: The title question, "When is it appropriate to have a public instance field," and your final sentence, "When is it appropriate to have a non-private instance field."

When is it appropriate to have a public instance field? Just about everyone knows the answer is almost never. I think they occasionally can be appropriate in very small value classes, which behave like simple C structs. A good example would be java.awt.Point and java.awt.Dimension.

Those are in fact especially good examples, because they ended up evolving to use accessor methods despite their simplicity, which is a good lesson: Even a class that seems so simple that public fields might seem acceptable has a real possibility of becoming something that requires encapsulation. (Point and Dimension continue to retain those public fields for backward compatibility.)

When is it appropriate to have non-private instance fields? Most people don't take advantage of the fact that fields and methods (and classes) with no access modifier are package-private, but package-private fields can be useful in a lot of situations. Since they're only accessed by the same package, it will often be the case that it's your code and you can trust yourself not to do "bad things" that would corrupt your objects. I'd say there are considerably more legitimate uses for package-private fields than for public fields.

That said, the Point/Dimension rule still applies: There have been many times when I thought I could get away with package-private fields, only to later realize I needed encapsulation via get- and set-methods.

Protected fields probably get used far more than they should. There's rarely a big gain to let a subclass modify state directly instead of going through a method, in my opinion.

OTHER TIPS

The classic example is a class to represent two-dimensional mathematical points.

public class Point {
    public float x;
    public float y;

    public Point( float x, float y ) {
        x = x;
        y = y;
    }

    public void scale( float c ) {
        x *= c;
        y *= c;
    }

    public void rotate( float angle, Point center ) {
       // whatever this logic is; I forget
    }   
}

A Point is really just a container for two floats that can vary arbitrarily. You aren't really going to hurt anything by allows access to x and y directly, rather than forcing the user to go through getters and setters. At the same time, some operations like scaling and rotation are common enough that it's worth creating a class that provides methods for doing the necessary math on the coordinates.


Please forgive (or better yet, correct) any syntax or other errors in the code. I haven't written any Java in ages.

When you don't actually need to protect them from arbitrary access or changes (such as when the value is allowed to take any integer, or a simple null mapping of "value retrieved" to "value in object"), it makes little sense to wrap a getter or setter around it.

The code can sometimes look more natural if that's the case, using:

object.value = 42;

rather than:

object.setValue (42);

(though the difference to my eyes is minimal).

Having said that, I still prefer getters and setters since, if at some point in the future you need to incorporate logic into the member, changing a public member to a getter/setter for that member will break the API for that class, involving changes to all clients using it.

This can include (but is in no way limited to):

  • restricting the values you can set the member to. For example, restricting the age of an object to between 0 and 13.7 billion years :-)
  • deriving the value being extracted, such as calculating Fahrenheit temperature from a Celsius member.
  • having side effects to setting a value, such as changing a file name involving preloading some of the file into a cache.

You must look at access specifiers in Java. For quick reference: http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top