0

Sorry for my elementary Java question. There is the following class

public class Matrix {

    public final double[][] items;
    private final int rows_count,  columns_count;

    public Matrix( final int rows_count_, final int columns_count_)   {
        rows_count = rows_count_; columns_count = columns_count_;
        items = new double[rows_count][columns_count];
    }

    public Matrix(final double[][] data)  {
            rows_count = data.length;
            columns_count = data[0].length;
            items = new double[rows_count][columns_count];
            for (int i = 0; i < rows_count; i++)
                    for (int j = 0; j < columns_count; j++)
    }

    public Matrix copy () {
            Matrix AC = new Matrix(rows_count, columns_count);
            for (int i = 0; i < rows_count; i++) 
                    for (int j = 0; j < columns_count; j++) 
                            AC.items[i][j] = items[i][j];
            return AC;
    }

    public Matrix clone ()  { return this.copy }

    public void test (Matrix B)        {
            B = this.clone();
            B.items[0][0] = 1;
    }

Inside the method test the following assignment is done

B = A

Calling

    double[][] d = { { 1, 2, 3 }, { 4, 5, 6 }, { 1, 0, 1} };
    Matrix A = new Matrix(d);
    Matrix B= new Matrix(3,3);
    A.test(B);
    B.print();

the results are surprising. Despite

 B = this.clone()

the resulting B matrix is of zeros.

0.0 0.0 0.0 
0.0 0.0 0.0 
0.0 0.0 0.0 

It looks as if B is passed by the value :-) Rewriting test() so as

    public void test (Matrix B)        {
            B.items[0][0] = 1;
    }

the matrix B is modified correctly

1.0 0.0 0.0 
0.0 0.0 0.0 
0.0 0.0 0.0 

Where is the problem, probably incorrectly written copy/clone method? How to fix the problem and performs an assignment B = A? Thanks for your help.

justik
  • 4,145
  • 6
  • 32
  • 53

3 Answers3

1

The problem is, that clone returns a new instance, which is then modified. The instance of Matrix in B is not touched at all. Assigning a parameter of a function a new value does not change the variable passed and all changes are lost, after the function returns. You have to change the object passed, not the variable holding it, to archive a change outside the function.

To change B you can either change your test method to return B and then reasign it outside (which would make passing it useless).

Another way would be to make a copy function taking a Matrix as argument, which then updates it with the new date (without creating a new Matrix). The old copy even can then use this new function by first creating a new Matrix and then passing it to the new copy.

Edit: About your comment mentioning C++ and Pointers: In C++ (and many other languages) you are able to pass pointer to a function. If you do that, reasigning actually changes the passed variable outside of the function. In Java, this is not possible in this way (as far as I know). You can find more on this topic in this question

Community
  • 1
  • 1
Leon
  • 2,926
  • 1
  • 25
  • 34
1

There is a clone() method of the Object class. You could use it without overriding it. To be able to use it, you need to make sure you class implements Cloneable.

public class Matrix implements Cloneable {
    //...
}
Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • @ Lajos: Error: unreported exception CloneNotSupportedException; must be caught or declared to be thrown B = (Matrix)(this.clone()); – justik Aug 24 '16 at 09:22
  • @justik, does your Matrix class implement Cloneable? This is a perequisite to my answer as you can read in the answer. Your error states that you forgot to specify that Matrix implements Cloneable (http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/CloneNotSupportedException.html) – Lajos Arpad Aug 24 '16 at 09:42
0

The problem with your test() method is that it doesn’t return any object, thus not making any changes outside of the method.

Public void test (Matrix B) B in this case is a local variable, that means its lifetime begins with starting the method and ends when the method is finished. Java is CallByValue and not CallByReference, that means that you don’t pass the actual object reference inside the method but rather a new reference with the same value, like a copy.

B= this.clone(); Despite the fact that you assign B the clone of A, B is still only available inside this method and doesn’t affect the instance of B you passed into the method.

B.items[0][0] = 1; //You are still only altering the internal(local) variable of B and not the original instance of B. Since you don’t return B, all the changes inside this method are obsolete and B will be discarded.

For your Method to work you should design it like this:

Public Matrix test(Matrix B){
B = this.clone();
B.items[0][0] = 1;
return B;
}

Then you need to assign the call of this Method to B again like this:

double[][] d = { {1,2,3},{4,5,6},{1,0,1}};
Matrix A = new Matrix(d);
Matrix B = new Matrix(3,3);
Matrix B = A.test(B);
B.print();
Corovus
  • 38
  • 4