Java面试中的值传递与引用传递

Wesley13
• 阅读 665

一、前言

Java是值传递的,对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。对于对象型变量而言的,传递的是该对象地址的一个副本,,并不是原对象本身 ,这里也有人说是引用传递。由于副本的地址和原对象地址一致,因此对副本的值进行操作时,会同步改变原对象值。

但是一旦副本的地址被改变,副本的值的操作则不会影响原对象地址。(重点)

二、常见例子

1、基本类型参数的值传递

public class Test {    public static void main(String[] args) {        int num = 0 ;        changeNum(num);        System.out.println("num="+num);   }

   private static void changeNum(int num) {        num = 1;   } }

最终输出结果是:num=0

因为这里 changeNum(num);语句中的num传递的是num的副本,也就是形参,所以当副本变为1,对实参原对象不影响,原对象还是num=0;

2、封装类型参数

public class Test {    public static void main(String[] args) {        Product p = new Product();        p.setProName("before");        p.setNum(0);        changeProduct(p);        System.out.println("p.proName="+p.getProName());        System.out.println("p.num="+p.getNum());   }

   private static void changeProduct(Product p) {        p.setProName("after");        p.setNum(1);   } }

class Product {    private int num;    private String proName;

   public int getNum() {        return num;   }

   public void setNum(int num) {        this.num = num;   }

   public String getProName() {        return proName;   }

   public void setProName(String proName) {        this.proName = proName;   } }

最终输出结果是:p.proName=afterp.num=1

这里我们可以看到 changeProduct(p); 该语句传递的是p内存中存储的地址的副本,该地址就是new Product();的地址。在changeProduct方法中对p地址的副本指向的值进行操作,由于副本地址和原地址一样,所以相当于最终p地址指向的值也会发生变化。所以这里的changeProduct方法能改变实参。

但是存在以下特殊情况,就是前言说的一旦副本的地址被改变。我们再 changeProduct() 方法中添加一条语句;

private static void changeProduct(Product p) {    p = new Product();//添加这条语句,相当于P的地址变成new Product()新对象的地址,不是主函数中的对象的地址    p.setProName("after");    p.setNum(1); }

这里添加的这条语句 改变了副本的地址,导致副本指向新对象的地址,因此变成对新对象的操作,不影响主函数中的原对象,最终输出结果是:p.proName=beforep.num=0

3、容易忽略的特殊类型String

首先要清楚一点,这种说法不正确:String str = "java",这就相当于String str = new String("java"),这是创建一个新的String的过程,不单单是赋值的过程。

public class Test {    public static void main(String[] args) {        String str = "ab";        changeString(str);        System.out.println("str="+str);   }

   private static void changeString(String str) {        str = "cd";   } }

猜猜这里最终结果是什么?

最终输出结果是:str=ab 。(没猜对的说明上面第二点还没理解清楚)

解析:

str1 = "cd"
str2 = new String("cd");
System.out.println(str1 == str2); // false
说明str = "cd";不能被解释为如下:str = new String("cd");
这里之所以最终显示结果是“ad”,是因为main中的str的地址是常量池“ad”的地址,而在str = "cd"说明此时str的地址变成常量池“cd”的地址,地址改变,对实参原来的str无影响,所以最终输出的还是“ad”.

4、常见面试题

public class Example {    String str = new String("good");    char[] ch = { 'a', 'b', 'c' };

   public static void main(String args[]) {        Example ex = new Example();        ex.change(ex.str, ex.ch);        System.out.print(ex.str + " and ");        System.out.print(ex.ch);   }

  public void change(String str, char ch[])         {        str = "test ok";        ch[0] = 'g';   } }

从如下4个选项选出最终输出结果

A 、 good and abc B 、 good and gbc C 、 test ok and abc D 、 test ok and gbc

正确答案: B

解析:

ex.str如第3点所说的,其传递的地址副本在change方法中被改变,因此不影响原地址的对象,所以ex.str不变;

ch数组是对象,数组的父类也是Object。传递的是数组地址的副本,因此在change中副本地址没改变,相当于对原对象进行操作,所以ch数组的值发送变化。

参考资料:https://blog.csdn.net/party3/article/details/78648186

https://www.cnblogs.com/boboooo/p/9066831.html

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java传值与引用的关系
       首先,我们必须要搞清楚的一件事是,不管java的参数类型是什么,一律传递的是参数的副本。也就是说每次传递参数的时候都会讲参数拷贝一份传递。1.基本数据类型:       对于基本的数据类型来说,java传递的是指的副本;也就是将数据拷贝一份以后传递。因此当函数返回的时候,不管在调用的函数中做了什么操作,基本数据类型的值都不会改变。
待兔 待兔
3年前
[Dart]Dart语言之旅<二>:变量
变量以下是创建变量并为其分配值的示例:varname'Bob';变量是引用。名为name的变量包含对值为“Bob”的String类型的对象的引用。默认值未初始化的变量的初始值为null。即使是数字类型的变量,初始值也为null,因为数字也是对象。intlineCount;assert(lineCountnull)
Wesley13 Wesley13
3年前
Java中只存在值传递
在Java中并不存在引用传递(即地址传递),对于变量(可以是基本数据类型,也可以是引用数据类型)而言,可以理解为就是一个地址。传递,存在着拷贝操作。举个列子:1、在方法参数上,传递的是基本数据类型。定义了一个用于交换两个整型数的方法:publicstaticvoidswap(inta,intb){in
Wesley13 Wesley13
3年前
Java对象的浅拷贝和深拷贝&&String类型的赋值
Java中的数据类型分为基本数据类型和引用数据类型。对于这两种数据类型,在进行赋值操作、方法传参或返回值时,会有值传递和引用(地址)传递的差别。浅拷贝(ShallowCopy):①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,
Stella981 Stella981
3年前
JS 对象数组Array 根据对象object key的值排序sort,很风骚哦
有个js对象数组varary\{id:1,name:"b"},{id:2,name:"b"}\需求是根据name或者id的值来排序,这里有个风骚的函数函数定义:function keysrt(key,desc) {  return function(a,b){    return desc ? ~~(ak
Stella981 Stella981
3年前
JavaScript学习小结
JavaScirpt变量可用来保存两种类型值:基本类型值,引用类型值基本类型值:Undefined,Null,Boolean,Number,String基本类型及引用类型值特点:1.基本类型值在内存中占据固定大小的空间,被保存在栈内存中;2.从一个变量向另一个变量复制基本类型值,会创建这个值的一个副本;
Stella981 Stella981
3年前
JVM调优总结一
数据类型   Java虚拟机中,数据类型可以分为两类:基本类型和引用类型。基本类型的变量保存原始值,即:他代表的值就是数值本身;而引用类型的变量保存引用值。“引用值”代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置。基本类型包括:byte,short,int,long,cha
Wesley13 Wesley13
3年前
Go语言方法的 值接受者 和 指针接受者 的区别
首先说下结论1\.无论方法的接受者是值接受者还是指针接受者,对象值调用该方法和对象指针调用该方法都是可行的。2\.当方法接受者为指针接受者时,对象的值调用该方法和指针调用该方法都会操作对象本身。3\.当方法接受者为值接受者时,对象的值调用该方法和指针调用该方法都会操作对象的副本,对对象本身无影响。pack