Say I have a class called Truck
and one of the private member variables is of class Wheel
. A getter for the Wheel
variable, getWheel
, would return a reference to it, as follows:
class Truck{
private Wheel wheel;
Truck(){
wheel=new Wheel();
}
Wheel getWheel(){
return this.wheel;
}
}
class Wheel{
int color;
}
Now, whoever calls getWheel
will be able to modify the private member object at will:
class me{
public static void main(String[] args){
Truck ye=new Truck();
Wheel v=ye.getWheel();
v.color=2;
}
}
This would defeat encapsulation, wouldn't it?
What would be the right remedy for this?
It simply sets the field to this value. The generated getter/setter method will be public unless you explicitly specify an AccessLevel , as shown in the example below. Legal access levels are PUBLIC , PROTECTED , PACKAGE , and PRIVATE . You can also put a @Getter and/or @Setter annotation on a class.
An object user can use the public methods, but can't directly access private instance variables. You can make methods private too. Object users can't use private methods directly.
The reason for declaring the getters and setters private is to make the corresponding part of the object's abstract state (i.e. the values) private. That's largely independent of the decision to use getters and setters or not to hide the implementation types, prevent direct access, etc.
We require a setter method to update the value of a private variable from outside of the class and a getter method to read the value of that variable. It allows developers to control how the main variables in the code are accessed and updated.
The usual approaches are:
Wheel
)Wheel
immutable (any time you want to change it, you create a new one instead, constructed with the new color)Wheel
, return an immutable interface on Wheel
that only exposes getters, no mutation operationspublic
for the getter. Then classes within the package could set the color of Wheel
, but classes outside the package cannot. (I prefer #3 in this situation for the clear separation, but this works too if you're crossing a visibility boundary.)That third option is one of the reasons why making instance variables (fields) non-private
is often considered poor practice.
Here's #3 in more depth, just because it's more complicated than #1 and #2, not because it's necessarily better (it isn't, design choices are made in context).
A read-only interface, typically public or package-private depending on how you're going to use all of this stuff:
public interface Wheel {
int getColor();
}
The concrete class, typically package-private (could be a private static nested class within Truck
if that's the only place it's used):
class WheelImplementation implements Wheel {
private int color;
WheelImplementation(int color) {
this.color = color;
}
public int getColor() {
return this.color;
}
void setColor(int color) {
this.color = color;
}
}
Truck
, typically same visibility as Wheel
:
public class Truck {
private WheelImplementation wheel;
Truck(){
this.wheel = new WheelImplementation(/*...initial color...*/);
}
Wheel getWheel() {
return this.wheel;
}
}
Sure, that can be defeated through reflection, but generally you design an API for use, rather than for abuse. :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With