当面试官问我————Java是值传递还是引用传递?

面试官:你好,你能说出下面个程序的执行结果吗?

public class Test {public static void main(String[] args) {String name = "Scott";int age = 5;User user = new User();user.setName(name);user.setAge(age);System.out.println("before change user = " + user);change(user, name, age);System.out.println("name = " + name);System.out.println("age = " + age);System.out.println("after change user = " + user);}public static void change(User user, String name, int age) {name = "Tom";age = 20;user.setName(name);user.setAge(age);}static class User {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "{name : " + name + ", age : " + age + "}";}}
}

:执行结果是:

面试官:恩,你的答案完全正确。age是一个基本类型变量,User、String都是引用类型变量,但是在调用change()方法之后,实参name和age都没有改变,而user对象改变了。那么可不可以说调用change()方法时,User对象是引用传递,age是值传递?可是String的传递方式又是什么呢?它的表现和age相同,但本身确是引用对象,这该如何解释呢?

:Java和C++不同,C++中有引用传递的函数调用方式,而Java中只有值传递

首先,值传递的官方解释是:

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

其次,引用传递的官方解释是:

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

一句话概括值传递和引用传递的区别:

值传递是传递实参副本,函数修改不会影响实参;引用传递是传递实参地址,函数修改会影响实参。

面试官:恩,那你可不可以结合上面的程序题,解释一下这句话呢?

:好的。针对于上面程序的应用场景,在调用change()方法的时候,user、name、age三个变量都是值传递

其中,user对象是将引用拷贝了一份,引用是对象的地址,change()中对user的修改,并没有影响到这个地址,而是修改了对象属性。产生混淆的关键在于人们看到对象本身被函数修改了,就错误的认为这是引用传递。但我们区分值传递还是引用传递的关键在于实参是否被函数所修改,对于user对象来说地址才是实参!但如果你在change()方法中修改user引用的地址,即新创建一个新的user对象的话,就会看到main方法中的user并没有任何改变,也就反向印证了它实际上是值传递。

name变量自然也是将name引用拷贝一份传递给change()方法,根据值传递的定义,函数对这个副本的修改不会影响到实际参数,又因为String的final特性,name = "Tom"; 实际上就是修改了name的地址,因此,实际参数不会受函数修改的影响。

age其本身也是将数值拷贝一份传入change(),所以任何修改都不会影响到实参。所以我们说,在Java中只有值传递这一种参数传递方式。

面试官:恩,你的理解已经非常到位了,那额外问一句,对于上面的三种类型User、String、int,当输出结果如何时,才可以认定是引用传递呢?

:对于User对象,上面的代码实际上并不能很好的验证这个问题,反而给人一种对象即是实参的假象。实际上,如果调用change()方法后,重新new 一个User对象后赋值给user,即改变了变量的地址。在这种情况下,main中如果可以成功打印出新对象的话,才可以认定是引用传递。

String类型的name也是一样,如果在change()中 name = "Tom"; main中如果可以打印出 Tom 的话才可以认为是引用传递。

包括age变量,尽管它是一个基本类型变量,但在内存中,依然有地址和数据的区分,如果在change()中的修改,main中可以看到的话,才可以说是引用传递。

实际上,“引用传递”中的“引用”二字,绝对不能简单的理解为“引用类型”中的“引用”,而应该理解为“指针”、“地址”,Java中就算是基本类型也同样拥有“地址”和“指针”。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558830.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu系统下Jenkins和tomcat的安装与配置

ubuntu 安装 JDK ubuntu的安装我们采取最简单的方式安装 直接用apt-get的方式 sudo apt-get install openjdk-8-jdk 安装器会提示你同意 oracle 的服务条款,选择 ok 然后选择yes 即可 ubuntu 安装tomcat8 通过apt安装 tomcat8 sudo apt-get install tomcat8 tomcat8-docs t…

String字符串拼接小例

