AnnanFay
AnnanFay

Reputation: 9739

What's the deal with Java's public fields?

I've been reading two articles (1)(2) on javaworld.com about how all class fields should be private and getter/setter methods are just as bad. An object should act on the data it has rather than allowing access to it.

I'm currently working on a University assignment for Connect Four. In designing the program the Agents playing the Game need access to the Board's state (so they can decide what to move). They also need to pass this move to the Game so it can validate it as a legal move. And during deciding what to move pieces are grouped into Threats with a start and end Points.

Board, Threat and Point objects don't really do anything. They are just there to store related data that can be accessed in a human readable way.

At the start of design I was representing Points on the board as two element int arrays, however that got annoying when creating points or referencing components of them.

So, the class:

public class Point {
    public int x;
    public int y;
    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }
}

Perfect in every way I can think of. Except it breaks every rule I've learned. Have I sinned?

Upvotes: 32

Views: 23447

Answers (9)

pm100
pm100

Reputation: 50110

This is one advantage that c# has over Java. YOu can declare a class that has public fields and later on change your mind use a hidden field with getter and setter; but the callers syntax is the same

public class Point
{
     public int X;
}

becomes

public class Point
{
     int m_x;
     public int X {get {return m_x;} set {m_x = value;}
}

but the caller always does

Point p;
p.X = 12;

Upvotes: 8

nsayer
nsayer

Reputation: 17047

Sometimes the rules anticipate usage that you may not have considered.

What if you make a set or a hashmap of points? For that to work the way you likely desire it to work, you should implement equals() and hashcode() overloads, but then the best practice is to make the object immutable - that way you can't change the values out from under the set/map.

Upvotes: 0

meriton
meriton

Reputation: 70564

Public fields expose the representation of an object to its callers, i.e. if the representation has to change, so do the callers.

By encapsulating the representation, you can enforce how callers interact with it, and can change that representation without having to modify the callers provided the public api is unchanged. In any non-trivial program, encapsulation is necessary to achieve reasonable maintainability. However, while you need capsules, their proper granularity may be larger than a single class. For instance, it makes little sense to encapsulate an Iterator from the internal representation of the Collection it operates on.

With that out of the way, let's look at your example:

public class Point {
    public int x;
    public int y;
    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }
}

The internal representation of that class is exceedingly unlikely to change, so hiding the structure of the representation by making the fields private has no benefit. However, I'd prevent callers from modifying a Point once it has been constructed:

public class Point {
    public final int x;
    public final int y;
    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }
}

so that a class that actually wishes to encapsulate its state can return its Point without leaking its internal representation, and use a given Point in its representation without capturing it. This also fits nicely with the mathematical notion of a point, which has no identity or changing state.

In designing the program the Agents playing the Game need access to the Board's state (so they can decide what to move). They also need to pass this move to the Game so it can validate it as a legal move. And during deciding what to move pieces are grouped into Threats with a start and end Points.

Board, Threat and Point objects don't really do anything. They are just there to store related data that can be accessed in a human readable way.

Now this sounds like a wasted opportunity for encapsulation: The agents should really not be permitted to arbitrarily modify the board, but be restricted to legal moves. Why is it the responsibility of class Game to decide what a legal move is, when the state being updated resides in class Board? If the Board were to validate the moves itself, no caller, and in particular no agent, could violate the rules of the game:

public class Board {
    // private fields with state

    // public methods to query state

    public void perform(Move move) throws IllegalMoveException;
}

Upvotes: 25

Mechkov
Mechkov

Reputation: 4324

Public fields break the rule of encapsulation i.e protection of the data. Yes, they do hold data but by having your instance variable PUBLIC it can be accessed by any class out there in your workspace. Instance variables can be protected as well as private.Your getter and setter methods are used just so you can modify the data that your class's instance variables hold. Usually your setter methods would have some kind of validation which is why we have to protect the instance variables of corrupt data (by marking them private or protected)

In the example above you have a constructor,which is initializing your inst. variable, but the chances are that you, as the developer of this class, has the rights and know what to data to insert in order to keep the integrity of your class. Someone else working on your class might not be aware of that and might access your variables by breaking the encapsulation and your program as a whole.

Consider x=-10; when x can only be from 0 to 100 (for example). I would recommend sticking to the encapsulation principles. Hope this helps!

Upvotes: 1

SetSlapShot
SetSlapShot

Reputation: 70

I see no problem with this. If a sin, it's at least not a mortal one. Vectors are another approach, but from what I've gathered vectors in java require too much overhead.

Upvotes: 1

James
James

Reputation: 2376

It's not always a sin to leave a field public, but you limit yourself severely in that you're coupling the implementation to the classes using it. Say later you want to add a listener that notifies you anytime the value in X is set. You have no way to do this without refactoring everything. If you implement setX() and hide the field itself, you will only have to change the implementation of setX() to notify you that a change was made with no change to classes utilizing this method.

Upvotes: 19

Roman Goyenko
Roman Goyenko

Reputation: 7070

If you know the interface won't change, it's perfectly legal to have the variable public. The problem is as the programs get more complex you would need to change the access to the field, but modern IDEs make refactoring easy, so I would say go ahead.

Upvotes: 5

Platinum Azure
Platinum Azure

Reputation: 46183

Java's "rules" aren't absolute. In your case, when you're using objects only to store data and not providing critical behaviors, it is perfectly okay to leave the fields public.

On the other hand, for fields that you don't need or want to expose to the user, because they might only be relevant in an internal context, then you SHOULD mark the fields private and only provide getters and/or setters if you really need/want to.

The more complicated your object, the more important it is to ensure a consistent state between operations, and therefore the more likely the programmer will be to keep the object's state well encapsulated.

Upvotes: 4

Dave Newton
Dave Newton

Reputation: 160181

Yes and no.

No, if: you're certain of your scope, and don't need anything that expects normal Java properties (getters/setters), then it's likely not a big deal.

yes, if: some of that behavior may change, like you need to abstract a calculation affecting x or y without affecting calling code, or you're using something that expects getters and/or setters.

In general, it's easiest to follow the normal Java property pattern--it eliminates one type of risk. And it's one reason I wish Java had real properties.

Upvotes: 4

Related Questions