起因

前两天面试被问到了这个问题,虽然之前老早就了解过这个问题,但是并没有深入了解,所以面试的时候一下子慌了,菜是原罪,今天菜鸡来补补基础知识。

其实这个问题一直是被讨论的,常见的三种说法就是,1,Java 值传递引用传递都有,2,只有值传递,3只有引用传递,今天查了很多资料,我发现这个问题并不是随随便便就能说清楚。

先说传参

方法的参数可以分为实参和形参,实参是指被调用时传入的实际的值,在方法调用前就已经初始化完毕。而形参是指方法中用来“承接”实参的参数,它是在这个方法里有效,即作用域。方法执行结束之后即被销毁。

OK,接下来说所谓的值和引用。

Java数据类型

1,基本数据类型,这种是Java中最小粒度的数据类型,包括:byte,short,int,long,float,double,char,boolean。

2,引用类型:是编程语言中存放实际内容所在地址的一种数据类型。一般是类,接口,数组。

在这里不得不说一下内存区域划分:

在Java文件经过编译器之后,转化成为class文件,之后JVM将class文件通过类加载加载到运行时数据区来存储程序运行时需要用到的数据和相关信息。

运行时数据区

1,虚拟机栈,它是线程私有的,所以是线程隔离的,栈里面存储的是栈帧,每一个栈帧表示被调用的一个方法,方法调用的过程对应着栈帧从入栈到出栈的过程,栈帧中存储的是方法运行需要的信息,它是用来支持方法调用和方法执行的数据结构:

(1),局部变量表(方法中的局部变量,变量为基本类型时,直接存储值,为引用类型时,存储指向具体对象的引用)

(2),方法出口地址(方法执行完返回的地址)

(3),操作数栈(JVM被称为基于栈的执行引擎)

(4),指向常量池的引用

(5),一些附加信息。

2,堆,是所有线程共享的,用来存储对象和数组,在JVM中,只有一个堆。

3,方法区:是一块所有线程共享的内存逻辑区域,在JVM这个中也只有一个方法区,用来存储一些线程可共享的内容,同时它也是线程安全的。方法区存储的信息有:

类的全路径名,类的直接超类的全限定名,类的访问修饰符,类的类型,类的直接接口的全限定名的有序列表,常量池等。

4,本地方法栈:本地方法栈类似于虚拟机栈,也是线程私有,不同的是,虚拟机栈是为Java方法服务,而本地方法栈是为native方法服务。

5,程序计数器,也是线程私有,字节码解释器工作就是通过改变程序计数器里的值来选取下一条执行的字节码指令,分支循环等都需要它来实现。

数据是如何存储的?

JVM 在运行过程中,涉及内存分配有:堆,栈,静态方法区,常量区。内存分配的策略有:堆式,栈式,静态。

基本数据类型的存储:

1,基本数据类型的局部变量以及他的值都是存储在栈上,也就是虚拟机栈的栈帧中。

如:int a = 30;事实上这个过程分为两步,第一步是创建一个age变量, 第二步是先查找栈中是否有30这个值,如果有,则直接将age指向它,没有则开辟一块内存来存储30.

再将age指向它。对它再赋值也是相同的道理,如age = 50,先查找栈中是否有50,有则指向,没有则开辟一块空间存50,再将age指向它。所以足以见之,基本数据类型的赋值是不改变自身数据的,而是像上面那样先查找栈中是否存在,有则指向它,没有则开辟一块内存来装下新的值。

2,基本数据类型的成员变量

与上面的不同的是,它存放在堆里,因为它跟随着一个实例对象,跟实例对象的生命周期相同。

3,基本数据类型的静态变量,与上面都不同,静态变量和它的值都存储在运行时常量区,它是跟随类加载的,随类的消失而消失。

引用数据类型的存储:

引用数据类型分为两部分,一部分是变量,存在栈中,用来存储实际内容的地址,同时在堆中有一块内存来存实际内容。

所谓值传递和引用

值传递

在方法被调用时,实参通过形参把它的内容副本传入方法内部,此时的形参接收到的实际上是实参的副本,在方法体内的任何操作,都是对副本的操作,对实参不影响。如:

public class Main {

    public static void main(String[] args)  {
int a = 10;
function(a);
System.out.println(a);
}
private static void function(int a){
a = 50;
}
}

输出结果:10

结合之前的铺垫,首先JVM会将其中的main()压入虚拟机栈,用一个栈帧存储,即为当前栈帧,栈帧存储着方法的局部变量表,操作栈,方法出口地址等。之后执行到function方法时,JVM也创建为它创建一个
栈帧,用来存放function的相关信息,因此a的值是在function的栈帧中,而它的值是从实参复制得来的,而再方法体内部进行赋值的时候,也不会去改变main所在的栈帧中的a的值,而是在当前的栈帧中,对值进行修改。而栈帧之间是隔离的,所以不会对实参产生影响。

引用传递

引用传递和值传递的不同点在于,调用方法的时候,实参的地址通过方法传给形参,所以对实参的操作会影响本身的内容,但是但是,这里面还需要分情况。如:

public class Main {
public static void main(String[] args) {
StringBuilder a = new StringBuilder("10");
function(a);
System.out.println(a);
}
private static void function(StringBuilder str){
str.append("20");
}
}

输出:1020

public class Main {
public static void main(String[] args) {
StringBuilder a = new StringBuilder("10");
function(a);
System.out.println(a);
}
private static void function(StringBuilder str){
str = new StringBuilder("20");
}
}

输出:10

这是为何呢,之前有说,变量是存储在栈,实际内容存储在堆,而造成这里不同的原因就是,Java中的赋值的操作(=)都不是将自身的内容进行改变,而是先检查有没有已经存在的并且等于它的值,有则指向

