一文了解为什么Java中只有值传递

目录
  • 经典的问题
  • 形参&实参
  • Java是值传递还是引用传递
    • 传参的类型:基本数据类型
    • 传参的类型:引用数据类型
  • 尾语

经典的问题

Java 传参是值传递还是引用传递?这个问题很基础,但是许多人都有点懵

形参&实参

首先我们得了解关于参数的几个概念

形式参数:定义函数时使用的参数,用来接收函数传入参数,比如我们写个函数,函数中的参数为形式参数

public void test(String str) { //str为形式参数
    System.out.println(str);
}

实际参数:我们调用函数时,函数名后面括号中的参数称为实际参数,必须有确定的值,如下面例子所示

public static void main(String[] args) {
    A a = new A();
    a.test("小 明"); //"小 明"则为实际参数
}

可以发现,当调用一个有参函数的时候,会把实际参数传递给形式参数。

这种传递的过程的参数一般有2种情况值传递和引用传递。

  • 值传递:调用函数时将实际参数复制一份传递到函数中,函数内部对参数内部进行修改不会影响到实际参数,即创建副本,不会影响原生对象
  • 引用传递 :方法接收的是实际参数所引用的地址,不会创建副本,对形参的修改将影响到实参,即不创建副本,会影响原生对象

我们还得知道:在Java中有2种数据类型,其中主要有基本数据类型引用数据类型,除了8种基本数据类型以外都是引用数据类型,分别是byte,short,int,long,char,boolean,float,double

Java是值传递还是引用传递

对于这个问题,我们先来看几个例子慢慢道来:

传参的类型:基本数据类型

public class TestBasic {
    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 20;
        change(num1, num2);
        System.out.println("==============");
        System.out.println("num1 = " + num1);
        System.out.println("num2 = " + num2);
    }

    public static void change(int param1, int param2) {
        System.out.println("param1 = " + param1);
        System.out.println("param2 = " + param2);
        param1 = 333;
        param2 = 444;
        System.out.println("after change....");
        System.out.println("param1 = " + param1);
        System.out.println("param2 = " + param2);
    }
}

结果:

param1 = 10
param2 = 20
after change....
param1 = 333

param2 = 444

==============

num1 = 10
num2 = 20

我们可以发现,change()方法内对变量重新赋值,并未改变变量num1和num2的值,改变的只是change()方法内的num1和num2的副本。我们需要知道,基本数据类型在内存中只有一块存储空间,分配在栈stack中。

Java传参的类型如果是基本数据类型,是值传递

传参的类型:引用数据类型

public class TestQuote {

    public static void main(String[] args) {
        String str = "小明";
        StringBuilder str2 = new StringBuilder("今天天气好");
        change(str,str2);
        System.out.println("==============");
        System.out.println("str = " + str);
        System.out.println("str2 = " + str2);

    }

    public static void change(String param1,StringBuilder param2) {
        System.out.println("param1 = " + param1);
        System.out.println("param2 = " + param2);
        param1= "小张";
        param2.append(",我们去钓鱼");
        System.out.println("after change....");
        System.out.println("param1 = " + param1);
        System.out.println("param2 = " + param2);
    }
}

结果:

param1 = 小明
param2 = 今天天气好
after change....
param1 = 小张

param2 = 今天天气好,我们去钓鱼

str = 小明
str2 = 今天天气好,我们去钓鱼

我们发现str变量没有改变,但是str2变量却改变了,大家是不是迷惑了:Java传参的类型如果是引用数据类型,是值传递还是引用传递

其实大家被一堆术语给忽悠了,笔者画了2张图,帮助大家理解:

before change():

after change():

在Java中,除了基本数据类型以外,其他的都是引用类型,引用类型在内存中有两块存储空间(一块在栈stack中,一块在堆heap中)。

如果参数是引用类型,传递的就是实参所引用的对象在栈中地址值的拷贝,这里创建的副本是 地址的拷贝。那就有人说了,可是它值变了呀,这明明就是"引用传递"嘛?

