首先说观点:java只有值传递没有引用传递

然后再来看看值传递与引用传递两者的定义

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

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

这里牢记值传递中将实际参数复制一份。

然后就是对于参数类型:值类型 和 引用类型。

结合起来理解就是:值类型传递,java是将其值内容复制一份给形参;对于引用类型传递,java是将其地址复制一份给形参。

下面结合实例深入理解为什么java只有值传递

package 字符串;

public class 值传递 {
public static void main(String[] args)
{
String str1="abc";
updateStr1(str1);
System.out.println("main函数中"+str1);
}
public static void updateStr1(String str1)
{
str1="cba"; //<注解>
System.out.println("调用函数中"+str1);
} }

结果:

在这里我们能够清晰看到我们传递的是String类型的对象即(引用类型),并且在调用函数中我们修改了str1为cba,如果是引用传递那么我们在主函数打印则应该是cba,

但是很遗憾我们在主函数中仍然打印出来的是abc。所以我们可以说java是值传递类型了吗,答案是不完全的。

接下来再看这一段代码:

package 字符串;
  

  public class person {
   private int age;
   public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }

}
public class 值传递2 {
public static void main(String[] args)
{
person p1=new person();
p1.setAge(10);
System.out.println("我在主函数里对p1的年龄属性赋值为"+p1.getAge());
setage(p1);
System.out.println("我再从主函数里获取P1的年龄属性"+p1.getAge());
} public static void setage(person p1)
{
p1.setAge(18); //不是我们对它的地址进行了操作,而是我们对它地址的内容进行了操作
System.out.println("我在调用函数里对p1的年龄属性重新赋值为"+p1.getAge());
} }

结果:

咦,怎么回事这次也是传递的对象(引用类型),为什么这次我们对年龄这个字段的修改在主函数同步了呢?

别急,下面我们先来分析这两个例子。

首先第一个类型的例子中,我们传递的是String类型的变量,它是一个特殊的类型的引用变量。

(不可变字符串:编译器可让字符串共享,即将各种字符串存放于公共存储池中,字符串变量是指向其中相应位置    --出自《Java核心技术 卷1》)

出于这句话的理解就是每个字符串都对应一个地址:我们例一中是将str1的地址复制给了我们的形参str1,并且形参中str1的地址进行了改变指向了“cba”的地址。所以说在主函数中的str1的地址仍然指向的是“abc”所对应的地址。

所以说对于String类型的变量,我们对于给它重新赋值不是改变了它的内容,而是改变了它指向字符串的位置。这也就解释了为什么java中String类型是不可变类型。

而在我们例二中,我们将p1的地址复制给了我们形参中的p1,此时他们都指向的内存中一块相同的地址这里存放着相同内容,所以我们在调用函数对这个地址中的内容进行修改时就会同步到我们主函数中的p1。所以这个并不意味着这个是引用传递。

好吧,那怎么才能解释好Java确实是值传递呢(上面String类型例子是特殊的引用类型不方便解释)

下面我们通过这个例子说明:

package 字符串;
public class person {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} }
public class 值传递3 {
public static void main(String[] args) {
person p1=new person();
person p2=new person();
p1.setAge(10);
p2.setAge(18);
System.out.println("我在主函数里对p1的年龄属性赋值为"+p1.getAge());
System.out.println("我在主函数里对p2的年龄属性赋值为"+p2.getAge());
swap(p1,p2);
System.out.println("************我是主函数里的分割线***************");
//我再在主函数里分别对p1,p2获取他们的年龄,若为引用传递则p1的年龄应该为18,p2为10.
System.out.println("我在主函数里获取p1的年龄"+p1.getAge());
System.out.println("我在主函数里获取p1的年龄"+p2.getAge());
}
public static void swap(person p1,person p2)
{
System.out.println("************我是调用函数里的分割线***************");
person temp=new person();
temp=p1;
p1=p2;
p2=temp;
System.out.println("我在调用函数里交换了p1和p2指向的地址");
System.out.println("我在调用函数里对p1的年龄属性赋值为"+p1.getAge());
System.out.println("我在调用函数里对p2的年龄属性赋值为"+p2.getAge()); } }

