java 创建方法并将对象作为参数传递时,它们是被复制还是被引用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5289174/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When creating methods and passing objects as parameters, are they copied or referenced?
提问by Steven
Possible Duplicate:
Is Java pass by reference?
可能的重复:
Java 是按引用传递的吗?
see example below... need java.io library to run...
见下面的例子...需要java.io库来运行...
public class BlankClass extends ConsoleProgram {
public void run() {
while(true) {
setFont("London-24");
String name = readLine("Type a name: ");
fixName(name);
/* I know that the way this is written doesn't make sense and that println(fixName(name))
* is the right way. However, I thought that when objects then the method is using the object
* (in this case a string) and not a copy of it. In other words, it is referenced.
* So if it is referenced why isn't it printing out Steven when I give it STEVEN.
*/
//println(fixName(name); this is removed to show the question.
println(name);
}
}
private String fixName(String name) {
char first = name.charAt(0);
first = Character.toUpperCase(first);
name = name.substring(1);
name = first + name.toLowerCase();
return name;
}
}
回答by Jon Skeet
Java alwayspasses parameters by value - but in the case of classes/objects, the value that's passed is a reference, not an object itself.
Java总是按值传递参数——但在类/对象的情况下,传递的值是引用,而不是对象本身。
What the type involved, the value of the argument expression is copied as the initial value of the parameter. Changes to the parameter variable itself are notseen by the caller, whereas changes to the object that the reference refers to willbe seen.
涉及什么类型,参数表达式的值被复制为参数的初始值。更改参数变量本身是不被调用者看到的,而更改对象的引用指的是将待观察。
For example, using StringBuilder (which is a mutable type):
例如,使用 StringBuilder(这是一个可变类型):
public void foo(StringBuilder builder)
{
builder = new StringBuilder("Change to builder");
}
public void bar(StringBuilder builder)
{
builder.append(" - appended");
}
Now:
现在:
StringBuilder x = new StringBuilder("Original value");
foo(x);
System.out.println(x); // Still prints "Original value"
StringBuilder y = new StringBuilder("Original value 2");
bar(y);
System.out.println(y); // Prints "Original value 2 - appended"
Note that when I say "the value of the argument expression", that is neveran object - it's either a primitive value, or a reference.
请注意,当我说“参数表达式的值”时,它绝不是一个对象——它要么是一个原始值,要么是一个引用。
I like to think of an analogy with houses. Suppose you have a piece of paper (a variable) with directions to a house written on it. You call a method and use that variable as the argument - that creates a new piece of paper (the parameter) with the same directions on. If the method crosses out the original directions and replaces them with some other ones, that doesn't change the firstpiece of paper. On the other hand, if the method follows the directions and then paints the house red, then you wouldsee that change if you followed the directions on the first piece of paper.
我喜欢用房子来做类比。假设你有一张纸(一个变量),上面写着到房子的方向。您调用一个方法并将该变量用作参数 - 这会创建一张具有相同方向的新纸(参数)。如果该方法划掉了原始方向并用其他一些方向替换它们,则不会改变第一张纸。另一方面,如果该方法遵循说明,然后将房子涂成红色,那么如果您遵循第一张纸上的说明,您就会看到这种变化。
EDIT: To explain your original code... no objectsare being copied, but the valueof name
in run
is being copied into fixName
. You're then changing the value of the parameterin fixName
when you write this:
编辑:解释你的原代码...没有对象被复制,但值的name
在run
被复制到fixName
。然后你改变的值参数中fixName
,当你这样写:
name = name.substring(1);
You're changing it again when you write:
当你写的时候你又在改变它:
name = first + name.toLowerCase();
Neither of these have changed the value of name
in the calling code, which is still referring to the original string.
这些都没有改变name
调用代码中的值,它仍然引用原始字符串。
You're then returning the new string reference here:
然后,您将在此处返回新的字符串引用:
return name;
but your calling code is completely ignoring it, because you've just written:
但是您的调用代码完全忽略了它,因为您刚刚编写了:
fixName(name);
One way to demonstrate what's happened is to use the return value in a new variable:
演示发生了什么的一种方法是在新变量中使用返回值:
String fixedName = fixName(name);
Then you could print out name
(which would show the original string) and fixedName
(which would show the new one).
然后您可以打印出name
(将显示原始字符串)和fixedName
(将显示新字符串)。
回答by Max Komarychev
you pass a reference, so you work with the same string, BUT you return another string, because String in java is immutable - every operation (such as subString) produce new string and if you want to perform many operations on string (such as substring, replace etc.) use a StringBuffer or StringBuilder
你传递一个引用,所以你使用相同的字符串,但你返回另一个字符串,因为 java 中的 String 是不可变的 - 每个操作(例如 subString)都会产生新的字符串,如果你想对字符串执行许多操作(例如 substring 、替换等)使用 StringBuffer 或 StringBuilder
回答by Christophe Roussy
This does not really answer your question, but you should avoid assigning parameters (like 'name' in this case), it can be handy at times but it is generally considered a bad practice because it often leads to unreadable and hard to maintain code. In your case the variable is both a parameter and a local variable.
这并不能真正回答您的问题,但您应该避免分配参数(如本例中的“名称”),它有时很方便,但通常被认为是一种不好的做法,因为它通常会导致代码不可读且难以维护。在您的情况下,变量既是参数又是局部变量。
In Eclipse there is a warning you can activate for this in
在 Eclipse 中有一个警告,您可以为此激活
Preferences->Java->Compiler->Errors/Warnings->Code style->Parameter assignment
Preferences->Java->Compiler->Errors/Warnings->Code style->Parameter assignment
I would recommend to set the parameter 'name' final in order to enforce this. Return another String that is based on your 'name' String and name it properly. The goal is that anyone reading your code should be able to quickly understand what is going on by elimination (the function is private, it is static, the parameter is final...). This excludes a lot of side effects. Search for the concept of 'pure functions' on the web. Make the method static so the person reading your code knows that there are no side effects on the instance. Here is the new version:
我建议将参数 'name' final 设置为强制执行此操作。返回另一个基于您的“名称”字符串的字符串并正确命名。目标是任何阅读您代码的人都应该能够通过消除快速了解发生了什么(函数是私有的,它是静态的,参数是最终的......)。这排除了很多副作用。在网上搜索“纯函数”的概念。将方法设为静态,以便阅读代码的人知道对实例没有副作用。这是新版本:
private static String fixName(final String name) {
final char firstCharOfName = Character.toUpperCase(name.charAt(0));
final String fixedName = firstCharOfName + name.substring(1).toLowerCase();
return fixedName;
}