This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 4 years ago.
public class Test {
public static void main(String[] args) {
int[] oldList = {1, 2, 3, 4, 5};
reverse(oldList);
for (int i = 0; i < oldList.length; i++)
System.out.print(oldList[i] + " ");
}
public static void reverse(int[] list) {
int[] newList = new int[list.length];
for (int i = 0; i < list.length; i++)
newList[i] = list[list.length - 1 - i];
list = newList;
}
}
how come the method does not apply and still get 1 2 3 4 5?
thank you !
This is happening because Java is pass by value. This means that when you pass an argument into a method you are passing the reference to it, not the argument itself. The changes that you make inside the method are resolved but in this case you don't return the modified argument. Try this simple experiment to see what I mean:
public static void main(String[] args) {
int x = 0;
foo(x);
System.out.println(x);
}
public static void foo(int x) {
x = 4;
}
This program will print 0 because the changes are essentially discarded. To return the copied reference try this:
public static int[] reverse(int[] list) {
int[] newList = new int[list.length];
for (int i = 0; i < list.length; i++) {
newList[i] = list[list.length - 1 - i];
}
return newList;
}
And in your main:
oldList = reverse(oldList);
A much more in depth answer:
Is Java "pass-by-reference" or "pass-by-value"?
There are couple of issues. You can fix it with below two Options:
Option 1:
1) Make a new copy of original array and use it as reference array to reverse
2) In reverse function, update values of array that has been passed in parameter and reverse it using reference array
public class Test {
public static void main(String[] args) {
int[] oldList = {1, 2, 3, 4, 5};
reverse(oldList);
for (int i = 0; i < oldList.length; i++)
System.out.print(oldList[i] + " ");
}
public static void reverse(int[] list) {
// create a copy of initial array to use it to reverse
int[] newList = Arrays.copyOf(list,list.length);
for (int i = 0; i < list.length; i++)
// update original array and reverse it. Calling method still have reference to this array
list[i] = newList[list.length - 1 - i];
}
}
Console Output:
PS: Here the idea is to ensure the reference of array remains the same. You can do it using another array as reference array or using another local variable and swapping two values inside array or doing XOR between i and n-i-1 variable. There are n number of ways out of which 1 has been shared above.
Option 2:
1) No need to copy the reference of the old array to new array in reverse method
2) Return the new array reference back to the calling method
3) For above point you will also have to change the return type of reverse function
4) Save the new reference of array in a variable in the main method and then print from the same.
Please find my comments below:
public class Test {
public static void main(String[] args) {
int[] oldList = {1, 2, 3, 4, 5};
//save the return list to a variable
int[] newList= reverse(oldList);
for (int i = 0; i < newList.length; i++)
//print the data from new list
System.out.print(newList[i] + " ");
}
// change the return type
public static int[] reverse(int[] list) {
int[] newList = new int[list.length];
for (int i = 0; i < list.length; i++)
newList[i] = list[list.length - 1 - i];
//remove this line as there is no point of copying old array back to new array
// list = newList;
//retrun newlist reference to the calling method
return newList;
}
}
Console Output:
This is happening because you are altering the new area, and the statement list = newList; does not affect the original list because java is pass by value and you only overwrite the pointer in the reverse function.
Instead you should return the new array and overwrite the old one like:
public class HelloWorld
{
public static void main(String[] args) {
int[] oldList = {1, 2, 3, 4, 5};
oldList = reverse(oldList);
for (int i = 0; i < oldList.length; i++)
System.out.print(oldList[i] + " ");
}
public static int[] reverse(int[] list) {
int[] newList = new int[list.length];
for (int i = 0; i < list.length; i++)
newList[i] = list[list.length - 1 - i];
return newList;
}
}
Java is always pass-by-value. What does this mean for object- and array-references? In Java, we handle objects only through references. References live on the stack, the actual objects live on the heap. References store the address where the actual object resides.
If you pass an object to a method, the reference-value (i.e. the address where the object resides) is passed as parameter. For some method foo(Object o) this means: if you re-assign o in foo's body (e.g. through o = new Object();, this change will not be visible outside the method.
To fix you problem, you would either have to do the reversal in-place (i.e. on list directly) or return your newly created array. Here is an implementation of the in-place variant:
public static void reverse(final int[] values) {
final int length = values.length;
for (int i = 0; i < length / 2; ++i) {
final int j = length - i - 1;
swap(values, i, j);
}
}
public static void swap(final int[] values, final int i, final int j) {
int tmp = values[i];
values[i] = values[j];
values[j] = tmp;
}
For an implementation of the return-variant, look at one of the other answers since every other answer seems to implement a variant on this.
Some remarks on your code:
Giving an array-parameter the name list is confusing. A list is not the same as an array, the are different datastructures with differen properties.
You should never neglect the optional parentheses around one-line if-, else-, for-,... bodies. This can be the source of nasty bugs and is regarded as bad practice.
You should take a little bit more care wrt. your indentation. Keep in mind that your source code is a means of coummuncation. The more semantics you can transport through simple rules (like indentation), the easier it is to understand your source code.
Related
Today, I have a question about the list. I want to put the variables in the array into the another array. For example, if there is a int[] list1 and int[] list2 = {1,2,3,4} and int[] list3 = {5,6,7}, I want to put the variables in list2 and list3 into the list1, making the list1 into {1,2 + 5, 3 + 6, 4 + 7}. Below is the code that I have made:
public int function(int[] parameter) {
int[] intlist;
for (int i = 0; i < intlist.length; i++) {
intlist = addVariable(int[] anotherlist); //the function addVariable(int[] parameter) gets a
//int[] as a paremeter, makes a new int[](which has the same size as the parameter) at the
//inside of the function, add parameter's each and every varibles into the new int[] and
//returns the new int[]. and anotherlist keeps changing in the for statement. This is the
//function that I want to make.
}
return intlist;
}
Next is the code of addVariable:
public static int[] addVariables(int[] intlist) {
int[] intlist2 = new int[intlist.length];
for(int i = 0; i < intlist.length; i++) {
intlist2[i] += intlist[i];
}
return intlist2;
}
So, what I want to do is making the intlist whole, by using for statement and addVariable function. But, the addVariable fuction is not complete, as the two lists can have different size, and the function that I've made didn't consider this. Also, the changes that I've made in the for statement doesn't last, so this is a problem as well. How can I fix this situation? Please help!
This is the code you need
public class Test {
public static void main(String args[]) {
int[] intlist = {1, 2, 3, 4};
int[] anotherlist = {5, 6, 7};
Test.addVariables(intlist, anotherlist);
for (int i : intlist) {
System.out.println(i);
}
}
public static void addVariables(int[] intlist, int[] anotherlist) {
for (int i = intlist.length - 1, j = anotherlist.length - 1; i >= 0 && j >= 0; i--, j--) {
intlist[i] += anotherlist[j];
}
}
}
I was trying to use this code I made to reverse a array. I don't understand why I was getting [I#7a84639c as my output in my console.
And for some reason why doesn't this method actually save my reversed array into the array? If i add a print at the bottom of x[i]=c[i]; it shows the array reversed but when i add a call for example karn[0] it shows that my array isn't actually reversed. I want to solve this by staying true to the code i made.
import java.util.Arrays;
public class HelloWorld {
public static void main(String[] args) {
int[]karn={1,2,3};
rev(karn);
System.out.println(karn.toString());
}
public static void rev(int[]x){
int[]c=new int[x.length];
for(int i=x.length-1;i>-1;i--){
c[i]=x[i];
x[i]=c[i];
}
}
}
in your rev method you are using a local variable for c. So this value will not be transferred over to your main method. You must return your array and assign the value to your old array:
public static int[] rev(int[]x){
//Creates new array this array is different from karn and local to the method.
//nothing outside of this method can see this array.
int[]c=new int[x.length];
for(int i = 0; i < c.length; i++){
//Here is where we are swapping the values by placing the first
//value at the last spot of the array and so on
c[c.length - i - 1] = x[i];
}
//we must return the new array we made and assign it to karn so our
//changes will be saved and seen outside of the method
return c;
}
In main method you must assign the changes of the rev method to karn. You can assign the value and display it like so:
karn = rev(karn);
//for each loop
for(int i : karn)
System.out.println(i);
//traditional for loop
for(int i = 0; i < karn.length; i++)
System.out.println(karn[i]);
Arrays do not have a default toString() method. That is why you are seeing the values of the array as you would like. You need to iterate through the array to display them to the console.
Your initial approach looked almost correct, you can do this in-place or through a copy. I posted a comment showing a copy, so I thought I might expand on in-place. I would start with a simple swap method, like
private static void swap(int[] x, int i, int j) {
if (i != j) {
int t = x[i];
x[i] = x[j];
x[j] = t;
}
}
Then you only need to iterate the first half of the array, swapping each element with the same index (but from the other half). Like,
public static void rev(int[] x) {
for (int i = 0; i < x.length / 2; i++) {
swap(x, i, x.length - i - 1);
}
}
Then you might call it like
public static void main(String[] args) throws IOException {
int[] karn = { 1, 2, 3 };
rev(karn);
System.out.println(Arrays.toString(karn));
}
for an output of
[3, 2, 1]
I'm learning and understanding Java now, and while practising with arrays I had a doubt. I wrote the following code as an example:
class example
{
public static void main(String args[])
{
String a[] = new String[] {"Sam", "Claudia", "Josh", "Toby", "Donna"};
int b[] = new int[] {1, 2, 3, 4, 5};
for(int n=0;n<5;n++)
{
System.out.print (a[n] + "...");
System.out.println (b[n]);
}
System.out.println (" ");
java.util.Arrays.sort(a);
for(int n=0;n<5;n++)
{
System.out.print (a[n] + "...");
System.out.println (b[n]);
}
}
In a nutshell, this class created two arrays with five spaces each. It fills one with names of characters from the West Wing, and fills the other with numbering from one to five. We can say that the data in these two strings corresponds to each other.
Now, the program sorts the array with the names in it using Arrays.sort(). After printing the array again, you can see that while the names are now in alphabetical order, the numbers do not correspond anymore as the second array is unchanged.
How can I shuffle the contents of the second array to match the sort requirements of the first? The solution must also be flexible to allow for changes in the scope and size of the program. Please do not post any answers asking me to change my methodology with the arrays, or propose a more 'efficient' way of doing things. This is for educational purposed and I'd like a straight solution to the example code provided. Thanks in advance!
EDIT: I do NOT want to create an additional class, however I think some form of sorting through nested loops might be an option instead of Arrays.sort().
Below is the code without using any Map Collection, but if you want to use Map then it becomes very easy. Add both the arrays into map and sort it.
public static void main(String args[]) {
String a[] = new String[] {
"Sam", "Claudia", "Josh", "Toby", "Donna"
};
int b[] = new int[] {
1, 2, 3, 4, 5
};
for (int n = 0; n < 5; n++) {
System.out.print(a[n] + "...");
System.out.println(b[n]);
}
System.out.println(" ");
//java.util.Arrays.sort(a);
/* Bubble Sort */
for (int n = 0; n < 5; n++) {
for (int m = 0; m < 4 - n; m++) {
if ((a[m].compareTo(a[m + 1])) > 0) {
String swapString = a[m];
a[m] = a[m + 1];
a[m + 1] = swapString;
int swapInt = b[m];
b[m] = b[m + 1];
b[m + 1] = swapInt;
}
}
}
for (int n = 0; n < 5; n++) {
System.out.print(a[n] + "...");
System.out.println(b[n]);
}
}
Some people propose making a product type. That is feasible only if the amount of elements is small. By introducing another object you add object overhead (30+ bytes) for each element and a performance penalty of a pointer (also worsening cache locality).
Solution without object overhead
Make a third array. Fill it with indices from 0 to size-1. Sort this array with comparator function polling into the array according to which you want to sort.
Finally, reorder the elements in both arrays according to indices.
Alternative solution
Write the sorting algorithm yourself. This is not ideal, because you might make a mistake and the sorting efficiency might be subpar.
You have to ZIP your two arrays into an array which elements are instances of a class like:
class NameNumber
{
public NameNumber(String name, int n) {
this.name = name;
this.number = n;
}
public String name;
public int number;
}
And sort that array with a custom comparator.
Your code should be something like:
NameNumber [] zip = new NameNumber[Math.min(a.length,b.length)];
for(int i = 0; i < zip.length; i++)
{
zip[i] = new NameNumber(a[i],b[i]);
}
Arrays.sort(zip, new Comparator<NameNumber>() {
#Override
public int compare(NameNumber o1, NameNumber o2) {
return Integer.compare(o1.number, o2.number);
}
});
You should not have two parallel arrays. Instead, you should have a single array of WestWingCharacter objects, where each object would have a field name and a field number.
Sorting this array by number of by name would then be a piece of cake:
Collections.sort(characters, new Comparator<WestWingCharacter>() {
#Override
public int compare(WestWingCharacter c1, WestWingCharacter c2) {
return c1.getName().compareTo(c2.getName();
}
});
or, with Java 8:
Collections.sort(characters, Comparator.comparing(WestWingCharacter::getName));
Java is an OO language, and you should thus use objects.
What you want is not possible because you don't know internally how Arrays.sort swap the elements in your String array, so there is no way to swap accordingly the elements in the int array.
You should create a class that contains the String name and the int position as parameter and then sort this class only with the name, providing a custom comparator to Arrays.sort.
If you want to keep your current code (with 2 arrays, but this not the ideal solution), don't use Arrays.sort and implement your own sorting algorithm. When you swap two names, get the index of them and swap the two integers in the other array accordingly.
Here is the answer for your query.
public class Main {
public static void main(String args[]){
String name[] = new String[] {"Sam", "Claudia", "Josh", "Toby", "Donna"};
int id[] = new int[] {1, 2, 3, 4, 5};
for ( int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int dtmp=0;
String stmp=null;
if (id[i] > id[j]) {
dtmp = rate[i];
id[i] = id[j];
id[j] = dtmp;
stmp = name[i];
name[i]=name[j];
name[j]=stmp;
}
}
}
System.out.println("Details are :");
for(int i=0;i<n;i++){
System.out.println(name[i]+" - "+id[i]);
}
}
}
The same solution, as a function that can be added to some utils class:
public static final boolean INCREASING = true;
public static final boolean DECREASING = false;
#SuppressWarnings("unchecked")
public static <T extends Comparable, U extends Object> void bubbleSort(ArrayList<T> list1, ArrayList<U>list2, boolean order) {
int cmpResult = (order ? 1 : -1);
for (int i = 0; i < list1.size() - 1; i++) {
for (int j = 0; j <= i; j++) {
if (list1.get(j).compareTo(list1.get(j+1)) == cmpResult) {
T tempComparable = list1.get(j);
list1.set(j , list1.get(j + 1));
list1.set(j + 1 , tempComparable);
U tempObject = list2.get(j);
list2.set(j , list2.get(j + 1));
list2.set(j + 1 , tempObject);
}
}
}
}
The arrays are not linked in any way. Like someone pointed out take a look at
SortedMap http://docs.oracle.com/javase/7/docs/api/java/util/SortedMap.html
TreeMap http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html
import java.util.*;
class mergeArrays2
{
public static void main(String args[])
{
String a1[]={"Sam", "Claudia", "Josh", "Toby", "Donna"};
Integer a2[]={11, 2, 31, 24, 5};
ArrayList ar1=new ArrayList(Arrays.asList(a1));
Collections.sort(ar1);
ArrayList ar2=new ArrayList(Arrays.asList(a2));
Collections.sort(ar2);
System.out.println("array list"+ar1+ " "+ar2);
}
}
Can anybody please explain to me why a method returning null is manipulating a final int [] ?
final int [] vals = {2,3};
int [] vals2 = multiply(vals);
for(int i : vals) System.out.println(i);
int [] multiply(int [] in){
for(int i = 0; i < in.length;i++){
in[i] *= 2;
}
return null;
}
Ouput:
4
6
Edit:
I have noticed this behavior only in methods returning an array. The same method returning an int doesn't change the original integers value...
Full code:
public class Main{
public Main(){
int [] myList = {56, 32, 200};
int [] newList = myList;
bubble_sort(newList);
for(int i : myList){ System.out.println(i); }
System.out.println();
for(int i : newList){ System.out.println(i); }
}
public int [] bubble_sort(int a[]){
int n = a.length;
int [] s = a;
for (int i = 0; i < n ; i++){
for (int j = n - 1; j >= (i+1); j--){
if (s[j - 1] > s[j]){
int t = s[j - 1];
s[j - 1] = s[j];
s[j] = t;
}
}
}
return null;
// return s;
}
public static void main(String [] args){
new Main();
}
}
Edit:
Following code produces following output as expected: 2, 4
int vals = 2;
int vals2 = multiply(vals);
System.out.println(vals);
System.out.println(vals2);
int multiply(int in){ return in*2; }
So my question is, why does a method returning an int does not change the input value, but a method returning an array does change the inputs original value(s).
Here, final means that the vals reference cannot be changed from referring to its initial array. But it says nothing about whether the contents of the array can be changed. As you see, they can be changed.
The final keyword will only stop you from assigning another array to vals, e.g.
vals = anotherArray; // Disallowed; final
A solitary return null; is useless. The multiply method should have been declared as void, returning nothing.
Arrays are mutable in java
the "final" keyword only stops you from reassigning, not from changing the actual value. It literally means that if you were to write "in = someOtherArray" somewhere in your code, you'd get a compile error.
This makes it sound like the "final" keyword is useless, but it works as expected for primitive types, or any immutable object.
If I have: int i = 0; I cannot change the 0 without reassigning a value to i.
Though you see the method returning null, the array contents are still getting modified within the multiply() method.
multiply(vals);
for(int i : vals) System.out.println(i);
Note that you are printing vals which has already been modified by the multiply method. (Java Pass by value)
So when i literally wanna use this method int [] newList = bubble_sort(myList); i mustn't modify the input value but saving each item into a new array int [] s = new int[a.length]; for (int i = 0; i < n ; i++)s[i] = a[i]; and then i can continue to sort the new array and return it. Then the original array(myList) won't be affected.
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 6 years ago.
I thought almost all languages, including java, pass array into function as reference (modifiable).
But somehow it does not work here, and the testArray is still 1,2,3 with size of 3.
Strange enough, when if I change result[i] = 2 to a[1] =2 it works. It did pass by reference.
What is wrong with this code?
At the end, I had a = result; (which update the a). Did result get removed from stack. Is that why I still get to the original a?
I am confused.
Thanks!
class Test
{
public static void main(String[] args)
{
int[] testArray = {1,2,3};
equalize(testArray, 6);
System.out.println("test Array size :" + testArray.length);
for(int i = 0; i < testArray.length; i++)
System.out.println(testArray[i]);
}
public static void equalize(int[] a, int biggerSize)
{
if(a.length > biggerSize)
throw new Error("Array size bigger than biggerSize");
int[] result = new int[biggerSize];
// System.arraycopy(a, 0, result, 0, a.length);
// int array default value should be 0
for(int i = 0; i < biggerSize; i++)
result[i] = 2;
a = result;
}
}
The array is passed by reference, but the reference is passed by value. That is, you can change the array that a refers to, but you cannot change which array a refers to.
Java is pass by value. This is why your code does not work. A good practice would be to mark int[] a as final so this would result in a compilation error (see the corresponding Checkstyle rule).
return parameter "a" from the function and assign to testArray in the main function. When you pass an object by reference, the reference is copied and given to the function. So the object is now referenced by 2 references. Any changes in the object through the 2nd reference will reflect in the first reference, because it is the same object referenced by both of them. But when you change the reference (not the object through reference), it is a different case. you have changed the 2nd reference to point to another object(int[] result). So any changes through the 2nd reference will change only the "result" object.
class Test
{
public static void main(String[] args)
{
int[] testArray = {1,2,3};
testArray = equalize(testArray, 6);
System.out.println("test Array size :" + testArray.length);
for(int i = 0; i < testArray.length; i++)
System.out.println(testArray[i]);
}
public static int[] equalize(int[] a, int biggerSize)
{
if(a.length > biggerSize)
throw new Error("Array size bigger than biggerSize");
int[] result = new int[biggerSize];
// System.arraycopy(a, 0, result, 0, a.length);
// int array default value should be 0
for(int i = 0; i < biggerSize; i++)
result[i] = 2;
a = result;
return a;
}
}
When you do a = result; object a dosnt anymore point to the testArray, bc you are changing its reference to result's address. That's why it dosnt effect anymore to the testArray.
What you are doing actually is you are making a the same adress as result has, so whatever you change in a it will change in result too.
Hope this helped...
The array referenced by a can be modified, but the reference itself is passed by value. So if you did a[0] = 1, then you would be changing the original array. However, a = result changes the reference, and so the original reference is unchanged.
Java is pass by value, always.
Arrays are Objects in java. If you have initialized your array with a size(actually length), you cannot modify it. You can create a new Array with a varying size (as you are currently doing in the function ) and copy all the values from the Old Array to the new Array. In your case, you have 2 objects and 3 references. If you want to access the Array of greater size in the calling function , make the function return the reference of the Array of greater size.
public class test
{
public static void main(String[] args){
int[] a = {15, 2, -3};
printArray(a);
changeArray(a);
printArray(a);
}
private static void changeArray(int[] a){
for(int i = 0; i < a.length; i++){
a[i]++;
}
}
private static void printArray(int[] a){
for(int i = 0; i < a.length; i++){
System.out.print(a[i] + " ");
}
System.out.println();
}
}
-----OUTPUT-----
15 2 -3
16 3 -2