我们可以换个角度理解,如果我们把栈地址当成值,会创建栈地址副本(复制栈帧),栈地址最终并没有改变,改变的是堆内存中的值。这就好比栈地址是钥匙,我们copy了一把,它能打开保险箱。我们关心的是钥匙有没有花纹这种变化,至于打开保险箱后的钱多钱少,我们并不需要关心。

虽然调用完函数后,str2变量值(堆中的数据)改变了,但是参数是引用类型,传递的实参是 栈中地址值,这是我们关心的,拷贝的是栈中地址值,最终栈中地址值并没有改变。所以是符合值传递的定义创建副本,不会影响原生对象。

可能又有人问了,那str变量值为啥没有改变呢?其实这完全是由于String类的特殊,我们知道它是不可变的final,这个时候在函数中 param1= "小张";其实会隐式创建一个新的String对象,同时堆内存中会开辟一个新的内存空间,param1指向了这个新开辟的内存空间。原地址str指向的堆内存空间中数据没有任何改变。

尾语

Java中只有值传递,始终是传值的,我们要牢记,这个是官方明确说的。我们还应该清楚,其中的缘由。

参数是基本数据类型,复制的是具体值;如果参数是引用类型,把地址当成值,复制的是地址;还有String类是一个非常特殊的类,她是不可变的。

