Thoughts on Parameter Passing of Java Functions

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 Integerthe value is IntegerCache.lowbetween IntegerCache.high([-127,128]), then IntegerCacheget 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 IntegerCachethe 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 IntegerCachevalues ​​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.

Guess you like

Origin blog.csdn.net/flash_love/article/details/132056144