Passing References to Methods Java - java

I've been trying to solve a problem that requires a couple of methods:
IT LOOKS LIKE A LOT, but you don't really need to read the methods. Just know that I'm passing an int[][] to a method, changing the int[][] inside the method, then checking for equality to an int[][] outside the method.
public static boolean One(int[][] matrix){
matrix = transpose(matrix);
matrix = reverseRow(matrix);
return Arrays.deepEquals(matrix, changed);
}
public static boolean Two(int[][] matrix){
//180 degree clockwise
matrix = transpose(matrix);
matrix = reverseRow(matrix);
matrix = transpose(matrix);
matrix = reverseRow(matrix);
return Arrays.deepEquals(matrix,changed);
}
public static int[][] transpose(int[][] matrix){
for(int i = 0; i < N; i++) {
for(int j = i+1; j < N; j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
return matrix;
}
public static int[][] reverseRow(int[][] matrix){
for(int j = 0; j < N; j++){
for(int i = 0; i < N / 2; i++) {
int temp = matrix[j][i];
matrix[j][i] = matrix[j][N - i - 1];
matrix[j][N - i - 1] = temp;
}
}
return matrix;
}
public static int[][] reverseCol(int[][] matrix){
for(int col = 0;col < matrix[0].length; col++){
for(int row = 0; row < matrix.length/2; row++) {
int temp = matrix[row][col];
matrix[row][col] = matrix[matrix.length - row - 1][col];
matrix[matrix.length - row - 1][col] = temp;
}
}
return matrix;
}
The structure of the problem is as follows:
I have an int[][] of original numbers
I have an int[][] of numbers, that is a result of a transformation of the original numbers. Specifically, a 90 degree clockwise turn, and an 180 degree clockwise turn.
The actual problem is much bigger, but I think there's a rule against getting straight up answers to problems, so I cut it down to what I need.
The problem is this:
After I run method one, the original array becomes modified, so it's corrupted before I run method two.
For instance,
Original before method One:
1111
0000
0000
0000
Original after method One;
0001
0001
0001
0001
These changes happens right after I run transpose(matrix) and reverseRow(matrix). Note that in java debug mode, I can see original being changed when I step over these methods. I DIDN'T EVEN MENTION ORIGINAL. I modified a passed of a passed version of Original.
So, 3 questions:
I thought that objects passed to methods don't get changed unless you return the changed object and then set the original to the changed in main() or the original method? I'm not talking about transpose, or reverseRow, because those were supposed to change matrix inside method One.
I tested this out with a method using strings. My belief above held true. Are int[][]'s different?
How can I fix it so that original doesn't get changed? Or am I missing something really simple?

This is easiest to understand when you learn that Java variables hold references, not objects.
And those references are always passed by value, as discussed in the earlier question Is Java "pass-by-reference" or "pass-by-value"? .
This answer addresses your specific questions.
1) I thought that objects passed to methods don't get changed unless you return the changed object and then set the original to the changed in main() or the original method?
Objects don't get passed to methods. Java variables are references to objects. You can copy a java variable without copying the object.
If you pass a variable of reference type to a method, that method can't modify your variable. It can, however, modify the object referenced by the variable, if it's mutable.
2)I tested this out with a method using strings. My belief above held true. Are int[][]'s different?
The array is a mutable object that you're accessing through a reference.
The String is an immutable object. You're probably trying to change the caller's variable by assigning to the called method's variable.
3)How can I fix it so that original doesn't get changed? Or am I missing something really simple?
You can make a copy of the array before passing a reference to it to a method.
One way to do that for a one-dimensional array is to use System.arraycopy(). Your two dimensional array is constructed from multiple one-dimensional arrays, so you could use multiple calls to System.arraycopy() to copy it.
Other approaches are discussed in this question: How do I copy a 2 Dimensional array in Java? . Note that the accepted answer in the question omits the necessary step of creating the two-dimensional array.

