一、基本类型 和 引用类型的不同之处

int num = 10;
String str = "hello";

首先变量其实是堆栈中的地址索引。然后 基本类型的数据直接保存在堆栈中,而对象是保存在堆中,堆栈中保存的是该对象在堆中的地址,这个地址就是所谓的引用

二、赋值运算符(=)的作用

num = 20;
str = "java";

对于基本类型 num ,赋值运算符会直接改变变量的值,原来的值被覆盖掉。
对于引用类型 str,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。但是原来的对象不会被改变(重要)。
如上图所示,”hello” 字符串对象没有被改变。(没有被任何引用所指向的对象是垃圾,会被垃圾回收器回收)

三、调用方法时发生了什么?参数传递基本上就是赋值操作

num = 20;
str = "java";
func(num,str);
public void func(int n,String s){
    n=30;
    s+="haha";
    // do something with s
}

n变为30,num不受影响;s虽然是对象类型,但是由于String是不可变类型,因此并不会影响到原来的str变量。所以结果如下:

如果str是StringBuilder对象的话,就会改变,结果如下:

总结

在java中,不管原始参数的类型是什么,参数都是按值传递的

每当一个方法被执行时,在堆栈中就会为每个参数创建一个拷贝,这个拷贝被传递到方法的内部,这个拷贝分以下2种情况:

  • 如果参数是基本类型,那么在堆栈中复制的就是这个参数的值
  • 如果是对象,那么在堆栈中传递的便是指向真正对象数据的新的引用。这个新的引用被传递到方法内部。

因此关于参数在方法中被修改后,会不会影响到原始变量,根据上面的原理:

  1. 修改一个基础类型的参数,不会影响原始数据;
  2. 修改一个对象参数(数组、集合、map、类)的引用时,永远不会影响到原始的引用;
  3. 修改一个对象参数的属性时,会影响原始对象
public static void main(String[] args) {
        DuplicatenNum app = new DuplicatenNum();

        int a1=5;
        app.fun1(a1);
        System.out.println(a1);

        TreeNode a2=new TreeNode(5);
        app.fun2(a2);
        System.out.println(a2);

        int[] a2_2={1,2};
        app.fun2_2(a2_2);
        System.out.println(a2_2[0]);

        List<Integer> list=new ArrayList<>();
        list.add(1);
        app.fun3(list);
        System.out.println(list);
    }

    public  void fun1(int a) {
        a=10;
    }

    public void fun2(TreeNode root) {
        root=new TreeNode(10);
    }

    public void fun2_2(int []  arr) {
        arr = new int[4];
    }

    public void fun3(List<Integer> list){
        list.add(2);
    }

输出:

5
TreeNode{val=5, left=null, right=null}
1
[1, 2]

参考: Java 到底是值传递还是引用传递?

评论