所谓的值传递(pass-by-value)指的是:传递给方法的是参数值的一个copy。Java方法使用的永远是值传递(很多地方说到的“引用传递”其实也可以看做是值传递,概念搞多了反而还不好理解,干脆说死一点,Java就只使用值传递)。
通过例子来看:
public class Test {
public static void change(String s) {
s = "changed";
}
public static void main(String[] args) {
String s = "original";
change(s);
System.out.println(s); // Output: original
}
}
值传递的示意图如下:
由于String是immutable class,即:String对象一旦创建,就不可修改。所以:
String s = "original";
s = "changed";
应该看成:
String s = new String("original");
s = new String("changed");
即s = "changed"并不是把"original"对象修改成"changed",而是新建了一个"changed"对象,而且于此同时"original"对象依然存在。亦即不应该看成下面这种表示:
String s = new String("original");
s.setValue("changed");
正因为String是个不可变类,所以在change()方法中,参数s指向"original",而s的拷贝指向"changed",s的拷贝的行为对s没有影响,所以System.out.println(s)还是打印出"original"。
下面是一个StringBuffer的例子:
public class Test {
public static void change(StringBuffer sb) {
sb.replace(0, sb.length(), "changed");
}
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("original");
change(sb);
System.out.println(sb.toString()); // Output: changed
}
}
sb.replace(0, sb.length(), "changed"),或者更准确地说应该是copyOfSb.replace(0, sb.length(), "changed")并没有创建新的对象,而是修改了原有的对象,所以System.out.println(sb.toString())打印出来的是changed。
题外话:一般说来,String和基本类型都是immutable class,而StringBuffer、Date还有数组都是可变类。
2010-7-6补充:用final来修饰方法的参数可以强制禁止参数的拷贝指向新的对象,例如:
public class Test {
public static void change(final String s) {
s = "changed"; // 非法!!!
}
public static void main(String[] args) {
String s = "original";
change(s);
System.out.println(s);
}
}
这里final就可以禁止copy of String s指向新对象"changed"的行为:
2011.10.23 补充:
对参数来说,可以分三类:(1)基本类型 primitive type;(2)可变类对象reference;(3)不可变类对象reference。(2)(3)的情况上面已经讨论过了,那么基本类型的情况如何呢?
基本类型的情况有一点特殊。基本类型和reference都是在栈上的值,只是reference存的是堆上对象的地址值,而基本类型存的是本身的值。如下图所示:
当 (i,j) 作为参数传入时,j会被原样copy一份,这份copy仍然指向Integer(10);i也会被原样copy一份,值仍然为5。如下图所示:
所以此时在方法里改变 (i,j) 的值,其实对 (i, j) 并没有什么影响:
当方法执行完毕,堆栈内容和方法执行前没有变化。
可以总结一下,java的值传递是在栈上进行的,即将栈上的primitive type或是reference copy一份,再传递给方法,方法实际操作的是这份copy。这份copy能否影响到堆上的值,要看方法具体对copy的操作是啥,如果是setter,那肯定改变了堆置,如果是new,其实不会改变。
2011.10.26 补充:
联系到【== 与 Object.equals() 的区别】,我们是否可以认为:【== 比较的是栈上的两个值是否相等】?
分享到:
相关推荐
### Java基础达内培训笔记知识点总结 #### 一、Java 文件与编辑器 - **编辑器选择**:在Java开发中常用的编辑器包括Eclipse、NetBeans和JBuilder等。 - **源文件创建**: - 源文件扩展名必须为`.java`。 - 公共...
- **解析**:在Java中,创建线程的常见方式之一是通过实现`Runnable`接口并重写`run()`方法,然后将这个对象传递给`Thread`类的构造函数来创建一个新的线程。因此,选项B“实现接口并重写 run()方法”是正确的。 ##...
计算得到`j` 的值为正数 0x0000000F,转换为十进制是15,但题目中提供了错误选项,所以正确答案是D. `?15`。这涉及到Java的整数运算和位操作符。 2. **自动装箱拆箱与对象比较**: 第二部分涉及了Integer、Long和...
- **解析**: 实际上传递给函数的实参值会被复制到形参变量中,这意味着改变形参变量的值不会影响到实参变量。 ### 14. HTML 中插入 JavaScript 代码 - **知识点**: JavaScript 代码可以在 HTML 页面的 `<body>` 或...
Java 中方法参数传递是按值传递,对于对象引用,传递的是对象的引用副本,而不是对象本身。在 `ObParm` 类的例子中,`amethod` 和 `another` 方法展示了这一点。尽管方法内部可以改变引用的指向,但方法调用结束后...
8. **对象与方法**:传递对象给方法时,Java传递的是对象的引用。在给定的代码中,虽然在`add3`方法内部修改了对象的值,但原始对象的引用并未改变,所以`main`方法中的`i`值仍然是0。 9. **数组与索引**:尝试访问...
- 16进制数使用16个数字符号(0-9 和 A-F 或 a-f),其中A-F分别代表10-15。 - 通常,在表示16进制数时会在前面加上`0x`或`0X`。 - 选项B“使用16个数字符号”是正确的描述。 #### 异常处理 - **`finally`块**...
4. **掌握方法中参数传递的方式:** 包括值传递和引用传递的区别。 5. **理解类的继承性:** 学会如何创建子类,继承父类的属性和方法。 6. **掌握类的多态性:** 理解多态的概念,学会使用抽象类和接口实现多态。 ...
8. 引用传递:Java中的参数传递是按值传递,对于对象则是按引用传递。在`add3`方法中,虽然修改了`i`的值,但原始的`Integer`对象没有被改变,因此`main`方法中的`i`仍然是0。 9. 数组和索引:尝试访问未初始化的...
5. **十六进制赋值**:将十六进制值赋给`long`变量应以`0x`开头,后面跟上数值,再加`L`表示长整型,因此`long number = 0x345L;`是正确的。 6. **位运算**:`^`是按位异或运算符,6^3的结果是2,因此输出是2,选项...
- **示例**:`deff(x,y=0,z=0): pass` 函数调用 `f(1,,3)` 将会因为缺少必要的参数而报错。 ### 6. 字节编码容量 - **基础知识**:一个字节由8位二进制数组成,可以表示 2^8 种不同的组合。 - **最大值**:一个...
这可能导致一些环境差异,特别是当涉及到多进程编程时,因为`pickle`在多进程间传递对象时会被用到。 在你的案例中,取消勾选“Run with Python Console”后,代码能够正常运行,这可能是因为这个选项改变了代码...
if ((c >= 0x00 && c <= 0x7F) || (c >= 0xC0 && c )) { charCount++; } else if (c >= 0xE0 && c ) { charCount += 2; } else if (c >= 0xF0 && c ) { charCount += 3; } } return str.substring(0, i); }...
代码中的for循环在i从0递增到99时,执行j=j++,但j的初始值和最终值并不会改变,因为j++是先使用j的当前值,然后才进行加1操作。因此,循环结束后j仍然是0,选项A正确。 4. Java集合框架与排序: 为了确保输出结果...
4. 参数 (Parameters): 参数是在方法签名中声明的变量,用于传递值从一个方法到另一个方法。它们也是局部变量,仅在方法内部有效。 Java的命名规则严格且一致,遵循以下准则: - 名称是大小写敏感的,不允许使用...
(4)此题涉及Java中StringBuffer对象的传递。`operate`方法接受两个StringBuffer对象作为参数,但`y`的赋值操作不会改变传递进来的对象`b`,因为`y`在这里是方法内部的一个局部变量。因此,`operate(a, b)`调用后,...
`0xFFFFFFF1` 是一个32位的二进制数,其取反后得到 `0x0000000F`,转换为十进制即为15,因此选项C正确。 第二题考察了对象的相等性判断。在Java中,`==` 运算符比较的是对象的引用,而`.equals()` 方法比较的是对象...
◇ 十六进制整数 以0x或0X开头,如0x123表示十进制数291,-0X12表示十进制数-18。 整型变量: 数据类型 所占位数 数的范围 byte 8 -27~27-1 bhort 16 -215~215-1 int 32 -231~231-1 long 64 -263~263-1 4....
- Java中的参数传递是按值传递的,但对于对象引用,传递的是对象的引用地址,而非对象本身。 - 示例代码展示了方法参数传递时,引用变量`v`的值在方法内部可以改变,但方法调用结束后,`v`依然指向原来的对象。...