In Java everything is passed by value. However, the confusing thing is that this value holds a reference to the original object.
Assigning a variable only changes what reference the input variable holds:
void doSomething(String str){
str = "New String"; // str variable now holds a reference to "New String"
// however, the original String Object was not changed
}
However, this does not change the original string. In fact, String is an immutable Object, along with all primitives int, double, etc. This leads me to the following statement:
The only way to change an input parameter of a calling function is to call a method of that parameter that mutates the object (e.g. param.setValue(newValue) or param[0] = newValue).
This allows us to make a couple observations:
Primitive types (char, int, double, etc.) can never be changed in a calling function because they don't contain any methods to mutate the data.
Immutable Objects (String, Integer, Double, etc.) can never be changed in a function, because by definition they do not contain methods that mutate the data.
Mutable Objects (StringBuilder, BigInteger, BigDecimal, etc.) can only change by calling mutator methods on the object (not by reassigning the variable). For arrays, you can think of array[0] = newValue, etc., as mutator methods on an Array akin to list.set(0, newValue) for a List.

Related

Need help using java.lang.reflect.Array to sort arrays

An interview question was to write this method to remove duplicate element in an array.
public static Array removeDuplicates(Array a) {
...
return type is java.lang.reflect.Array and parameter is also java.lang.reflect.Array type.
How would this method be called for any array?
Also not sure about my implementation:
public static Array removeDuplicates(Array a)
{
int end=Array.getLength(a)-1;
for(int i=0;i<=end-1;i++)
{
for(int j=i+1;j<=end;j++)
{
if(Array.get(a, i)==Array.get(a, j))
{
Array.set(a, j, Array.get(a, end));
end--;
j--;
}
}
}
Array b=(Array) Array.newInstance(a.getClass(), end+1);
for(int i=0;i<=end;i++)
Array.set(a, i, Array.get(a, i));
return b;
}
You may want to consider using a different data structure such as a hashmap to detect the duplicate (O(1)) instead of looping with nested for loops (O(n^2)). It should give you much better time complexity.
There are various problem with this code. Starting here:
if(Array.get(a, i)==Array.get(a, j))
Keep in mind that those get() calls return Object. So, when you pass in an array of strings, comparing with == simply will most likely result in wrong results (because many objects that are in fact equal still have different references --- so your check returns false all the time!)
So, the first thing to change: use equals() instead of == !
The other problem is:
end--;
Seriously: you never ever change the variable that controls your for loop.
Instead: have another counter, like
int numberOfOutgoingItems = end;
and then decrease that counter!
For your final question - check the javadoc; for example for get(). That reads get(Object array, int index)
So you should be able to do something like:
int a[] = ...;
Object oneValue = Array.get(a, 0);
for example.
Disclaimer. I have to admit: I don't know if the Array implementation is smart enough to automatically turn the elements of an int[] into an Integer object.
It could well be that you have to write code first to detect the exact type of array (if it is an array of int for example); to instead call getInt() instead of getObject().
Beyond that, some further reading how to use reflection/Array can be found here

Sorting an object array into another array based on a variable

I have a problem with a program I'm writing for a school assignment.
Essentially, before this piece of code, I already recieve and work with a bunch of information that I store into an array of objects. Now I have to sort this array (after it's sorted, I will have to calculate some things in the order of the PRIORITY variable).
presume I already have a MyClass[] array called input, that stores a finite amount of MyClass objects.
MyClass[] priorityArray = new MyClass[input.length];
for (int i=0; i<priorityArray.length; i++) {
int maxIndex = 0;
int maxPrivilege = input[i].returnPrivilege();
for (int j=1; j<input.legnth; j++) {
int currentPrivilege = input[j].returnPrivilege();
if (currentPrivilege > maxPrivilege) {
maxPrivilege = currentPrivilege;
maxIndex = j;
}
}
priorityArray[i] = input[maxIndex];
input[maxIndex].setPrivilege(-900000000);
}
the MyClass class if nothing fancy, but of course, contains a proper constructor, getter and setter methods and an integer variable "privilege".
I'm getting an error in my final tests of the program and, seeing as the program returns privileges as "-900000000", it has to have something to do with this part of the code.
It's also not even writing certain MyClass instances from the input array into the priorityArray array.
How can I clead this up? Help.
I'll rewrite my answer totally.
In this line
priorityArray[i] = input[maxIndex];
You are assigning object from one array to another array by reference. It means that there is only one object and you set value to -9000000 in the next line to it. Of course element in priorityArray will have the same changes. To fix it you need to clone your object here.

Shallow copying with primitives

From what I understand about Java (which is arguably pretty little =P), Java treats primitive values differently than objects. One example I can think of is that primitives are passed by value, while objects are passed via the value of their references.
Extending this, I have implemented code that creates an array of int, and shallow copied it over to a new array of int:
public class Test {
public static void main(String[] args){
int[] array = {2,3,4,5};
int[] copy = array;
copy[1] = 0;
for (int i : copy){
System.out.print(i);}
System.out.println();
for (int i : array){
System.out.print(i);}
}
}
However, the output is:
2045
2045
So, what puzzles me is why do both arrays change? I thought when we made a copy of the original array, we only copied over the values of the elements (since we are dealing with primitives)?
You didn't copy the array at all. What you did was make the references array and copy point to the same array in memory. Thus, when you change the array via one reference, the other reference will point to the same change.
Arrays are objects. When you set
int[] copy = array;
both copy and array refer to the same object. Your update
copy[1] = 0;
updates "both".
When you made the assignment copy[1] = 0, you told Java to take the array which copy refers to, go to position 1, and assign the value 0. Since you also have the following statement
int[] copy = array;
then copy and array refer to the same array in memory. You never really made a shallow copy, you only assigned another variable to point to the same array.
If you want to make a copy of the array, then you could try:
int[] copy = Arrays.copyOf(array, array.length);

whether return an array in Java is safe?

I am a new bird to Java and I am confused about returning an array in Java.
Below are my codes:
public class Pointer{
private final int[] data;
Pointer(){
data = new int[4];
data[0] = 1;
data[1] = 2;
data[2] = 3;
data[3] = 4;
}
public int[] test(){
return data;
}
public void print(){
int length = data.length;
int j;
for(j = 0; j < length; j++){
System.out.println(data[j]);
}
}
static public void main(String[] argv){
Pointer i = new Pointer();
int[] re = i.test();
i.print();
re[2] = 1;
i.print();
}
}
I though I returned an array of int, instead of the pointer to that, so the data should not be changed when I wrote re[2] = 1. How to make this Pointer Object immutable?
First, take a look at this documentation of the immutable class chapter in Josh Bloch's excellent book Effective Java. I know the site looks like it was made in 1997, but don't let that bother you. The information is good.
In order for your class to be immutable, you can't allow mutator methods (i.e. setters) or accessors (i.e. getters) on private data that are mutable. That negates the private-ness and creates a leaky abstraction.
You discovered an instance of the latter. The array you've exposed via a getter is mutable. This makes your class mutable. There is no way to make arrays immutable.
You have choices. Here are some:
In your getter, return a copy of the array in the class.
Have no getter, but allow something like getValue(int index) that retrieves the array value at the given index (with error handling like an IllegalArgumentException if the index is out of bounds).
In your getter, return an immutable collection constructed from the array like Collections.unmodifiableList(Arrays.asList(data));. See here for the documentation.
Arrays are objects in Java and objects are passed by reference (even though a reference is passed by value).
You can not pass the array itself by value.
What you can do is to instead return a copy of the array. This way changes to the returned array will not affect the internal array inside Pointer (if this is the behaviour you want).
public int[] test(){
return data.clone();
}
The only case when returning an array is safe is when the array is empty. Otherwise we need to return a copy. There are 2 ways to make a copy 1) arr.clone() 2) Arrays.copyOf()