结果:

看到没,这就是充分说明Java是值传递的例子。在这个例子中我们依然传递的是person类的对象p1,p2(引用类型),他们将各自的地址复制一份到了形参p1、p2。

然后我们在调用函数中交换了他们的地址,确实在调用函数中他们的age属性发生交换。但是再当我们在主函数获取他们的age时,如果是引用传递则应该p1的age为18,p2的age为10,

和我们在调用函数中打印结果一致。但是,很遗憾在主函数中他们的值仍然是p1(10),p2(18)。所以这也充分印证了java是值传递。

那么什么是引用传递呢?我们把代码放入C#看看。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace 值传递or引用传递
{
public class person
{
private int age;
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
} }
class Program
{
static void Main(string[] args)
{
person p1 = new person();
person p2 = new person();
person p3 = new person();
p1.setAge(10);
p2.setAge(18);
p3.setAge(15);
Console.WriteLine("我在主函数里对p1的年龄属性赋值为" + p1.getAge());
Console.WriteLine("我在主函数里对p2的年龄属性赋值为" + p2.getAge());
Console.WriteLine("我在主函数里对p3的年龄属性赋值为" + p3.getAge());
swap(ref p1,ref p2,p3);
Console.WriteLine("************我是主函数里的分割线***************");
//我再在主函数里分别对p1,p2获取他们的年龄,若为引用传递则p1的年龄应该为18,p2为10.
Console.WriteLine("我在主函数里获取p1的年龄" + p1.getAge());
Console.WriteLine("我在主函数里获取p2的年龄" + p2.getAge());
Console.WriteLine("我在主函数里获取p3的年龄" + p3.getAge());
}
public static void swap(ref person p1,ref person p2, person p3)
{
Console.WriteLine("************我是调用函数里的分割线***************");
person temp = new person();
temp = p1;
p1 = p2;
p2 = temp;
p3.setAge(20);
Console.WriteLine("我在调用函数里交换了p1和p2指向的地址");
Console.WriteLine("我在调用函数里对p1交换地址后年龄为" + p1.getAge());
Console.WriteLine("我在调用函数里对p2交换地址后年龄为" + p2.getAge());
Console.WriteLine("我在调用函数里修改p3年龄为" + p3.getAge()); }
}
}

结果:

请注意在C#中如果我们要实现引用传递,请加上关键字ref,否则,它执行的原理仍然与我们java中执行的机制一样,即拷贝一份地址给形参。

如果你还有点晕,不妨我们来看看下面两张图。

为了方便大家理解把图画成这样,然后关于java的值传递深度分析就到这里。欢迎大家一起讨论。(可以打脸/哈哈)

