Java中的值传递和引用传递

发布时间:2024年01月15日

看了很多关于Java中的值传递和引用传递,我觉得有所收获,但是还是觉得有些迷惑,下面是关于我自己对于Java中的值传递和引用传递的理解。【作为一个Java初学者的理解,下面的文章可能不对,请谨慎甄别和选择,也欢迎大家来提出意见

Java中的数据类型

众所周知,Java中的数据类型分为两大类:基本数据类型引用数据类型,在这里就不列举分别有哪些了。

基本数据类型

比如我们定义一个基本数据类型:

int x = 10;
x = 100;

这里第一行的x表示的是一块内存,其大小为4个字节,存储的是int类型的数据,不妨设这块内存的起始地址为0x1111,这块内存中的值是10。更为形象的说,可以将x视为起始地址为0x1111的这块内存。

第二行代码就可以看出x = 100,而其具体是怎么做到的呢?就是将100这个值赋值到名为x的这块内存中,也就是赋值到0x1111这块内存上。

引用数据类型

我们定义一个引用数据类型

public static void main(String[] args) {
	Person p1 = new Person("Alice", 10);
	p1 = new Person("Bob", 20);
}

class Person {
    int age;
    String name;
    public Person(String name, int age) {
    	this.name = name;
    	this.age = age;
    }
}

main方法中,一开始的p1是在内存中申请了一块内存,其大小为一个Person类的大小,存储的是Person类型的数据,内容有Alice, 10等信息,这块内存的起始地址不妨假设为0x2222。那么其实和基本数据类型一样的是,p1的含义就是这个已经实例化的对象的起始地址,也就是p1就是0x2222的这块内存。

紧接着p1 = new Person("Bob", 20);,这就是再次申请了一块内存,而这块内存中存储的就是Bob, 20等信息,假设这块内存的起始地址是0x3333,然后将p1的含义改为0x3333,也就是说p1变为了0x3333的这块内存。

当然,真正的JVM处理可能并不会将p1直接改为地址,也许是其他的操作,但是其本质上的意思就是上面的情况。

基本数据类型与引用数据类型的相同与不同

相同点:

  • 变量名都是对应的数据地址。

不同点:

  • 基本数据类型赋值时:是将值直接复制到与变量名对应的内存中去;
  • 引用数据类型赋值时:是将变量名改为数据的起始地址。

接着分析传参的问题。

Java中的方法传参

Java中传递的参数有两种数据类型,一种是基本数据类型,另一种就是引用数据类型。因此就有两种传参规则:

  • 基本数据类型:值传递;
  • 引用数据类型:引用传递;

具体来说什么是值传递,什么是引用传递。

  • 值传递:将实参复制到形参中,因此,在方法中的形参的改动,并不会对调用者的实参的改变;
  • 引用传递:将实参的地址复制到形参中,因此,如果直接对形参进行改变,其本质也并不会对实参进行改变。但是如果对形参中的二级地址进行改变,则会改变实参。

这也就是为什么有些人会说,在Java中其实并没有引用传递,都是值传递的原因,其实他们说的也是对的,因为本质上来说都是值传递,只不过一个是数据本身的值传递,另一个是数据的地址的值传递而已。

在这里就不详细介绍值传递的问题了,直接说引用传递。

Java中的引用传递

上一节说的引用传递可能描述的并不是很好理解,举个例子来说:

public static void main(String[] args) {
    Person p1 = new Person("Alice", 10);
    System.out.println(p1);
    Person.change1(p1);
    System.out.println(p1);
    Person.change2(p1);
    System.out.println(p1);
}

class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public static void change1(Person p) {
        p = new Person("Bob", 20);
    }

    public static void change2(Person p) {
        p.age = 70;
    }
}

从上面代码进行分析:

change1change2传进来的都是Person类,都是属于引用传递,那么为什么change1没有影响main函数中的p1,而change2却改变了main函数中的p1呢?

根据Java的引用传递规则来看:

  • 分析change1:传进来的形参pAlice, 10这样的内存的地址的值0x4444,而直接对p = new Person("Bob", 20);这样的操作,只是将形参p的值改为了Bob, 20这样的内存的地址的值0x5555,由于Java的引用传递的规则来看,这并不会影响mian中的p1的值还是等于0x4444
  • 分析change2:传进来的形参pAlice, 10这样的内存的地址的值0x4444,紧接着,对0x4444这块内存中的age部分内存进行了修改,而这块内存也还是在main中的p1所对应的内存中,因此,会对main中的p1进行影响。

总结

值传递和引用传递其本身都是对值的复制,不同的是,一个是数据本身的值复制,一个是数据的地址的值复制。

文章来源:https://blog.csdn.net/renshy5/article/details/135578275
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。