>>>写出下面程序运行结果: public class StringTest {public static void main(String[] args) {String s1 "Programming";String a "Program";String b "ming";String s2 "Program" "ming";Stri…

看完这篇文章,还不懂nginx,算我输

看完这篇文章,还不懂nginx,算我输 参考:https://mp.weixin.qq.com/s/PeNWaCDf_6gp2fCQa0Gvng 1. Nginx产生~ Nginx 同 Apache 一样都是一种 Web 服务器。基于 REST 架构风格,以统一资源描述符(Uniform Resources Id…

一篇博客读懂设计模式之---工厂模式

设计模式之—工厂模式 工厂模式: 创建过程: 创建Shape接口 public interface Shape {void draw(); }创建实现类: public class Circle implements Shape {Overridepublic void draw() {System.out.println("this is a circle!"…

一篇博客读懂设计模式之-----策略模式

设计模式之策略模式 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的对象 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。 主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和…

Java并发编程实战————恢复中断

中断是一种协作机制,一个线程不能强制其他线程停止正在执行的操作而去执行其他操作。 什么是中断状态? 线程类有一个描述自身是否被中断了的boolean类型的状态,可以通过调用 .isInterrupted() 方法来查看。官方解释如下: 简单来…

一篇博客读懂设计模式之---模板方法模式

设计模式之模板方法模式: 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 简而言之就是:父类定义了骨架(调用哪些方法及其顺序)…

一篇读懂--mybatis的缓存

一篇读懂–mybatis的缓存 MyBatis的缓存指的是缓存查询结果,当以后使用相同的sql语句、传入相同的参数进行查询时,可直接从mybatis本地缓存中获取查询结果,而不必查询数据库。 mybatis的缓存包括一级缓存、二级缓存,一级缓存默认…

Spring Boot————BeanCreationNotAllowedException异常分析

引言 在对数据库进行新增记录的JUnit测试时,抛出一个BeanCreationNotAllowedException异常: 异常分析与解决 异常信息太长,图片截不下,粘贴来看: Exception in thread "pool-2-thread-1" org.springframew…

一篇博客读懂设计模式之---委派模式

一篇博客读懂设计模式之—委派模式 委派模式可能大家听起来不太熟悉,但是在代码开发的时候却很好用,下面从几个方面来介绍一下 what:是什么? 委派模式:顾名思义,委托其他对象或者实例来帮我们完成任务&am…

Jackson快速入门

引言 上一篇博客《XML模板解析————Dom4j解析xml案例分析》简单讲解了关于xml模板的解析,使用到了dom4j,这篇文章其实算是个姊妹篇,都是对于目前工作中的一些任务,如xml、json相互解析所涉及到的知识。 但是相对于xml而言&am…

一篇文章读懂MySQL的各种联合查询

一篇文章读懂MySQL的各种联合查询 联合查询是指将两个或两个以上的表的数据根据一定的条件合并在一起! 联合查询主要有以下几种方式: 全连接:将一张表的数据与另外一张表的数据彼此交叉联合查询出来 举例如下: 先建两张表: CR…

一篇文章看懂@Scheduled定时器/@Async/CompletableFuture

一篇文章看懂Scheduled定时器/Async/CompletableFuture Scheduled注解解析: 1.cron:最重要的一个参数 cron表达式[秒] [分] [小时] [日] [月] [周] [年]([年]可省略) 简单了解一下,网上有现成的工具 示例&#xff…

一篇搞懂HTTP协议

本文转自 :flyhero 码上实战《一个HTTP打趴80%面试者》 HTTP协议简介 HTTP(超文本传输协议)是应用层上的一种客户端/服务端模型的通信协议,它由请求和响应构成,且是无状态的。(暂不介绍HTTP2) 协议&…

Jackson高级操作————节点树

引言 继《Jackson快速入门》基础篇之后的树模型相关操作。 节点树模型 ObjectMapper构建JsonNode节点树,类似于DOM解析器的XML。 Testpublic void testJsonTree() throws JsonProcessingException, IOException {String jsonString "{\"name\":\…

Jackson高级操作————流式API与JsonGenerator、JsonParser

引言 继《Jackson快速入门》之后的高级相关操作。 Jackson提供了一种对于性能要求应用程序操作json更加高效的方式——流式API,这种方式开销小,性能高,因此,如果应用程序或者程序逻辑对于性能有一定要求,可以使用这种…

Mysql高级教程思维导图

Mysql高级教程思维导图 1、思维导图总览: 2、MySQL架构介绍: 2.1、MySQL简介 2.2、MySQL Linux版安装 2.3、MySQL配置文件 2.4、MySQL逻辑架构介绍 2.5、MySQL存储引擎 2.6、MySQL的用户和权限管理 2.7、MySQL一些杂项配置 ’ 3、索引优化分析 3.1、性…

Eclipse(STS 4)闪退导致EGit插件异常

引言 到目前为止,STS已经闪退过三次了。 问题很棘手,我需要冷静。 首先出现了一个问题就是,EGit无法commit。 第二个问题是切换分支报错。 闪退重启后EGit无法提交代码 观察闪退出现的时机,一般出现在我 commit 代码的时候&…

spring源码分析第二天------spring系统概述以及IOC实现原理

1、Spring5 概述 Spring 是一个开源的轻量级 Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架, 其目的是用于简化企业级应用程序开发。 Spring 框架除了帮我们管理对象及其依赖关系,还提供像通…

Linux进阶之路————Linux概述

引言 Linux是一个开源、免费的操作系统。学习Linux知识分为以下几个阶段: 第一阶段:Linux环境下的基本操作命令,包括文件操作命令(rm、mkdir、chmod、chown)编辑工具使用(vi、vim)Linux用户管…