在c/c++中对于传参类型,无外乎就是传值、传引用、传指针这几种。但在java中,由于没有指针类型,其传参的方式也发生了相应的变化。之前有搜过相关的知识点一直理解的是:Java的传参方式中主要有两种:传值和传引用。(基本数据类型相当于传值,对象相当于传参)

但是,在做需求的时候遇到了,将从上一个方法中获取到的对象,当做参数传进下一个方法中的时候,如果传进来的是空对象,那么在给这个“对象”直接赋值的时候,会报空指针异常!

探究与理解:
Java中传值也就是传的是原变量的一个副本,函数内部无论怎么操作都不会影响到原变量本身,影响到的只是原变量的那个副本。

经典的一个test:

public class Test {
public static void main(String[] args){
int a = , b = ;
fun(a,b);
System.out.println("a="+a);}
static void fun(int m , int n){
m = m + n; }
}

运行结果:a=1.

另一个例子:

public class Test {
public static void main(String[] args){
List<String> str_1 = new LinkedList<String>();
str_1.add("");
fun(str_1);
System.out.println("str_1 ="+str_1);}
static void fun(List s){
s.add("");}
}

运行结果:str_1 = [111,222] 从这个例子来看似乎,Java传对象的时候就是传引用。

那么,我们再看另一个例子:

public class Test {
public static void main(String[] args){
List<String> str_1 = new LinkedList<String>();
List<String> str_2 = new LinkedList<String>();
str_1.add("");
str_2.add("");
fun(str_1,str_2);
System.out.println("str_1 ="+str_1);
System.out.println("str_2 ="+str_2);}
static void fun(List s,List m){
List<String> str = new LinkedList<String>();
str = s;
s = m;
m = str;}
}

运行结果为:str_1 =[111] , str_2 =[333] .我们发现str_1与str_2的值并没有发生交换。 如果该对象传的是引用的话,那它们两个的值应该发生了变化才对。 然而,java中对象作为实参,传递的实际上还是值,即java中的传参传递的都是值!

下面从jvm的构成角度来解释一下自己对这个问题的理解:

JVM的结构图:

从Jvm的结构图上可以看出来,Jvm在执行Java程序的时候将属于它的内存分为五部分。其中程序代码(字节码)和基本的数据类型是放在java栈的栈帧中,而对象是从堆中分配的。堆,我们可以形象的理解成“对象池”。程序和程序中需要用到的对象放在两个相对独立的区域中,那么程序怎么使用对象呢?

实际上是程序中真正使用对象的地方其实只是声明了一个对象的引用,也就是把堆中分配了的相应对象的地址放到引用中,当然引用也是放在栈内存中,栈和堆之间就是通过一个一个的引用来联系的。至于引用,我们可以把它看做是一个指针常量,这个指针指向引用对象的地址。所以,不管是基本类型变量(int,float,double等)还是对象,相应的内存地址中存放的都是一个数(无符号整数,整数,浮点数等)。当方法调用时候,方法的参数会占内存中开辟一块新的区域,同时把要传递的基本类型,或者引用类型名称复制到这块内存中,结果是,基本类型(存放在占内存中的)复制之后连同其数值也复制到了这块内存中,而对象只是复制了引用名,实际还要联系到原对象所在的堆区域中。之所以说java中传递的都是值,是因为传递得是内存地址中的数,当然,这个值对于基本类型和对象类型来说意义是不一样的,对于基本类型这个数就是其值本身,传递值的结果就是,改变新的变量的值不影响旧的变量的值;而对于对象来说这个数是它的地址,传递这个值就相当于传递了真实对象的引用,传递了引用或者说是地址的结果就是变化会全局可见。所以说java中的方法都是按值调用的!只不过基本类型和对象类型的"值"的在具体的机制上作用不同。

所以在第二个例子中,fun方法中,两个list s和m交换,实际只是str_1与str_2在栈中对应的引用值进行了交换,而引用与相应堆区域的联系并没有改变。因此,str_1与str_2的值并没有发生变化。

结论:

java中不论是基本类型还是对象,方法调用时,传递的都是值!

对于基本类型的变量,相当于操作其副本。

对于对象,相当于复制了一个引用,该引用指向的还是原变量的内存区域。