它,没有则另外创建一个,再指向它,所以在第二段代码里,str=new StringBuilder("20")并没有修改原有的自身的内容而是指向了一个新对象,也就是形参的str和实参a只想了不同的地址,自然对形参没有影响。而在第一段代码中,str.append();是对指向的内存进行操作,而指向的内存也就是实参引用所指向的内存,故有影响。

所以我觉得这里可以做个总结,那就是Java之间并没有引用传递,无论基本数据类型还是引用类型,传的都是值,都是实参的副本,但是不同的是,基本数据类型是实参内容的复制品,而引用类型也是,但是赋值的内容是地址罢了,即实参和形参指向一个同一块内存(对象),形参变化是否会改变实参取决于操作是否是对指向的这块内存进行直接修改。如果是赋值操作这种,那么形参操作对实参就没有影响。

老生常谈--Java值传递和引用传递的更多相关文章

  1. 死磕面试系列,Java到底是值传递还是引用传递?

    Java到底是值传递还是引用传递? 这虽然是一个老生常谈的问题,但是对于没有深入研究过这块,或者Java基础不牢的同学,还是很难回答得让人满意. 可能很多同学能够很轻松的背出JVM.分布式事务.高并发 ...

  2. Java中引用类型变量,对象,值类型,值传递,引用传递 区别与定义

    一.Java中什么叫做引用类型变量?引用:就是按内存地址查询       比如:String s = new String();这个其实是在栈内存里分配一块内存空间为s,在堆内存里new了一个Stri ...

  3. java中值传递和引用传递

    最近工作中使用到了值传递和引用传递,但是有点懵,现在看了下面的文章后清晰多了.一下是文章(网摘) 1:按值传递是什么 指的是在方法调用时,传递的参数是按值的拷贝传递.示例如下: public clas ...

  4. Java中的值传递和引用传递

    这几天一直再纠结这个问题,今天看了这篇文章有点思路了,这跟C++里函数参数为引用.指针还是有很大区别. 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里 ...

  5. java的值传递和引用传递

    昨天博主在对于值传递和引用传递这里栽了一个大坑啊,导致一下午时间都浪费在这里,我们先说下值传递和引用传递java官方解释: 值传递:(形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对 ...

  6. java中方法的参数传递机制(值传递还是引用传递)

    看到一个java面试题: 问:当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?  答:是值传递.Java 编程语言只有值传递参 ...

  7. java 对象传递 是 值传递 还是 引用传递?

    这个问题说实话我感觉没有太大的意义. 按第一印象和c++的一些思想去理解的话对象传递是引用传递,因为传递过去的对象的值能被改变. 但是又有很多人,不知道从哪里扣出来一句,java中只有值传递,没有引用 ...

  8. java参数传递时到底是值传递还是引用传递

    java参数传递时到底是值传递还是引用传递(baidu搜集) 问”,很多人的BLOG里都引用这些面试题,最近因为工作内容比较枯燥,也来看看这些试题以调节一下口味,其中有一道题让我很费解. 原题是:当一 ...

  9. Java面向对象-方法的值传递和引用传递

    Java面向对象-方法的值传递和引用传递 0 发布时间:『 2016-08-21 14:21』  博客类别:Java核心基础  阅读(197) 评论(0) Java面向对象-方法的值传递和引用传递 方 ...

随机推荐

  1. 实现Windows数据更新

    一.枚举 枚举是一组描述性的名称 定义一组有限的值,不能包含方法 对可能的值进行约束 .定义枚举类 public enum Gender { Male,Female } .使用枚举表示整数值 publ ...

  2. nodeJS菜鸟教程笔记

    http模块 var http = require('http'); // 引入http模块 var url = require('url'); // 引入url模块 var querystring ...

  3. HTTP 协议的 8 种请求类型介绍

    HTTP 协议的 8 种请求类型介绍 HTTP 协议中共定义了八种方法或者叫“动作”来表明对 Request-URI 指定的资源的不同操作方式,具体介绍如下: OPTIONS:返回服务器针对特定资源所 ...

  4. 强烈推荐一款强大的公式编辑器软件AxMath

    Axmath教程请移步:https://www.cnblogs.com/coco56/p/11759578.html

  5. gulp-css-spriter 雪碧图合并

    相信做前端的同学都做过这样的事情,为优化图片,减少请求会把拿到切好的图标图片,通过ps(或者其他工具)把图片合并到一张图里面,再通过css定位把对于的样式写出来引用的html里面.gulp-css-s ...

  6. POJ3723(最小生成树,负权)

    题目描述 温迪有一个国家,他想建立一支军队来保护他的国家.他收留了N个女孩和M个男孩,想把她们收留成他的士兵.征兵无特权,必须交纳一万元.女孩和男孩之间有一些关系,温迪可以利用这些关系来降低他的成本. ...

  7. Codeforces 474B. Worms

    It is lunch time for Mole. His friend, Marmot, prepared him a nice game for lunch. Marmot brought Mo ...

  8. ALSA lib编译

    http://blog.sina.com.cn/s/blog_7d7e9d0f0101lqlp.html alsa  lib: #!bin/sh rm -rf ./output/* mkdir -p ...

  9. .netcore 3.1高性能微服务架构:加入swagger接口文档

    本文为原创文章:首发:http://www.zyiz.net/tech/detail-108663.html swagger是什么? Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视 ...

  10. JavaScript中四种不同的属性检测方式比较

    JavaScript中四种不同的属性检测方式比较 1. 用in方法 var o = {x:1}; "x" in o; //true "y" in o; //fa ...