4

Since a few months I'm having a Java course and I'm trying to make a simple version of a pokemon game. Until now everything went pretty well but now I'm having troubles.

I have my map with obstacles stored in a class in an Array (private) and use a get method to use the Array in other classes. Somehow these other classes change the Array in the first class.

How is this possible?

Farvardin
  • 5,336
  • 5
  • 33
  • 54
Wim
  • 378
  • 2
  • 6
  • 14
  • 2
    You should share code, so that people can help you. – CuriousMind May 07 '15 at 17:19
  • Read [this](https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value), it explains how Java handles passing around objects. You might want to brush up on pointers and references too. – Floegipoky May 07 '15 at 17:26
  • take a look at this too http://stackoverflow.com/questions/1771744/accessing-private-variables-in-java-via-reflection – Kick Buttowski May 07 '15 at 17:29
  • If you're providing access to the Array with a get() method, then you're giving others the ability to modify the array once they have it. The array is the same object, i.e. it might be defined one place, but get() provides a pointer, if you will, to the same array, so that updates to the array will be seen by anybody "pointing" to that array, i.e. using a reference to the array. – swingMan May 07 '15 at 18:45

4 Answers4

6

Private does not mean it can't be mutated. Private means the reference of that object cannot access directly using the parent object. If you have a getter and which return object reference then any object which has that instance can mutate it.

Eranda
  • 1,439
  • 1
  • 17
  • 30
  • Thanks that makes it clear. But how can i acces a private instance without giving that reference in a getter? – Wim May 07 '15 at 17:30
  • Here what you beed to do is make your array immutable. That can be done by returning it as a unmodifiable list using Collections.unmodifiableList(Arrays.asList(your _array)) in your getter method. – Eranda May 07 '15 at 17:38
4

Yes. By using reflection, you can access your private field without giving reference methods.
For example:

Field field = YourClass.class.getDeclaredField("fieldName");
field.setAccessible(true); // Force to access the field
// Set value
field.set(yourClassInstance, "Something");
// Get value
Object value = field.get(yourClassInstance);
3

private doesn't mean that you can't change the value of particular thing. when you make a variable private it can't be directly access outside the class. This means that you are no longer able to access a private variable in a class like follows

class A{
    private int x = 10;
}

class B{
    public void m(){
         A a = new A();
         a.x = 20; // This is a compile error. Because x is not visible to outside of class A
    }
}

Though still you are able to access the variable through a public method. That is what we normally call as encapsulation. e.g.

class A{
    private int x = 10;
    public int getX(){
        return x;
    }
    public void setX(int val){
        x = val;
    }
}

class B{
    public void m(){
         A a = new A();
         a.setX(20); 
    }
}
0

Without seeing your code, it's hard to say what exactly is happening in your program. Maybe something like the following is happening.

Maybe you have a class that has a method that returns a mutable, private member. When you do this, and some other class calls this method, it will be able to change the content of the object that the private member variable refers to. Here is an example:

import java.util.Arrays;

class Example {

    // Private member variable
    private int[] data = { 1, 2, 3 };

    // Method that returns the private member variable
    public int[] getData() {
        return data;
    }

    public void showData() {
        System.out.println(Arrays.toString(data));
    }
}

public class Main {
    public static void main(String[] args) {
        Example example = new Example();

        // Prints: [1, 2, 3]
        example.showData();

        // Get the array
        int[] x = example.getData();

        // We can modify the array here!
        x[0] = 4;

        // Prints: [4, 2, 3]
        example.showData();
    }
}

This is because objects are arrays, and variables such as data and x are references to the same array object - there's only one array and data and x both refer to that one array. If you modify the array, you'll see the changes through both variables.

If you want to avoid this, then you shouldn't expose the array by returning it directly in the getData() method in class Example. You should make a copy of the array:

public int[] getData() {
    // Return a copy of the array
    return Arrays.copyOf(data, data.length);
}
Jesper
  • 202,709
  • 46
  • 318
  • 350
  • Thanks, the problem is exact that. But when i try the solution with the copy, it still changes the original array... – Wim May 07 '15 at 18:53
  • Then you're not making the copy correctly, or it's leaking out in some other way. – Jesper May 07 '15 at 19:48
  • public static int[][] clone2D(int[][] array) { int[][] clone = new int[array.length][]; int i; for (i = 0; i < array.length; i++) { clone[i] = Arrays.copyOf(array[i], array[i].length); } return clone; } that is the methode i created to get the array, and it is the only wat to get is. – Wim May 08 '15 at 11:07
  • With that you are only copying the top-level array. You also have to copy all the arrays inside the array! Otherwise you're just making a new array which refers to all the existing second-level arrays. – Jesper May 08 '15 at 11:59
  • Isn't that what i am doing with the for loop? – Wim May 08 '15 at 12:37
  • @WimVanLaer Hmmm... yes, you are. You'll have to carefully look at all of your code to check if a private member variable is leaking out somewhere. – Jesper May 08 '15 at 17:39