对象的引用,Java的值传递

1.什么是引用?

如下表达式:

Student s1 = new Student();

它代表Student是类,s1是引用,s1不是对象,new Student()才是对象,s1引用指向new Student()这个对象。

在JAVA里,“=”不能被看成是一个赋值语句,它不是在把一个对象赋给另外一个对象,它的执行过程实质上是将右边对象的地址传给了左边的引用,使得左边的引用指向了右边的对象。Java表面上看起来没有指针,但它的引用其实质就是一个指针,引用里面存放的并不是对象,而是该对象的地址,使得该引用指向了对象。

Student s2;

它代表Student是类,s2是引用,s2不是对象,s2所指向的对象为空null;

s2 = s1;

它代表,s2是引用,s1也是引用,s1所指向的对象的地址传给了s2(传址),使得s2和s1指向了同一对象。

综上所述, 在初始化时,“=”语句左边的是引用,右边new出来的是对象。 在后面的左右都是引用的“=”语句时,左右的引用同时指向了右边引用所指向的对象。
再所谓实例,其实就是对象的同义词。

2.什么是值传递,什么是引用传递。为什么说Java中只有值传递?

错误理解:传递的参数如果是基本类型,那就是值传递,如果是对象,那就是引用传递。

  • 值传递
    是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

  • 引用传递
    是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

举三个例子:

public static void main(String[] args) {
    int i = 10;
    pass(i);
    System.out.println("print in main , i is " + i);
}
 
public void pass(int j) {
    j = 20;//注意这里
    System.out.println("print in pass , j is " + j);
}
print in pass , j is 20
print in main , i is 10

有人得到结论:Java的方法传递是值传递。

但是:

public static void main(String[] args) {
    User user= new User();
    user.setName("User");
    user.setGender("W");
    pass(user);
    System.out.println("print in main , user is " + user);
}
 
public void pass(User user0) {
    user0.setName("Jxy");//注意这里
    System.out.println("print in pass , user0 is " + user0);
}
print in pass , user is User{name='Jxy', gender='W'}
print in main , user is User{name='Jxy', gender='W'}

有人得出一个新的结论:Java的方法中,在传递普通类型的时候是值传递,在传递对象类型的时候是引用传递。

但是,这种表述仍然是错误的。

public static void main(String[] args) {
    String name = "Jxy";
    pass(name);
    System.out.println("print in main , name is " + name);
}
 
public void pass(String name) {
    name = "Hello";//注意这里
    System.out.println("print in pass , name is " + name);
}
print in pass , name is Hello
print in main , name is Jxy

同样传递了一个对象,但是原始参数的值并没有被修改!

举了三个例子,表现的结果却不一样,其实,上面的概念没有错,只是代码的例子有问题。

为什么说例子错了----->

  • 你有一把钥匙,当你的朋友想要去你家的时候,如果你直接把你的钥匙给他了,这就是引用传递。这种情况下,如果他对这把钥匙做了什么事情,比如他在钥匙上刻下了自己名字,那么这把钥匙还给你的时候,你自己的钥匙上也会多出他刻的名字。
  • 你有一把钥匙,当你的朋友想要去你家的时候,你复刻了一把新钥匙给他,自己的还在自己手里,这就是值传递。这种情况下,他对这把钥匙做什么都不会影响你手里的这把钥匙。
  • 但是,不管上面哪种情况,你的朋友拿着你给他的钥匙,进到你的家里,把你家的电视砸了。那你说你会不会受到影响?而我们在pass方法中,改变user对象的name属性的值的时候,就是在“砸电视”。你改变的不是那把钥匙,而是钥匙打开的房子。

所以第二个例子应该是这样的:

public static void main(String[] args) {
    User user= new User();
    user.setName("User");
    user.setGender("W");
    pass(user);
    System.out.println("print in main , user is " + user);
}
 public void pass(User user) {
    user = new User();//注意这里
    user.setName("Jxy");
    user.setGender("W");
    System.out.println("print in pass , user is " + user);
}
print in pass , user is User{name='Jxy', gender='W'}
print in main , user is User{name='User', gender='W'}

这里是把实参引用的地址复制了一份,传递给了形参。所以,上面的参数其实是值传递,把实参的值(引用地址)传递给了形参,二者指向的对象是同一个

  • 错误的例子中是把他们指向的对象里的内容改了,所以,只要是指向这个对象的引用都受到了影响。
  • 正确的例子中是把pass里的引用指向换了对象,当回到main,main里的引用指向并没有变化,仍然是原来那个对象,各指各的,二者无关。

至于传String对象和User对象的表现结果不一样,是因为String的不可变性,我们在pass方法中使用name = “Hello”;直接改变了name的引用地址。因为这段代码,其实是去常量池中寻找"Hello",有–>返回"Hello"的引用,没有–>常量池中创建"Hello",返回"Hello" 的地址。<详情请看String>

所以:
在判断实参内容有没有受影响的时候,要看传的的是什么,如果你传递的是个地址,那么就看这个地址的变化会不会有影响,而不是看地址指向的对象的变化。就像钥匙和房子的关系。
即:Java中是值传递的,对于对象参数,值的内容是对象的引用,即对象的地址;对于基础数据参数,值的内容就是一个值

ref: https://blog.csdn.net/qq_41854911/article/details/122149948

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值