4
public class foo {

private int a[];
private int b;

public foo(){
    a = new int[] {1,2};
    b= 3;
}

public int[] getA(){
    return this.a;
}

public int getB(){
    return this.b;
}

I noticed that it's possible to change a value of A by accessing the object like this:

foo f = new foo();
f.getA()[0] = 5; // f.a[0] changes to 5

but it isn't possible to do something like:

f.getB = 5; // gives error
f.getA() = new int[]{2,3};  //gives error

can someone explain me how this works, and how to prevent the user from changing the value of an array cell?

Thanks in advance.

0x5C91
  • 3,360
  • 3
  • 31
  • 46
Robdll
  • 5,865
  • 7
  • 31
  • 51
  • All java parameters and results are passed by value. Including arrays. But the value that is passed (for a reference type) is the reference. – Stephen C Feb 06 '15 at 12:38
  • http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value – robert Feb 06 '15 at 12:38
  • https://stackoverflow.com/questions/51426788/setters-and-getters-for-arrays/51427122 – Leponzo Apr 01 '21 at 16:58

3 Answers3

7

In Java, array is a reference type, which means that the value of an array expression is a reference to the actual array.

The return value of getA() is, therefore, a reference to the private array inside your object. This breaks encapsulation: you give access to your object's internals.

You can avoid this by either returning a reference to a copy of your internal array, or by providing a different API which only returns individual elements, say a method getA(int index).

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • Or OP could *not* use an array, but an immutable collection instead, like Guava's `ImmutableList` for example. – Zoltán Feb 06 '15 at 12:39
  • 1
    Your suggestion amounts to using a 3rd-party implementation of the same idea (`ImmutableList` still uses an array on the inside). – Marko Topolnik Feb 06 '15 at 12:42
  • 1
    Yes. I was just trying to complement your answer, not dispute it. – Zoltán Feb 06 '15 at 13:30
  • If we were nitpicking, there would also be the issue of a sixfold increase in memory consumption when going from `int` to `Integer`. But perhaps Guava has primitive type specializations for its immutable containers? – Marko Topolnik Feb 06 '15 at 13:36
  • 1
    @MarkoTopolnik: Not for immutable containers, but `Collections.unmodifiableList(Ints.asList(array))` would do. – Louis Wasserman Feb 06 '15 at 17:12
2

f.get(A) returns a reference to an array. You can access that array the way you access any array, and assign values to its elements with f.get(A)[i]=... (though it makes more sense to store the returned array in a variable, which would let you access that array multiple times, without having to call f.get(A) each time).

You can't, however, assign anything f.get(A) via f.get(A)=.., since a method call is not a valid left side of an assignment operator. For all you know, a call to f.get(A) may generate a new array that is not referred to by a member of the foo class, so assigning f.get(A)= new int[5]; would make no sense, since there would be no variable in which to store the new array. The same explanation applies to f.getB() = 5;.

Eran
  • 387,369
  • 54
  • 702
  • 768
0

Instead of giving away the array, to allow the caller to do what they like with it you can use an indexed getter

public int getA(int n){
    return this.a[n];
}

public void setA(int n, int x) {
    this.a[n] = x;
}

Now, the caller has no access to the array and cannot change it without you knowing.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130