Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getter for private member object in Java

Tags:

java

oop

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?

like image 670
Fresh Air Avatar asked Mar 31 '17 07:03

Fresh Air


People also ask

Can getter setter be private?

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.

Can an object be private members in Java?

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.

Can getters and setters be private Java?

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.

Do private variables need getters and setters?

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.


1 Answers

The usual approaches are:

  • Make a defensive copy (e.g., return a copy of Wheel)
  • Make Wheel immutable (any time you want to change it, you create a new one instead, constructed with the new color)
  • Don't return Wheel, return an immutable interface on Wheel that only exposes getters, no mutation operations
  • As Sandeep said, make the setter more restricted than the getter, say, package-private for the setter and public 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. :-)

like image 110
T.J. Crowder Avatar answered Nov 12 '22 16:11

T.J. Crowder