首页 > 基础资料 博客日记

Java中的实参和形参

2025-01-17 08:00:08基础资料围观22

文章Java中的实参和形参分享给大家,欢迎收藏Java资料网,专注分享技术知识

一、背景

为了回顾Java的一些基础但不常用的知识,于是打算出一个合集,方便迅速查找(主要还是不想翻课本,并且把概念和脉络厘清一些)

  • 对于初学者而言,对这方面的理解可能是:在函数内修改形参的值,会导致实参发生改变吗?
  • 对于有一定编程基础的同学,可能会感到疑问:Java是值传递还是引用传递?
  • 对于编写过程序,但对概念不是特别清晰的小伙伴,可能会得出这么一个结论:在函数内修改形参的值,有时会导致实参的值发生改变,有时不会。Java有时是值传递,有时是引用传递。

(*´・д・)?  (*´・д・)?  (*´・д・)?

二、结论

先说结论:

在函数内修改形参的值,不会导致实参的发生改变,但可能会导致实参指向的对象发生改变,所以看起来像是实参发生了改变

Java是值传递

其实这些结论的意思并不矛盾,但对于初学者来说,可能不太能够理解这些概念。因此我会从头分析这些概念的含义,并解释出现“矛盾”的原因。

如果对这些概念比较清楚的小伙伴,可以自行跳过啦!

三、解释

1.“实参”、“形参”、“值传递”、“引用传递”

提前声明:概念的解释不一定很规范,只是个人的理解

a.实参

实参是调用方法时传入的具体值或对象。

它们实际在方法调用时传递给形参。

add(3, 5);//这里的3,5为实参

b.形参

形参是定义方法时,在方法声明中使用的参数

它们是方法的“占位符”,表示将要传入方法的值或对象。形参在方法体内部作为局部变量使用。

public int add(int a, int b) {//这里的a,b为形参
    int sum = a + b;
    return sum;
}

c.值传递

在调用函数时,将实际参数复制一份传递到函数中

顾名思义,就是将参数的值传递给形参。既然是值,那么相当于和原来的实参不再有关系。

d.引用传递

在调用函数时,将实际参数的地址直接传递到函数中

顾名思义,就是将参数换个名字(别名)传递给形参。既然是别名,那么实际上还是同一个变量。

综上所述,“Java是值传递”就代表“在函数内修改形参的值,不会导致实参发生改变”。因为传递的只是拷贝。

这时候可能会有人有疑惑:嘶~不对呀,那我传递数组时,在函数里面修改数组的值,实参也发生改变了呀,这是怎么回事?

没错,这就是看似“矛盾”的地方,我们接着往下看

2.Java 的数据类型

a.Java 的两大数据类型:

  • 内置数据类型:Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。byte、short、int、long、float、double、boolean、char。

  • 引用数据类型:在Java中,引用类型的变量非常类似于C/C++的指针。引用类型指向一个对象,指向对象的变量是引用变量。

  我相信对于没学过的其它编程语言的初学者来时,引用数据类型的定义十分晦涩难懂,在不了解“指针”这个概念的前提下,很难理解“指向”的具体含义。这是人之常情,也无可厚非。学习没有必要追求每一个细节,很多概念的理解在了解完后面的知识后便会豁然开朗。我当初对于这个概念就直接跳过,并且这个知识点出现的频率很低。第一次遇到这个问题时,自己琢磨出“new出来的变量作为实参传递给函数时,在函数里面修改会导致实参改变”这个一个粗糙的结论。

在这里简单介绍一下“指针”的概念(解释不规范,只是为了本文需要)

  • 如果我们把操作“int x = 1;”分为声明变量赋值
  • “int x;”为声明变量,数据类型为int,对应下表的名称; “x=1;”为赋值,对应下表的值
  • 对于内置数据类型而言,上述操作只需要一个表即可
  • 对于引用数据类型而言,定义变量的操作则需要两个表。

         “A a;”为声明变量创建一个表,数据类型为A,名称为a(与上面相同)。

        “a = new A();”可以分成两步。

                第一步是创建对象,即“new A();”操作,这是创建一个值的过程(实例化),需要创建一个新的表。

                第二步才是给a赋值(关键!),a的值为第一步中新创建的对象的地址。也就是说,a的值实际上是一个地址,这个地址指向一个对象。

  

至于为什么会有引用数据类型,为什么不能像内置数据类型一样直接把新对象的值放在a的值里,就不是本文需要探讨的内容,有兴趣的小伙伴可以自己探索一下。

b.String类型

值得注意的是,根据上述的定义我们知道String类型不属于内置数据类型,而属于引用数据类型,但String类型表现的像内置数据类型。

在 Java 中,String 是一个引用数据类型,而不是基本数据类型。

