Today I occasionally saw a video about parameter passing in Java functions. Although it is a very simple program, it involves a lot of Java basics, so it is necessary to sort it out.
Is Java's function parameter passing by value or by reference?
clear concept
值传递:表示方法接收的是调用者提供的值。
引用传递:表示方法接收的是调用者提供的变量地址。
According to Horstmann's "Java Core Technology", Java does not pass by reference.
The java programming language always uses call by value. That is, the method gets a copy of all parameter values, and in particular, the method cannot modify the contents of any parameter variable passed to it.
Some programmers (even the author of this book) think that the Java programming language uses reference calls for objects. In fact, this understanding is wrong.
Most people think about Java value passing,
- For basic data type variables (int, long, double, float, byte, boolean, char), copy the original value and pass it on, and the operations in the method will not affect the original data.
- For object variables, passing a copy of the value pointing to the address is essentially copying the pointer pointing to the address. (The String type is also an object variable)
All in all, no matter what the type of the parameter is, a copy of the parameter is always passed.
pass primitive type
public class Swap {
public static void main(String[] args) {
Integer a = 10;
System.out.println("swap before: a = "+a);
swap(a);
System.out.println("swap after: a = "+a);
}
private static void swap(Integer a) {
// TODO Auto-generated method stub
a = 30;
}
}
result:
swap before: a = 10
swap after: a = 10
The result remains unchanged, and the operation of parameters in the method does not affect the original data.
pass object type
public class Swap {
public static void main(String[] args) {
Person p = new Person();
p.setAge(20);
System.out.println("update before: age = "+p.getAge());
update(p);
System.out.println("update after: age = "+p.getAge());
}
private static void update(Person p) {
p.setAge(30);
}
}
class Person{
private Integer age;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
result:
update before: age = 20
update after: age = 30
The result has changed, the object parameter is the incoming address value, and then the value in the object is modified, the address still does not change, but the value has changed.
Based on the above situation, if you write a function for exchanging data, you cannot follow the conventional writing method. The following is to use reflection to exchange
import java.lang.reflect.Field;
public class Swap {
public static void main(String[] args) {
// TODO Auto-generated method stub
Integer a=10,b=15;
System.out.println("swap before:a="+a+",b="+b);
swap(a,b);
System.out.println("swap after:a="+a+",b="+b);
}
private static void swap(Integer a, Integer b) {
try {
Field f = Integer.class.getDeclaredField("value");
f.setAccessible(true);
Integer temp = new Integer(a.intValue());
f.set(a, b.intValue());
f.set(b, temp);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
result:
swap before:a=10,b=15
swap after:a=15,b=10
Among them, one of the codes needs to be paid attention to
Integer temp = new Integer(a.intValue());
This is to create a new object instead of assigning it directly. Why?
There is such a piece of code in Java's Integer.java source code
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
That is, if Integer
the value is IntegerCache.low
between IntegerCache.high
([-127,128]), then IntegerCache
get it directly, and if the value is greater than this range, a new one will be created Integer类型
.
For example, if changed Integer temp = a.intValue()
to
swap before:a=10,b=15
swap after:a=15,b=15
After the first assignment of temp, it is 10, and after the subsequent f.set(a, b.intValue());
operation, a becomes 15, because IntegerCache
the value is obtained from the slave, which leads to the change of temp at this time, and becomes 15, which finally leads to a deviation in the result. Therefore, it is necessary to avoid taking IntegerCache
values to make the results accurate.
If a and b exceed that range, look at the result
swap before:a=231,b=144
swap after:a=144,b=231
So you need to recreate the object yourself to be correct.