2

I'm learning Java and I have some doubts. If defined a class with a private variable like

class test<A>{
private A var;
...
public A get(){
    return var;
}

}

Is the get method wrong? I think so because with this definition I can modify the variable "var" like

test<A> x = new test<A>();

A temp = x.get();

temp.set(*something*);

At the end x is changed (I tested it using Vector as A). If I understand correctly, this works because object reference (I miss C pointers, sob). Am I wrong? Maybe I don't understand the purpose of the keyword "private"! Thanks in advance!

Edit: I have no problems with "pass-by-reference" and "pass-by-value". I have doubts defining get() method for a private variable in a class (you don't say?). Please stop linking Is Java "pass-by-reference" or "pass-by-value"?

HegManga
  • 23
  • 3
  • All depends on what you want to do. Other classes like `TreeSet` have the same issue, that the underlying classes could change. It's up to a programmer to use them correctly. – markspace Jul 10 '19 at 16:56
  • The x is a passed-by-value it is not actually changing the actual value but instead a copy of the value. – Hayes Roach Jul 10 '19 at 17:03
  • But in this way "private" isn't very useful, the representation is exposed to errors! I think this way of define get is good iff x is a primitive type variable. – HegManga Jul 10 '19 at 17:07
  • Another option is to make a _read only_/immutable version of your `A` class (either an interface, with only the `getters`, or a simple view which constructs itself from instances of `A`) and return _that_ from the `get` method. This depends entirely on _what_ the `A` is though. – BeUndead Jul 10 '19 at 17:18
  • "read only_/immutable version o...." is a good way but I think it's easier define get() "normally" iff x is public, otherwise return a (deep) copy. Is it also a good way to write code in Java? – HegManga Jul 10 '19 at 17:29
  • Related: [Is encapsulation still one of the elephants OOP stands on?](https://softwareengineering.stackexchange.com/questions/358611/is-encapsulation-still-one-of-the-elephants-oop-stands-on) - Some will say you should avoid getters altogether in favor for a more behavioral approach, as getters introduce content coupling. – Vince Jul 10 '19 at 18:22

4 Answers4

3

If your getter method is returning a reference to a mutable object, then this greatly weakens the quality of the encapsulation provided by your class, because it becomes possible to modify the state of an instance of your class without calling a method of the class.

One standard strategy to guard against this problem is what J. Bloch calls defensive copies (Effective Java, 3rd edition, Item 50: "Make defensive copies when needed").

This would mean creating a copy of var in the getter method, and returning that copy instead. How to do this depends on the design of A.

Because A is a type parameter, making a copy of the instance requires additional support in the design. To see how to achieve this using Java's cloning mechanism, see my answer to the post "Does it make sense to create a Copyable type interface instead of using Cloneable?".

SDJ
  • 4,083
  • 1
  • 17
  • 35
0

If this is a problem, you can create a façade to protect your variable

public class Facade extends A {
  A myObj;

  public Facade (A obj) {
    myObj = 
  }

  public A get(){
    return myObj.get();
  }

  public B set(Object val) {
    throw new RuntimeException("Setting is not allowed");
  }
}
ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • thanks. It's ok define get() "normally" iff x is public, otherwise return a (deep) copy? Is it a good way to write code in Java? I'm a "beginner" in Java. – HegManga Jul 10 '19 at 17:42
  • @HegManga it all depends on the method's requirements. Not every object needs to be immutable – ControlAltDel Jul 10 '19 at 17:57
  • Whether or not to provide a getter depends more on the API that the object type is to present. Think of 'getX' as a required behavior and 'private V value' as the way that required behavior is implemented. Normally, the implementation is hidden from the API. That frees the implementer to change the implementation without breaking the API. – Thomas Bitonti Jul 11 '19 at 15:29
  • I'd stay away from copy issues, for now. There are too many issues to explain, and they won't stick very well at a beginning level. The main case which is worth presenting is when returning collection type values, and whether the caller should have the ability to update the returned collection. In many cases, caller updates to a returned collection are forbidden. – Thomas Bitonti Jul 11 '19 at 15:31
  • But, the way to safely return collection type values is *not* to make a copy of the collection. That is likely terribly inefficient. Better, java provides unmodifiable collections, for example, 'Collections.unmodifiableSet(aSet)'. – Thomas Bitonti Jul 11 '19 at 15:34
0

This might be a bit too much detail for just starting, but you might review class java.util.concurrent.atomic.AtomicReference<V>, which is very similar to your example.

Generally speaking, placing instance variables in private variables, while providing access to the variable using a getter and a setter, is standard practice.

Note that your class name should be capitalized, type parameter 'V' is more standard, and the variable name would more usually be 'value'. Also, try to pick a more communicative name for the class. (Type parameter type variable could be 'ValueType', which would fit some preferences. But, single character type variable names are more usual.)

public class Wrapper<V> {
    private V value;
    public V get() {
        return value;
    }
    public void set(V value) {
        this.value = value;
    }
}
Thomas Bitonti
  • 1,179
  • 7
  • 14
0

I'd add some other point here: as others have said, you hand out the object reference and it can be modified, which could be bad.

Object orientation is about keeping the data and the code that works on it in one place. If you need getters, think what the callers of the getters need to do, and whether that action should rather be a method on the class that has the data. Your code could suffer from the Feature Envy code smell, as it violates the Tell, Don't Ask principle.

To fix this, remove the getter, and introduce new methods as needed. For example, if you have some data object that needs to get printed, you could pass the Printer to the object and have it print itself to the given Printer.

If you're dealing with a collection class (just a guess from your template parameter), you may need to keep the getter, but then you're probably not concerned with the caller changing the value anyway.

Robert
  • 7,394
  • 40
  • 45
  • 64