尽管 String 在许多方面表现得像基本数据类型(例如,它具有类似于基本数据类型的常量池、不可变性等特点),但它仍然是一个类,属于引用数据类型。你可以把 String 看作是一个特殊的类,Java 对它做了一些优化,使得它在使用时像基本数据类型一样高效和方便。

基本数据类型(如 intcharboolean 等)是直接存储在栈中的值,而 String 对象是存储在堆中的。

然而在大多数情况下,都可以把String类型当作是基本数据类型(一直以来我都是这么干的,哈哈哈(→ܫ←))。但还是需要稍微厘清一下这个概念。

3.矛盾分析

有了上述理论知识,那么理解“矛盾”的根本所在就很清晰了

Java仍然是值传递

也就是说,在a作实参时,传递给形参:a的值的拷贝。

因此不变的是a的值(也就是对象的地址),改变的是对象。

很好理解,对于局部变量形参来说,形参的值是a的值拷贝,所以形参和实参指向的是同一个对象。借助形参改变了对象,所以在函数外部看起来就像是:函数改变了实参

实际上实参的值没改变,只是实参的值所指向的对象改变了,不知道这样的说法能不能理解。

4.代码演示

a.实验代码:

  • 测试内置数据类型,在函数内修改形参的值
  • 测试引用数据类型,在函数内修改形参的值
  • 测试引用数据类型,在函数内修改形参指向的对象
  • 测试String类
public class Main {

    public static void main(String []args) {
        System.out.println("****************************************************");
        int x=1;//内置数据类型
        System.out.println("原来的x:"+x);//输出x的值
        functionOnBasic(x);//在函数中改变形参的值
        System.out.println("调用函数后x:"+x);//输出x的值

        System.out.println("****************************************************");
        classA a=new classA();//引用数据类型
        System.out.print("原始:a:"+a);//输出a的值,地址,指向其它对象
        System.out.println(";属性:"+a.attribute);//借助a的值来访问对象的属性
        functionOnClassOne(a);//在函数中改变形参的值
        System.out.print("调用函数一后:a:"+a);//输出a的值,地址,指向其它对象,未变
        System.out.println(";属性:"+a.attribute);//借助a的值来访问对象的属性

        System.out.println("****************************************************");
        functionOnClassTwo(a);//在函数中改变形参指向的对象
        System.out.print("调用函数二后:a:"+a);//输出a的值,地址,指向其它对象
        System.out.println(";属性:"+a.attribute);//借助a的值来访问对象的属性,改变
        System.out.println("****************************************************");
        String str=new String("欢迎来看我的blog");
        System.out.println("原来的str:"+str);
        functionOnString(str);
        System.out.println("调用函数后str:"+str);

    }

    public static void functionOnBasic(int number)
    {
        number = -1;
    }
    public static void functionOnClassOne(classA a)
    {
        a=new classA(100);
        System.out.println("改变形参的值,此时形参的值:"+a+";属性为:"+a.attribute);
    }
    public static void functionOnClassTwo(classA a)
    {
        a.attribute=-1;
    }
    public static void functionOnString(String s)
    {
        s="我在函数中被改变了呀";
    }
}
class classA{
    public int attribute;
    public classA(){
        attribute=10;
    }
    public classA(int newNumber){
        attribute=newNumber;
    }
}

b.实验结果:

****************************************************
原来的x:1
调用函数后x:1
****************************************************
原始:a:classA@b4c966a;属性:10
改变形参的值,此时形参的值:classA@2f4d3709;属性为:100
调用函数一后:a:classA@b4c966a;属性:10
****************************************************
调用函数二后:a:classA@b4c966a;属性:-1
****************************************************
原来的str:欢迎来看我的blog
调用函数后str:欢迎来看我的blog

Process finished with exit code 0

c.结果分析

  • 测试内置数据类型,在函数内修改形参的值:

                形参的改变不影响实参的值,实参的值未变:1

  • 测试引用数据类型,在函数内修改形参的值: 

                形参的改变不影响实参的值,实参的值未变:classA@b4c966a,对象的属性未变:10

  • 测试引用数据类型,在函数内修改形参指向的对象

                形参的改变不影响实参的值,实参的值未变:classA@b4c966a,对象的属性改变:-1

  • 测试String类

                形参的改变不影响实参的值,实参的值未变:“欢迎来看我的blog”

5.总结结论

  • Java是值传递
  • 在函数内修改形参的值,不会导致实参的值发生改变
  • 若函数的参数类型是引用数据类型,则通过形参修改对象的值会导致实参指向的对象发生变化
  • String类表现得像内置数据类型,则通过形参修改对象的值不会导致实参指向的对象发生变化

    若有解释有误的地方,欢迎大家指正批评,本人也是个萌新(^ρ^)/


文章来源:https://blog.csdn.net/c335000/article/details/144153311
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云