0

In developing my most recent project I discovered something that breaks the encapsulation and visibility rules as i understand them.

In my GUI class I created several class variables for the textfields and buttons in my app and set them all to be private. I also set up getters for the buttons and text fields that return the values of the private members. In my SqlStatements class I reference the getters and then call setText() method on the getters and it changes the value of the private member fields. How is this possible?

For instance:

public class InitGUI {
    public static JTextField getfNameField() {     <---- getter for JTextField
        return fName;
    }

    private static JTextField fName;   <---- JTextField variable.
}

public class SqlStatements {
    // how is this able to change the value of a private member?
    InitGUI.getmNameField().setText("");
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Keith
  • 123
  • 4
  • 10
  • giving access to the private member via a method isn't keeping it private. If that makes sense. – Breavyn Jul 22 '13 at 11:08
  • I thought that outside of using a getter and or a setter on a private member , it couldnt be touched from outside the class. – Keith Jul 22 '13 at 11:10
  • Access modifiers don't control access, it is always possible to access private outside the class if you want through reflection. Though I realize that isn't the case here but something you probably also didn't know. – Esailija Aug 10 '13 at 18:31

6 Answers6

11

You confuse immutability with visibility. By providing getter for a private field (you break encapsulation) you expose it's methods to the outside world. (possibly some methods that changes the inner state of the fields - and your class as a consequence).

gyorgyabraham
  • 2,550
  • 1
  • 28
  • 46
  • I thought that by not providing a setter method for the private textfield that they would not be modifiable from outside the class. – Keith Jul 22 '13 at 11:16
  • 2
    @Keith: re, `"I thought that..."` -- well we all make mistakes, and now you know better. Better though would be to give your class a `public void setFNameText(String text)` method and `getFNameText()`, that prevents direct exposure to the Swing component. – Hovercraft Full Of Eels Jul 22 '13 at 11:21
  • I think i understand what you mean. By doing it the way i did , i exposed the TextField object and am not really changing the value in the private member field ? – Keith Jul 22 '13 at 11:23
  • @HovercraftFullOfEels _Better though ..._ that's exactly the way to go - would upvote if you move it to an answer :-) – kleopatra Jul 22 '13 at 11:26
  • 1
    @Keith a setter is for replacing the current reference (instance) sitting on that field. But if you provide a getter and the actual class is not immutable, you can change the inner state of that object (but yes, you can't replace it by another). – gyorgyabraham Jul 22 '13 at 11:43
  • 2
    I see what every one is talking about now. I should have called it like this public String getfNameField(){ return fname.getText();} That way I don't expose the entire textfield object. – Keith Jul 22 '13 at 11:51
2

how is this able to change the value of a private member ?

It's not changing the value of the fName private field - that is still a reference to the same JTextField. All you're doing is calling a method on that JTextField object.

Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
  • So what would the purpose of using private on the field member , if you can perform direct manipulations on it ? – Keith Jul 22 '13 at 11:13
  • Keith, if you design an immutable class and use it as a private field, and you provide a getter for that, you can't "perform direct manipulations" on it. Hope you are slowly getting the point. :) – gyorgyabraham Jul 22 '13 at 11:46
0

The purpose of getters and setters is to provide restrict/disable unwanted modification to private variables.

If this is not useful for you, no need to define them as Private

RaceBase
  • 18,428
  • 47
  • 141
  • 202
0

Your problem is that your assumptions on how private works is incorrect and because of this, your code exposes too much. Rather than,

public class InitGUI {
    public static JTextField getfNameField() {     <---- getter for JTextField
        return fName;
    }

    private static JTextField fName;   <---- JTextField variable.
}

public class SqlStatements {
    // how is this able to change the value of a private member?
    InitGUI.getmNameField().setText("");
}

You're better off doing:

public class InitGUI {
    // for heaven's sake, get rid of the statics!    
    private JTextField fName= new JTextField(10);   

    public String getfNameText() {     
        return fName.getText();
    }

    public void setfNameText(String text) {
       fName.setText(text);
    }

}

This will limit exposure of your components to only the exposures that you desire.

And again, please avoid using static unnecessarily.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Can you explain to me why using static methods are bad in this case ?Should i just be trying to pass the object around as a parameter ? – Keith Jul 22 '13 at 11:28
  • @Keith: use of static breaks the object oriented paradigm because you're no longer dealing with instances but with classes. Your code becomes harder to upgrade and debug, and you cannot use unit testing on it. It makes no sense to use an object-oriented language in a static way, since you will be throwing out over 80% of the power of the language by doing this. – Hovercraft Full Of Eels Jul 22 '13 at 16:56
0

You are confused about how members work in java. A private member is indeed private to begin with. When you give access to that member via a getter method it can indeed be 'modified'. The getter returns the instance of the class stored in the member. Whatever you do to this instance affects the private variable because they are both the same instance.

What it does not return however is the memory address that this member is stored at. Because of this you can't replace the instance by doing;

JTextField field = InitGUI.getmNameField();
field = new JTextField(); // this can't affect the original.

This post Is Java "pass-by-reference" or "pass-by-value"? may help explain java's reference by value nature.

Community
  • 1
  • 1
Breavyn
  • 2,232
  • 16
  • 29
0

You can provide public getters for specific fields of the JTextField rather then a getter of the whole object. This way you can avoid someone setting the fields.

e.g.

public String getFname(){
return fName.getXXXX();
}
sidshu
  • 315
  • 4
  • 13