JAVA中字符串和数组做参数传递的情况

JAVA中字符串和数组做参数传递的情况首先明确的一点就是在java中只有值传递!只有值传递!理论依据来自《thinkinjava》。接下来就是具体说明为何java只有值传递。因为java中有基本类型和引用类型两种数据类型,再加上String这个特殊的类型,所以主要从三个方面就行解释。1.基本数据类型先看代码publicclassDemo01{publicvoidchange(inta){System.out.println(“副本a的初始…

大家好,又见面了,我是你们的朋友全栈君。

        首先明确的一点就是在java中只有值传递!只有值传递!理论依据来自《think in java》。接下来就是具体说明为何java只有值传递。
        因为java中有基本类型和引用类型两种数据类型,再加上String这个特殊的类型,所以主要从三个方面就行解释。

1. 基本数据类型

先看代码

public class Demo01 {
    
    public void change(int a) {
        System.out.println("副本a 的初始值" + a);
        a = 20;
        System.out.println("副本a 的新值值" + a);
    }

    public static void main(String[] args) {
        int a = 10;
        Demo01 d = new Demo01();
        d.change(a);
        System.out.println("change方法执行后的值" + a);
    }
}

分析:

        在java中基本数据类型遵循值传递,所以对象d在调用change()方法时,只是将原数据a的副本传给方法中的参数,第一时间原本和副本a的值都是10,在执行到a=20后,副本a的值变成了20。

所以运行结果为:

JAVA中字符串和数组做参数传递的情况

原理参考下图

JAVA中字符串和数组做参数传递的情况

2. 引用数据类型

先看代码

public class Demo02 {

    char[] ch = {'a', 'b', 'c'};

    public void change(char ch[]) {
        System.out.println("方法中ch[0]的初始值:" + ch[0]);
        ch[0] = 'g';
        System.out.println("方法中ch[0]执行后的新值:" + ch[0]);
    }

    public static void main(String[] args) {
        Demo02 d = new Demo02();
        System.out.println("对象d中数组的初始值是:"+d.ch);
        d.change(d.ch);
        System.out.println("对象d中数组的最终值是:"+d.ch);
    }
}

分析:

        在引用类型作为参数进行传递时,也属于值传递,此时传递的是地址值副本,但是这两个地址指向同一个地方。在副本地址没有进行更改指向时,对副本地址指向的数据进行操作会影响到原始数据的值。方法中ch[] 数组和原始ch[]数组指向同一个数据,所以初始阶段ch[0]都指向’a’;接着对副本中的ch[0]进行新的赋值变为‘g’。
所以运行结果为:

JAVA中字符串和数组做参数传递的情况

 原理参考下图

JAVA中字符串和数组做参数传递的情况

3. 字符串的参数传递

先看代码

public class Demo03 {
    public void change(String str2) {
        System.out.println("方法中str2初始值" + str2);
        System.out.println("方法中str2初始hashcode值" + str2.hashCode());
        str2 = "bbb";
        System.out.println("方法中str2赋值后:" + str2);
        System.out.println("方法中str2赋值后hashcode值:" + str2.hashCode());
    }

    public static void main(String[] args) {
        String str1 = new String("aaa");
        System.out.println("原始字符串str1的hashcode值:" + str1.hashCode());
        Demo03 d = new Demo03();
        d.change(str1);
        System.out.println("方法调用后str1的值" + str1);
    }
}

分析:

        字符串是一个特殊的数据类型,它的底层是一个final 型的char[]数组,属于无法更改,所以字符串在作为参数传递时,可以当做一个特殊的数组进行操作,同样的它也是将复制一份原本的对象引用给了副本,此时副本对象的引用和原本对象的引用都指向原始字符串的位置,也就是str2在刚开始初始化时它指向的地址和原对象str1指向的位置一致,即str2的初始hashcode值和原对象str1的hashcode值一样,str2经过str2=“bbb”操作后,由于字符串的不可变性,此时str2会指向一个新的对象引用,即此时str2指向“bbb”的位置。str2的hashcode值会变化,但是原本str1它的对象引用没有发生改变,并且“aaa”也未发生改变,所以str1仍然指向”aaa”。运行结果如下:

JAVA中字符串和数组做参数传递的情况

接下来看一个更具体的字符串例子:

public class Demo04 {

    public static void main(String[] args) {
        StringBuffer s = new StringBuffer("hello");
        StringBuffer s2 = new StringBuffer("hi");
        test(s, s2);
        System.out.println("方法調用后s的值:" + s);
        System.out.println("方法調用后s2的值:" + s2);
    }

    static void test(StringBuffer s3, StringBuffer s4) {
        System.out.println("方法初始化時s3的值" + s3);
        System.out.println("方法初始化時s4的值" + s4);
        s4 = s3;
        s3 = new StringBuffer("new");
        System.out.println("第一步变化后s3的值" + s3);
        System.out.println("第一步变化后s4的值" + s4);
        s3.append("boy");
        s4.append("gril");
        System.out.println("第二步变化后s3的值" + s3);
        System.out.println("第二步变化后s4的值" + s4);

    }
}

这次先看结果:
JAVA中字符串和数组做参数传递的情况

然后进行分析:

在未执行方法之前,字符串s1和s2指向的位置分别是“hello”和“hi”,这个毋容置疑,

(1)接着进入方法内部,方法中参数s3和s4初始化时和上面例子相同,此时它们和s1s2指向同一个位置,或者说s1s2将对象引用副本给了s3s4,此时s3s4的值为“hello”和“hi”

(2)接着执行s4=s3,这个操作就是将s3的对象引用给了s4,此时s4为“hello”;s3=new StringBuffer(”new”);这个操作要注意,此时相当于给了s3一个新的对象引用,s3指向一个字符串为“new”的位置,所以此时s3=“new”,s4=“hello”

(3)然后s3.append(“boy”);s4.append(“gril”);在StringBuffer中的append方法要注意,它的操作不会为s3s4指向一个新的对象引用,是在原来的基础上进行操作,因此操作完之后s3=“newboy”,s4=“hellogril”

(4)此时方法调用完,回头捋一下s3s4在此过程中的对s1s2的影响。
——- A . 首先是s3和s1一样刚开始指向“hello”,接着给s3创建一个新的对象引用“new”,此时s3和s1再无半毛钱关系,s3进行append(boy)后,s3=“newboy”;
——– B . s4刚开始和s2都指向“hi”,接着s3将自己初始值(也就是s1的副本)给了s4,此时s4指向“hello”(这会s4和s1有了关系),s4执行append(grill)操作,因为它和s1指向相同位置,所以它们的共同指向的对象会变化,s4=s1=“hellogrill”。
——- C .然后就清楚了,s2指向的对象“hi”并未变化,s1指向的“hello”在append(“grill”)操作下变成了“hellogril”。

4. 总结

① 当使用基本数据类型作为方法的形参时,在方法体中对形参的修改不会影响到实参的数值

② 当使用引用数据类型作为方法的形参时,若在方法体中修改形参指向的数据内容,会对实参变量的数值产生影响,因为形参变量和实参变量共享同一块堆区;

③当使用引用数据类型作为方法的形参时,若在方法体中改变了形参变量的指向,此时不会对实参变量的数值产生影响,因此形参变量和实参变量分别指向不同的堆区;最后一个例子就是最形象的解释。

④关于字符串做参数,也是看它的参数变量指向是否发生了变化,因为String的底层为final类型的char[]原因,当你在String s = “aaa”还是String s = new String(“aaa”)时,都会为s创建一个新的对象引用。但是调用了append()方法时,是不会指向新的对象,会在原来的指向的对象上发生改变,与它共享的对象引用也会发生变化。

⑤最后重复的是java中没有引用传递,只有值传递,引用类型属于特殊值传递(是将它的地址副本给了参数,但是它与基本数据类型不同,如果地址指向的对象发生了变化,因为共享原因,原始对象也会改变)。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/138691.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • webAR涉及的技术「建议收藏」

    webAR涉及的技术「建议收藏」1.技术体系1.1技术体系整理其中绿色底色的代表Demo中表现出的能力比较成熟,可以直接应用。脑图地址:http://naotu.baidu.com/file/3392a895a90397252

    2022年8月5日
    6
  • 大数据分析应用的机遇与挑战「建议收藏」

    大数据分析应用的机遇与挑战「建议收藏」随着信息技能的发展,互联网家当的进步,计算机数据处理能力的快速增长,电子商务的日新月异及各种社交媒体的传播扩散,各种信息无时无刻不在影响着我们的生活。我们每时每刻都在自觉或者不自觉得与数据打交道,成为数据的记录者与传播者。海量数据的处理,以及如何利用大数据营销,给我们提出了更多的挑战。在这个人人都高喊“大数据时代”的今天,数据似乎被提到一个前所未有的高度。无论是个人还是企业,无论是网络营销还是线…

    2022年5月15日
    38
  • 把AutoEventWireup属性关闭

    把AutoEventWireup属性关闭1、关于AutoEventWireup属性的作用:,自动关联页面的Page_Load、Page_Init事件,好处就是不用再多写委托代码或重载代码了啦,坏处就是性能(听说的)和不直观性(影响菜鸟升级,“没见到事件关联它为什么会执行这段代码呢?”)。2、删除:(1)、在aspx页面一个个将“AutoEventWireup=true”改为“AutoEventWireup=false”了

    2022年5月28日
    32
  • 原生 android 平板,前沿体验 原生Android 4.0系统平板推荐「建议收藏」

    原生 android 平板,前沿体验 原生Android 4.0系统平板推荐「建议收藏」【PConline海选导购】尽管早在2011年10月份,谷歌和三星就共同发布了代号为“冰激凌三明治”的Android4.0系统,但时至今日,搭载原生搭载Android4.0系统的平板电脑并不多见。即使有些厂商号称旗下的平板电脑可以升级到Android4.0系统,真正能够迅速付诸行动、为用户提供官方升级包的产品也寥寥无几。前沿体验原生Android4.0系统平板推荐相对于Android…

    2022年6月19日
    50
  • SplitContainer 控件作用[通俗易懂]

    SplitContainer 控件作用[通俗易懂]原文出处:http://blog.csdn.net/xiaobai1593/article/details/7356973作用:(Splitter的简化)使用 SplitContainer 控件可分隔容器(如 Form)的显示区域,并使用户可以调整已添加到 SplitContainer 面板中的控件的大小。当用户将鼠标指针移到拆分器上时,光标将发生变化,以指示可以调整 SplitC

    2022年7月18日
    17
  • 测试用例设计的八大要素及ANSI/IEEE 829标准和编写示例[通俗易懂]

    测试用例设计的八大要素及ANSI/IEEE 829标准和编写示例[通俗易懂]1、测试用例的八大要素1.用例编号和其他编号一样,测试用例编号是用来唯一识别测试用例的编号,要求具有易识别和易维护性,用户可以很容易根据用例编号获取到相应用例的目的和作用,在系统测试用例中,编号的一般格式为A-B-C-D这几部分的作用分别如下:A:产品或项目类型,如CMS(内容管理系统)、CRM(客户关系管理系统)B:一般用来说明用例的属性,如ST(系统测试)、IT(集成测试)、UT(单元测试)C:测试需求的表示,说明该用例针对的需求点,可包括测试项和测试子项等,如文档管理、客户投诉信息管理

    2022年6月28日
    34

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号