一、引入示例
public class StringAsParamOfMethodDemo {
public static void main(String[] args) {
StringAsParamOfMethodDemo sapm = new StringAsParamOfMethodDemo();
sapm.testA();
}
private void testA() {
String originalStr = "original";
System.out.println("=======Test A Begin:=======");
System.out.println("1.The outer String:\n" + originalStr);
simpleChangeString(originalStr);
System.out.println("3.The outer String after inner change:\n" + originalStr);
System.out.println("=======Test A End.=======");
System.out.println();
}
public void simpleChangeString(String original){
original = original + " is changed!";
System.out.println("2.The changed inner String:\n" + original);
}
这段代码的逻辑是这样的:先赋值一个String类型的局部变量,然后把这个变量作为参数送进一个方法中,在这个方法中改变该变量的值。
编译运行之后,发现输出结果是这样的:
=======Test A Begin:=======
1.The outer String:
original
2.The changed inner String:
original is changed!
3.The outer String after inner change:
original
=======Test A End.=======
结果表明在方法内部对String类型的变量的重新赋值操作并没有对这个变量的原型产生任何影响。
好了,这个示例的逻辑和运行结果都展示清楚了,接下来我们来对这个小程序进行分析。在这之前我们先来回顾下Java中所谓的“传值”和“传引用”问题。
二、Java中的“传值”和“传引用”问题
结论是:
在Java中,当基本类型作为参数传入方法时,无论该参数在方法内怎样被改变,外部的变量原型总是不变的,代码类似上面的示例:
int number = 0;
changeNumber(number) {number++}; //改变送进的int变量
System.out.println(number); //这时number依然为0
这就叫做“值传递”,即方法操作的是参数变量(也就是原型变量的一个值的拷贝)改变的也只是原型变量的一个拷贝而已,而非变量本身。所以变量原型并不会随之改变。
但当方法传入的参数为非基本类型时(也就是说是一个对象类型的变量),方法改变参数变量的同时变量原型也会随之改变,代码同样类似上面的示例:
StringBuffer strBuf = new StringBuffer(“original”);
changeStringBuffer(strBuf) {strbuf.apend(“ is changed!”)} //改变送进的StringBuffer变量
System.out.println(strBuf); //这时strBuf的值就变为了original is changed!
这种特性就叫做“引用传递”,也叫做传址,即方法操作参数变量时是拷贝了变量的引用,而后通过引用找到变量(在这里是对象)的真正地址,并对其进行操作。当该方法结束后,方法内部的那个参数变量随之消失。但是要知道这个变量只是对象的一个引用而已,它只是指向了对象所在的真实地址,而非对象本身,所以它的消失并不会带来什么负面影响。回头来看原型变量,原型变量本质上也是那个对象的一个引用(和参数变量是一样一样的),当初对参数变量所指对象的改变就根本就是对原型变量所指对象的改变。所以原型变量所代表的对象就这样被改变了,而且这种改变被保存了下来。
可是String类型在Java语言中属于非基本类型啊!它在方法中的改变为什么没有被保存下来呢!
三、关于String参数传递问题的曲解之一??直接赋值与对象赋值
关于String类型的变量作为参数时怎么会像基本类型变量那样以传值方式传递这个问题,有两种常见解释。
一种解释就是,对String类型的变量赋值时并没有new出对象,而是直接用字符串赋值,所以Java就把这个String类型的变量当作基本类型看待了。即,应该String str = new String(“original”);,而不是String str = “original”;。这是问题所在么?我们来为先前的示例稍微改造下,运行之后看看结果就知道了。改造后的代码如下
private void testB() {
String originalStr = new String("original");
System.out.println("======= Test B Begin =======");
System.out.println("1.The outer String: " + originalStr);
changeNewString(originalStr);
System.out.println("3.The outer String after inner change: " + originalStr);
System.out.println("======= Test B End =======");
System.out.println();
}
public void changeNewString(String original) {
original = new String(original + " is changed!");
System.out.println("2.The changed inner String: " + original);
}
运行结果是:
======= Test B Begin =======
1.The outer String: original
2.The changed inner String: original is changed!
3.The outer String after inner change: original
======= Test B End =======
实践证明,这种说法是错的。
实际上,字符串直接赋值和用new出的对象赋值的区别仅仅在于存储方式不同。
字符串直接赋值时,String类型的变量所引用的值是存储在类的常量池中的。因 为“original”本身是个字符串常量,另一方面String是个不可变类型,所以这个String类型的变量相当于是滴对一个常量的引用。这种情况下,变量的内存空间大小是在编译期就已经确定的。
而new对象的方式是将“original”存储到String对象的内存空间中,而这个存储动作是在运行期进行的。在这种情况下,Java并不是把“original”这个字符串当作常量对待的,因为这时它是作为创建String对象的参数出现的。
所以对String的赋值方式和其参数传值问题并没有直接联系。总之,这种解释并不是正解。
四、关于String参数传递问题的曲解之二??“=”变值与方法变值
这种说法认为:“在Java 中,改变参数的值有两种情况,第一种,使用赋值号”=“直接进行赋值使其改变;第二种,对于某些对象的引用,通过一定途径对其成员数据进行改变,如通过对象的本身的方法。对于第一种情况,其改变不会影响到被传入该参数变量的方法以外的数据,或者直接说源数据。而第二种方法,则相反,会影响到源数据??因为引用指示的对象没有变,对其成员数据进行改变则实质上是改变的该对象。”
还是用老办法,编写demo,做个小试验,代码如下:
private void testB() {
String originalStr = new String("original");
System.out.println("======= Test B Begin =======");
System.out.println("1.The outer String: " + originalStr);
changeNewString(originalStr);
System.out.println("3.The outer String after inner change: " + originalStr);
System.out.println("======= Test B End =======");
System.out.println();
}
public void changeNewString(String original) {
original = new String(original + " is changed!");
System.out.println("2.The changed inner String: " + original);
}
结果如下:
=========Test C Begin=========
1.The outer String: original
2.The changed inner String: original is changed!
3.The outer String after inner change: original
=========Test C End=========
这证明了问题并不是出在这,又一个解释在实践论据下夭折了。
那到底是什么原因导致了这种状况呢?
五、String参数传递问题的症结所在
public String(String original) {
int size = original.count;
char[] originalValue = original.value;
char[] v;
if (originalValue.length > size) {
// The array representing the String is bigger than the new
// String itself. Perhaps this constructor is being called
// in order to trim the baggage, so make a copy of the array.
int off = original.offset;
v = Arrays.copyOfRange(originalValue, off, off+size);
} else {
// The array representing the String is the same
// size as the String, so no point in making a copy.
v = originalValue;
}
this.offset = 0;
this.count = size;
this.value = v;
}
也许你注意到了里面的char[],这说明对String的存储实际上通过char[]来实现的。怎么样?其实就是一层窗户纸。不知道大家还记不记得在Java API中定义的那些基本类型的包装类。比如Integer是int包装类、Float是float的包装类等等。对这些包装类的值操作实际上都是通过对其对应的基本类型操作而实现的。是不是有所感悟了?对,String就相当于是char[]的包装类。包装类的特质之一就是在对其值进行操作时会体现出其对应的基本类型的性质。在参数传递时,包装类就是如此体现的。所以,对于String在这种情况下的展现结果的解释就自然而然得出了。同样的,Integer、Float等这些包装类和String在这种情况下的表现是相同的。
Integer例子如下:
private void testD() {
Integer originalInt = new Integer(123);
System.out.println("=========Test D Begin=========");
System.out.println("1.The outer Integer: " + originalInt);
changeIntWithMethod(originalInt);
System.out.println("3.The outer Integer after inner change: " + originalInt);
System.out.println("=========Test D End=========");
System.out.println();
}
private static void changeIntWithMethod(Integer original) {
original += 456;
System.out.println("2.The changed inner Integer: " + original);
}
结果为:
=========Test D Begin=========
1.The outer Integer: 123
2.The changed inner Integer: 579
3.The outer Integer after inner change: 123
=========Test D End=========
分享到:
相关推荐
本文将深入探讨Java中的引用类型及其如何影响方法参数的传递机制。通过具体实例,我们将揭示值类型与引用类型之间的差异,并解释在实际编程过程中可能遇到的一些常见困惑。 #### 二、Java的数据类型 Java语言支持两...
本文旨在深入解析Java语言中的参数传递机制。作为一门广泛使用的编程语言,Java提供了多种处理数据的方法,其中参数传递是函数(方法)间数据交互的基础。本文将重点讨论Java中方法调用时的基本类型和引用类型参数...
在 Axis1.4 中传递复杂类型数组参数,涉及到的是 Web 服务中的数据绑定和消息处理。Axis 是一个开源的 SOAP 库,它允许开发者创建、部署和使用 Web 服务。在处理复杂类型数组时,ArrayMapping 是 Axis 中的一个关键...
通过对Java中参数传递方式的学习,我们可以更加熟练地掌握如何在方法间传递数据,这对于编写高效且易于维护的代码至关重要。此外,理解不同类型的参数传递方式也有助于避免一些常见的错误和陷阱,提高代码的质量和...
在方法调用中,`String`类型的参数是按值传递(实际传递的是对象的引用),而数组也是按引用传递,但数组本身是可以修改的,只要不改变数组的引用,就可以改变数组的内容。理解这些特性对于编写高效的Java代码至关...
在Java编程中,String对象和Byte类型的转换是常见的操作,特别是在网络编程中,因为网络通信通常涉及字节流的处理。下面将详细讲解Java中如何进行这两种类型之间的转换,并探讨其在网络编程中的应用。 首先,让我们...
Java中,当涉及到基本类型(如`int`, `double`等)的参数传递时,采用的是传值的方式。这意味着当一个基本类型的变量作为参数传递给方法时,实际上是传递了一个副本,而不是原始值本身。因此,即使在方法内部改变了...
综上所述,在Java中,对于基本数据类型的参数传递实际上是按值传递,而对于对象类型的参数传递则是按引用传递的一种特殊形式——传递的是对象引用的副本,但由于这些副本指向同一个对象,因此对对象的修改会影响到...
Java 参数传递机制是编程中的重要概念,尤其是在Java中,它涉及到“值传递”和“引用传递”的理解。这里我们将深入探讨这两个概念,并结合给定的示例代码进行解析。 首先,我们看“值传递”。在Java中,基本类型...
1. **直接传递数组:** 在Java中,当我们想要将一个数组作为参数传递给某个方法时,只需要在方法的参数列表中指定数组类型即可。 ```java public void someMethod(int[] array) { // 方法体 } ``` 上述代码...
当前端使用 jQuery 向后台传递数组类型的参数时,Java 后台尝试直接通过 `List` 类型来接收这些参数,却发现无法取到任何数据。例如: **前端代码示例**: ```javascript $.ajax({ url: "xxxx", data: { areaList...
Java 参数传递机制详解 Java 中的参数传递机制是一个经久不息的讨论...Java 参数传递机制详解,揭开了 Java 中的参数传递机制的奥秘,详细分析了基本类型和对象作为参数传递的机制,并揭开了对象作为参数传递的迷惑。
### JNI中C和Java参数传递详解 #### 一、引言 Java Native Interface (JNI) 是Java平台标准的一部分,用于让Java代码与其他语言写的代码进行交互。本文将深入探讨在JNI环境中,C/C++和Java之间如何进行参数传递,...
根据题目要求,我们将详细解析如何使用Java Applet来接收HTML文件中的参数,并计算矩形的面积与周长,最后将结果展示在Applet窗口中。 ### 一、Java Applet简介 Java Applet是一种可以嵌入到网页中的小型Java应用...
在Java编程语言中,函数参数的传递方式有两种:值传递和引用传递。理解这两种机制对于编写高效、无误的代码至关重要。以下是对这两种传递方式的详细解析。 首先,值传递是指函数调用时,实际参数的值被复制一份传给...
今天,我们将讨论如何在 Lotus Domino Java 代理中获取传递值 JSON。 代理程序的作用 在 Lotus Domino 服务器上,代理程序可以用来处理用户请求,并返回相应的数据。代理程序可以用 Java 语言编写,具有很高的灵活...
3. **类型不匹配**:Web服务的接口定义与实际传递的参数类型不一致可能导致问题。检查服务接口定义(WSDL文件)与客户端调用的参数类型是否匹配。 4. **配置问题**:Xfire的配置文件(如xfire-config.xml)可能没有...
### Java参数的传递与返回值 #### 一、Java参数传递的基本概念 在Java中,方法(或称为函数)可以通过参数来接收外部的数据,并且能够返回处理后的结果。参数的传递方式主要有两种:值传递(Pass-by-value)和引用...
总之,Java调用shell脚本向DataX传递参数,尤其是在where条件中包含特殊字符时,需要关注字符串转义、shell命令构建以及安全问题。同时,合理设计和使用配置文件能有效提高代码的灵活性和可维护性。
在Java中,这通常是通过将字符串参数直接传递给服务端方法来实现。然后,服务端代码将接收到的JSON字符串转换为JSON对象,以便从中提取所需的数据。 2. 使用诸如net.sf.json JSONObject类(一个流行的Java库,用于...