Java的对象传参问题的更多相关文章

  1. Java自学-类和对象 传参

    Java中的传参 变量有两种类型 基本类型 和类类型 参数也是变量,所以传参分为 基本类型传参 类类型传参 步骤 1 : 基本类型传参 基本类型传参 在方法内,无法修改方法外的基本类型参数 publi ...

  2. java复用和传参

    java复用和传参的三种方法总结: (1) 直接在一个类中调用函数 : 1 package test1; 2 3 public class a 4 { 5 public static void get ...

  3. [Java]_函数传参的疑惑与思考

    问题来源于leetcode上的两道题 Path Sum I && II,分别写了两个dfs. void dfs(TreeNode node , int sum , ArrayList& ...

  4. Spring cloud Feign不支持对象传参解决办法[完美解决]

    spring cloud 使用 Feign 进行服务调用时,不支持对象参数. 通常解决方法是,要么把对象每一个参数平行展开,并使用 @RequestParam 标识出每一个参数,要么用 @Reques ...

  5. SpringCloud:feign对象传参和普通传参及遇到的坑

    对象传参: #使用@RequestBody来指定传参对象 @RequestMapping(value = "/v2/matterCode/genCode", method = Re ...

  6. 由PHP实现单向链表引发的对象赋值,对象传参,链表操作引发的一系列问题

    2019年2月25日14:21:13 测试版本php 5.4 ,5.6,7.0,7.2 代码请看: https://www.cnblogs.com/zx-admin/p/10373866.html 1 ...

  7. datasnap远程方法支持自定义对象传参

    有同仁需要远程方法传输自定义的数据类型,他以为要自己写代码会很复杂,其实DATASNAP早就为我们想到了. datasnap的数据序列和还原真是无与伦比的强大,其远程方法支持自定义对象传参,DATAS ...

  8. js date对象传参获取特定日期的时间戳

    当我们想要通过js获取某一特定时间的时间戳时,会通过给date对象传参再通过getTime函数来获取,传递的参数格式也有不同形式.有些时候,可能会因为自己传入参数的格式不正确而导致date对象inva ...

  9. Java函数的传参机制

    一 最近的一个项目,里面各种返回void,参数用引用类型,那叫一个熟和多,但是也把我绕糊涂了. 我就打算好好理一理java的传参机制,整理一番 二 很多人一听Java的传参,那一定会脱口而出,java ...

随机推荐

  1. JavaScript中数组的应用

    Array的应用 1)创建 new Array();new Array(size);new Array(element,element,...,element); 2).Array对象属性 const ...

  2. squid http,https, 代理,默认端口3128

    squid http,https, 代理,默认端口3128 https 代理时出现 403,是因为squid默认允许 192.168.0.0 网段代理 在配置文件中,““acl localnet sr ...

  3. python-setuptool安装

    安装setuptools时报error: ”RuntimeError: Compression requires the (missing) zlib module“ 解决办法: yum安装zlib和 ...

  4. 理解OpenShift(5):从 Docker Volume 到 OpenShift Persistent Volume

    理解OpenShift(1):网络之 Router 和 Route 理解OpenShift(2):网络之 DNS(域名服务) 理解OpenShift(3):网络之 SDN 理解OpenShift(4) ...

  5. rxjava&retrofit请求直接返回string

    1.添加gradle依赖: compile com.squareup.retrofit2:converter-scalars:2.0.0' 2.更换转换器 mRetrofit = Retrofit.B ...

  6. 使用阿里云Java SDK 实现 DDNS

    本代码的实现前提: 1.拥有阿里云域名,且获取了Access Key 及 Access Secret 2.能获取外网IP的页面地址(注意:ip138.com的实际包含ip地址为http://2018. ...

  7. Why Lua?

    Why Lua? 最近在很多的地方都遇到了lua这个东西,于是想一探究竟,为什么这么多的游戏前端都用了Lua脚本呢? 于是乎简单的看了一下Lua,目前总结出来了几点~ 还是先放上资源: GitHub上 ...

  8. docker的核心概念和安装

    里Dcoker的安装要求 我这里安装的是在vmware下的centos7 64位 并且通过模拟远程连接xshell 我在安装好之后就配置了静态ip,这里我就不多说怎么配置了 具体静态ip配置可以参考 ...

  9. 关于ueditor插入不了动态地图

    1. 打开编辑器根目录下面的ueditor.all.js文件,找到: table.setAttribute("data-sort", cmd == "enablesort ...

  10. API手册(2017)

    本页存放内容: API手册. 少量教程 [旧的工具页面] (是一些旧的页面.不放在外面了,这里做个索引) http://www.cnblogs.com/qq21270/p/3538677.html 常 ...