zoukankan      html  css  js  c++  java
  • 字符串是通过“引用”传递的

    这是Java中一个很经典的问题,在stack-overflow上有很多类似的问题,然而很多回答都是错的或者回答不完整;如果你不深入思考的话,会认为这个问题很简单,但是当你深入下去,会发现这个问题很容易让人产生困惑。

    一段有趣且让人困惑的代码

    package simplejava;
    
    public class Q14 {
    
        public static void change(String x) {
            x = "cd";
        }
    
        public static void main(String[] args) {
            String x = new String("ab");
            change(x);
            System.out.println(x);
        }
    
    }

    结果打印:

    ab

    C++版本如下:

    void change(string &x) {
        x = "cd";
    }
    int main(){
        string x = "ab";
        change(x);
        cout << x << endl;
    }

    打印结果:

    cd

    常见有误的理解

    x变量存储了堆中“ab”对象的引用,当x作为一个参数传入到change()方法内部时,仍然指向堆中的“ab”对象,如下所示:

    因为Java是按值传递的,x的值是“ab”对象的引用,当方法change()被调用时,创建了一个新的对象“cd”,然后x指向“cd”对象,如下图所示:

    这看起来像是一个完美的解释,他们很清楚Java总是按值传递的。但是,问题到底出在哪里呢?

    这段代码到底究竟在做什么

    上面的解释有若干处错误,为了更加容易的理解该问题,我们还是先理清下整个过程。

    当字符串对象“ab”被创建的时候,Java分配了对应大小的内存空间,然后对象被赋值给变量x,事实上是x变量存储的是对象的引用,这个引用是“ab”对象在内存中的地址;

    x变量包含了对象的引用,x并不是“ab”对象,而是一个存储了“ab”对象引用(内存地址)的变量。

    Java是按值传递的,当x被传入change()方法的时候,事实上传入的是一个x变量的拷贝。然后在方法change()内部创建了另一个对象“cd”,它有一个不同的引用。真正改变的是这个x变量的拷贝,其值变成了“cd”对象的引用,而不是原始的x变量被改变;

    注:感觉说得有点混乱,我的理解,先说这个参数x,其相当于一个局部变量,当使用该参数的时候,将会分配一个新的存储位置,将实参拷贝到该位置,并将该拷贝值传递给该方法;

    在change()方法内部,执行x = "cd"的时候,这里的x实际上是main方法的x变量的一个拷贝,一开始其存放的是“ab对象”的引用,执行完这段代码后,其值变成“cd”对象的引用,而main方法的x变量并没有改变,存放的仍然是“ab”对象的引用。

    另一错误解释

    这个问题的原因跟字符串的不变形没任何关系,即使将String替换成StringBuilder对象,结果仍然不变,关键点是变量存储的是对象的引用,而不是对象本身;

    解决这个问题的方法

    如果真的想改变这个对象的值,

    首先这个对象是要可改变的,例如StringBuilder。

    其次,我们要保证没有新对象被创建赋值给参数变量,因为Java只能按值传递。

    如下代码:

    public static void main(String[] args) {
        StringBuilder x = new StringBuilder("ab");
        change(x);
        System.out.println(x);
    }
    public static void change(StringBuilder x) {
        x.delete(0, 2).append("cd");
    }

    译文链接:http://www.programcreek.com/2013/09/string-is-passed-by-reference-in-java/

  • 相关阅读:
    Oct 21st-
    ContextLoaderListener 解析
    HTTPS 证书制作及使用
    Spring MVC 源码分析
    思考
    《深入理解java虚拟机》 第七章虚拟机类加载机制
    《深入理解java虚拟机》第六章 类文件结构
    《深入理解java虚拟机》第三章 垃圾收集器与内存分配策略
    《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常
    SSM-1第一章 认识SSM框架和Redis
  • 原文地址:https://www.cnblogs.com/chenpi/p/5494980.html
Copyright © 2011-2022 走看看