How do I copy a two dimensional array of strings?

I'm working with a program that uses two-dimensional arrays of Strings (probably not that smart to begin with, but eh), and I'd like to write a function that takes one of these arrays (let's say array1), makes an independent copy, and returns it (let's say array2). However, when I then change a value in array2, it seems to be reflected in array1.
My function currently looks something like this:
public static String[][] copy(String[][] matrix, int n) {
String[][] out = new String[n+1][n+1];
for (int i = 0; i < n+1; i++)
for (int j = 0; j < n+1; j++) {
if(matrix[i][j] != null) {
String cp = new String(matrix[i][j]);
out[i][j] = cp;
}
}
return out;
}
I declare a new array of Strings, and then iterate through it, copying each value individually. When that didn't work, I even tried explicitly declaring a new string from each old string and putting that in the array instead.
Can anyone tell me where I'm going wrong?
I'm not sure what the n parameter is for, but if I needed such a function, I'd use something like this:
public static String[][] copy(String[][] matrix) {
String[][] copy = new String[matrix.length];
for (int idx = 0; idx < matrix.length; ++idx)
copy[idx] = matrix[idx].clone();
return copy;
}
You don't need to create a copy of the String, because they are immutable. As pointed out by Michael in the comments, the String(String) constructor might be useful if the original string was created as a substring of some very large string. Another use is when you are using String objects as locks (not recommended), and want a private instance to avoid deadlocks.
Also, your check to see whether an element is null before assigning is unnecessary; if you have your loops setup correctly, the element is guaranteed to be null. (And if it's not, what's the harm in overwriting it?)
Your method looks like it should work, though passing in n as a parameter makes it brittle, using the input array's length field would be better, and you could even handle jagged arrays that way.
Making a copy of the contents is not necessary, since Strings cannot be changed - which leads to the main question: What kind of changes are you making that seem to be reflected in the copy? Show us the code that does this.
Have a look at System.arraycopy. That way you can get rid of the inner loop.
Maybe Arrays.copyOf would be of some use?
I tried with your code : got exception
java.lang.ArrayIndexOutOfBoundsException
It's working for me, please try like this :
public static String[][] copy(String[][] matrix, int n)
{
String[][] out = new String[n][n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
if(matrix[i][j] != null) {
String cp = new String(matrix[i][j]);
out[i][j] = cp;
}
}
return out;
}
Take a look at this question Is Java pass by reference? It can be a little confusing how Java passes objects, but this would explain why making a change to one array also makes the change to your other array.
Your use of the 'n' parameter, as noted above is redundant, but also flawed by your code with n+1?? Your code would produce an ArrayIndexoutOfBoundsException if run something like:
String [][] m1 = { {"A", "B"}, {"C", "D" } };
String [][] m2 = copy(m1, 2);
Which presumably is how you intend it to be invoked?
It also limits your function to square 'matrices' of Strings.
But as for the problem you cited, I see no reason why the program should behave that way... I even ran it using the above call (but with n=1???) then changed
m2[0][1] = "X";
and m1 was unaffected as expected.
Even replacing the innermost code line to:
out[i][j] = matrix[i][j];
does not change this, as the compiler rewrites it to what you originally had. In fact a lot of the String sytax is simply syntactic sugar for StringBuffers (such as concatenation and assignment). eg the compiler will rewrite
String s = "Hello ";
s += "World"; // Makes it appear that String is builtin type!
to
String s = new String("Hello ");
s = new StringBuffer(s).append("World").toString();
Which is why is you have lots of string concatenation inside loops they can perform very poorly.
I do not understand why you are having the problem you cited either.
And as you are not modifying the parameter 'matrix', 'Pass By Reference' has nothing to do with it.

Categories