到此这篇关于一文了解为什么Java中只有值传递的文章就介绍到这了,更多相关Java值传递内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 浅谈Java中真的只有值传递么

    回顾值传递和引用传递 关于Java是值传递还是引用传递,网上有不一样的说法. 1.基本类型或基本类型的包装类以及String是值传递,引用类型是引用传递. 2.Java中只有值传递. 关于这个问题应该是存在争议的.根据测试出来的结果和我们自己的经验,以及口口相传或是上学时老师讲的,我们认为是第一种.但第二种说法的呼声也很高,渐渐地我们也认为第2中才是对的.那么下面我们就来分析一下这个问题. 在谈这个问题之前我们先了解值传递和引用传递的概念及现象.我还记得,值传递和引用传递这些概念是大学里学Jav

  • 为什么Java中只有值传递

    参数传递 在我们日常编写代码的过程中,调用函数可能是最常见的操作了.那么,在调用函数时,参数是怎么样传递的呢? 值传递 相信有很多人都是学C语言入门的,刚开始写代码时,用的最多的就是值传递了. void plus_one(int a){ a++; printf("a: %d", a); } int main(){ int n = 10; plus_one(n); printf("n:%d", n); return 0; } 这是一个简单的值传递的例子,无需多言,pl

  • 带你详细了解Java值传递和引用传递

    1.什么是值传递,什么是引用传递? 值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数. 引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数. 2.值传递和引用传递的区别是什么? 3.Java中只有值传递 3.1 纠正一下大家以前的那些错误看法 错误理解一:值传递和引用传递,区分的条件是传递的内容,如果是个值,就是值传

  • Java中值传递的深度分析

    前言 首先说观点:java只有值传递没有引用传递 然后再来看看值传递与引用传递两者的定义 值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数. 引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数. 这里牢记值传递中将实际参数复制一份. 然后就是对于参数类型:值类型 和 引用类型. 结合起来理解就是:值类型传递,java

  • 一文秒懂java到底是值传递还是引用传递

    首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语.按值调用(call by value)表示方法接收的是调用者提供的值,而按引用调用(call by reference)表示方法接收的是调用者提供的变量地址.一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值. 它用来描述各种程序设计语言(不只是 Java)中方法参数传递方式. Java 程序设计语言总是采用按值调用.也就是说,方法得到的是所有参数值的一个拷贝,也就是说,方法不能修改传递给它的任何参

  • 深入了解为什么Java中只有值传递?

    1.为什么 Java 中只有值传递? 首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语.按值调用(call by value)表示方法接收的是调用者提供的值,而按引用调用(call by reference)表示方法接收的是调用者提供的变量地址.一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值. 它用来描述各种程序设计语言(不只是Java)中方法参数传递方式. Java程序设计语言总是采用按值调用.也就是说,方法得到的是所有参数值的一个拷贝,也就

  • 一文了解为什么Java中只有值传递

    目录 经典的问题 形参&实参 Java是值传递还是引用传递 传参的类型:基本数据类型 传参的类型:引用数据类型 尾语 经典的问题 Java 传参是值传递还是引用传递?这个问题很基础,但是许多人都有点懵 形参&实参 首先我们得了解关于参数的几个概念 形式参数:定义函数时使用的参数,用来接收函数传入参数,比如我们写个函数,函数中的参数为形式参数 public void test(String str) { //str为形式参数 System.out.println(str); } 实际参数:我

  • Java中的值传递和引用传递实例介绍

    复制代码 代码如下: package Object.reference; public class People {     private String name;     private int age;     public People(){     }     public People(String name, int age) {         super();         this.name = name;         this.age = age;     }    

  • java中的值传递和引用传递的区别分析

    传值---传递基本数据类型参数 复制代码 代码如下: public    class           PassValue{    static void exchange(int a, int b){//静态方法,交换a,b的值        int temp;        temp = a;        a = b;        b = temp;    }    public static void main(String[] args){       int i = 10;   

  • 全面理解Java中的引用传递和值传递

    目录 1.基本类型和引用类型在内存中的保存 2.变量的基本类型和引用类型的区别 3.引用传递和值传递 4.结论 关于Java传参时是引用传递还是值传递,是一个讨论比较多的话题, 有说Java中只有值传递,也有些地方说引用传递和值传递都存在,本篇记录思考过程,不保证正确性, 感兴趣的同学一起讨论. 1.基本类型和引用类型在内存中的保存 Java中数据类型分为两大类,基本类型和对象类型.相应的,变量也有两种类型:基本类型和引用类型. 基本类型的变量保存原始值,即它代表的值就是数值本身: 而引用类型的

  • 一文搞懂Java中的反射机制

    前一段时间一直忙,所以没什么时间写博客,拖了这么久,也该更新更新了.最近看到各种知识付费的推出,感觉是好事,也是坏事,好事是对知识沉淀的认可与推动,坏事是感觉很多人忙于把自己的知识变现,相对的在沉淀上做的实际还不够,我对此暂时还没有什么想法,总觉得,慢慢来,会更快一点,自己掌握好节奏就好. 好了,言归正传. 反射机制是Java中的一个很强大的特性,可以在运行时获取类的信息,比如说类的父类,接口,全部方法名及参数,全部常量和变量,可以说类在反射面前已经衣不遮体了(咳咳,这是正规车).先举一个小栗子

  • 一文详解Java中的类加载机制

    目录 一.前言 二.类加载的时机 2.1 类加载过程 2.2 什么时候类初始化 2.3 被动引用不会初始化 三.类加载的过程 3.1 加载 3.2 验证 3.3 准备 3.4 解析 3.5 初始化 四.父类和子类初始化过程中的执行顺序 五.类加载器 5.1 类与类加载器 5.2 双亲委派模型 5.3 破坏双亲委派模型 六.Java模块化系统 一.前言 Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最 终形成可以被虚拟机直接使用的Java类型,这个过程

  • 一文详解Java中Stream流的使用

    目录 简介 操作1:创建流 操作2:中间操作 筛选(过滤).去重 映射 排序 消费 操作3:终止操作 匹配.最值.个数 收集 规约 简介 说明 本文用实例介绍stream的使用. JDK8新增了Stream(流操作) 处理集合的数据,可执行查找.过滤和映射数据等操作. 使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询.可以使用 Stream API 来并行执行操作. 简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式. 特点 不是数据结构

随机推荐