关于Java 值传递深度分析的更多相关文章

  1. JAVA CAS原理深度分析 volatile,偏向锁,轻量级锁

    JAVA CAS原理深度分析 http://blog.csdn.net/hsuxu/article/details/9467651 偏向锁,轻量级锁 https://blog.csdn.net/zqz ...

  2. String 不变性以及 Java 值传递和引用传递

    String 不变性以及 Java 值传递和引用传递 public class Example { String str = new String("good"); char[] ...

  3. 老生常谈--Java值传递和引用传递

    起因 前两天面试被问到了这个问题,虽然之前老早就了解过这个问题,但是并没有深入了解,所以面试的时候一下子慌了,菜是原罪,今天菜鸡来补补基础知识. 其实这个问题一直是被讨论的,常见的三种说法就是,1,J ...

  4. Java值传递和引用传递详细解说

    前天在做系统的时候被Java中参数传递问题卡了一下,回头查阅了相关的资料,对参数传递问题有了新的了解和掌握,但是有个问题感觉还是很模糊,就是 Java中到底是否只存在值传递,因为在查阅资料时,经常看到 ...

  5. 关于Java函数传参以及参数在函数内部改变的问题——JAVA值传递与引用最浅显的说明!

    看了很多关于阐述JAVA传参到底是值传递还是引用的问题,有些说得很肤浅让人感觉似懂非懂的感觉,但是好像又能解决一些问题,然后就止步了.还有一些则是,讲得很深奥,看着好像很有道理的样子,但是其实还是没怎 ...

  6. 理解java值传递与引用传递

    1.基本类型和引用类型在内存中的保存 Java中数据类型分为两大类,基本类型和对象类型.相应的,变量也有两种类型:基本类型和引用类型.基本类型的变量保存原始值,即它代表的值就是数值本身:而引用类型的变 ...

  7. 06-02 Java值传递、数据加密

    值传递: /* 思考题1:看程序写结果,然后分析为什么是这个样子的.并画图讲解.最后总结Java中参数传递规律. Java中的参数传递问题: 基本类型:形式参数的改变对实际参数没有影响.基本类型传递的 ...

  8. JAVA 值传递

    Java里方法的参数传递方式只有一种:值传递 值传递:当系统开始执行方法时,系统为形参执行初始化,就是把实参变量的值赋给方法的形参变量,方法的操作的并不是实际的实参变量 引用型变量:系统复制的是变量, ...

  9. java 值传递和引用传递。

    java中 基本类型的参数传递是值传递,即前后两个方法的变量不相干,被调方法参数值改变不影响调用方法的传参数值. 引用数据类型的参数传递是 传递的是参数的地址.即被调方法修改参数值会,调用方法里会跟着 ...

随机推荐

  1. 17.Linux高可用之Keepalived

    1.什么是高可用,为什么要设计高可用? 两台机器启动着相同的业务系统,当有一台机器宕机,另外一台服务器能快速的接管,对于访问的用户是无感知的. 减少系统不能提供服务的时间. 2.高可用使用什么工具来实 ...

  2. js初学者循环经典题目

    1.根据一个数字日期,判断这个日期是这一年的第几天例如: 2016和02和11,计算后结果为42 var y = 2016;//+prompt("请输入年份") ;         ...

  3. lable的渲染

    <StackPanel Margin=" TextOptions.TextFormattingMode="Display"> <Label TextOp ...

  4. human_pose_estimation_demo的再进一步研究

    这次研究的主要是速度问题,后来还获得了其它方面的收获. 1.原始的抽帧       对于这样一个问题,想提高速度,能够想到的最简单.最直接的方法就是“抽帧”.比如添加一个计数器 这里,只有当Sumof ...

  5. 手把手实现微信网页授权和微信支付,附源代码(VUE and thinkPHP)

    wechat github 手把手实现微信网页授权和微信支付,附源代码(VUE and thinkPHP) 概述 公众号开发是痛苦的,痛苦在好多问题开发者文档是没有提到的,是需要你猜的. 在开发过程中 ...

  6. 函数进阶(二) day13

    目录 昨日内容 闭包函数 装饰器 二层装饰器 装饰器模板 三层装饰器 今日内容 迭代器 可迭代对象 迭代器对象 for循环原理(迭代循环) 三元表达式 列表推导式 字典生成式 生成器 yield关键字 ...

  7. 选择器, ,>,+,~

    一.后代选择器 选取指定元素的后代元素 与子元素选择器相比,后代选择器选取的不一定是直接后代(儿子),而是作用于所有后代元素(儿子.孙子.重孙…)都可以. 二.(>)子元素选择器 选取某个元素的 ...

  8. 我是如何在一周内拿到4份offer的?

    前言 大概一个月没写博客了吧,这段时间事情比较多(家里有事,请了一段时间假,正好利用剩余几天时间面了几次试),也没抽出来时间写博客,还好所有的事情已经处理完了,今天闲来无事就整理一下这几次面试过程中遇 ...

  9. 如何使用git上传代码

    首先在github 上创建好远程仓库,并拷贝仓库地址,接下来按照以下步骤:   1.打开命令行进入要上传的文件目录,初始化 git init  2. 建立远程仓库,git remote add ori ...

  10. 程序员这十个java题你都会吗?

    前言 不论你是职场新人还是步入职场N年的职场新人大哥大~当然这个N<3~,我能担保你答不对这十个题~不要问我为什么这么自信~,这些个题还是"有水平"的javase的基础题,传 ...