How do I prevent the modification of a private fie

2019-01-29 18:10发布

Imagine that I have this class:

public class Test
{
  private String[] arr = new String[]{"1","2"};    

  public String[] getArr() 
  {
    return arr;
  }
}

Now, I have another class that uses the above class:

Test test = new Test();
test.getArr()[0] ="some value!"; //!!!

So this is the problem: I have accessed a private field of a class from outside! How can I prevent this? I mean how can I make this array immutable? Does this mean that with every getter method you can work your way up to access the private field? (I don't want any libraries such as Guava. I just need to know the right way to do this).

10条回答
萌系小妹纸
2楼-- · 2019-01-29 18:48

If you can use a List instead of an array, Collections provides an unmodifiable list:

public List<String> getList() {
    return Collections.unmodifiableList(list);
}
查看更多
Anthone
3楼-- · 2019-01-29 18:48

Yes, you should return a a copy of the array:

 public String[] getArr()
 {
    return Arrays.copyOf(arr);
 }
查看更多
成全新的幸福
4楼-- · 2019-01-29 18:57

The nub of the problem is that you are returning a pointer to a mutable object. Oops. Either you render the object immutable (the unmodifiable list solution) or you return a copy of the object.

As a general matter, finality of objects does not protect objects from being changed if they are mutable. These two problems are "kissing cousins."

查看更多
Bombasti
5楼-- · 2019-01-29 18:58

Returning an unmodifiable list is a good idea. But a list that is made unmodifiable during the call to the getter method can still be changed by the class, or classes that are derived from the class.

Instead you should make it clear to anybody that extends the class that the list should not be modified.

So in your example it could lead to the following code:

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Test {
    public static final List<String> STRINGS =
        Collections.unmodifiableList(
            Arrays.asList("1", "2"));

    public final List<String> getStrings() {
        return STRINGS;
    }
}

In the above example I've made the STRINGS field public, in principle you could do away with the method call, as the values are already known.

You could also assign the strings to a private final List<String> field made unmodifiable during construction of the class instance. Using a constant or instantiation arguments (of the constructor) depends on the design of the class.

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Test {
    private final List<String> strings;

    public Test(final String ... strings) {
        this.strings = Collections.unmodifiableList(Arrays
                .asList(strings));
    }

    public final List<String> getStrings() {
        return strings;
    }
}
查看更多
登录 后发表回答