我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。
什么是解释?
我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。
什么是解释?
当前回答
经过全面的讨论,我认为现在是时候将所有严重的结果聚集在一起。
/**
*
* @author Sam Ginrich
*
* All Rights Reserved!
*
*/
public class JavaIsPassByValue
{
static class SomeClass
{
int someValue;
public SomeClass(int someValue)
{
this.someValue = someValue;
}
}
static void passReferenceByValue(SomeClass someObject)
{
if (someObject == null)
{
throw new NullPointerException(
"This Object Reference was passed by Value,\r\n that's why you don't get a value from it.");
}
someObject.someValue = 49;
}
public static void main(String[] args)
{
SomeClass someObject = new SomeClass(27);
System.out.println("Here is the original value: " + someObject.someValue);
passReferenceByValue(someObject);
System.out.println(
"\nAs ´Java is pass by value´,\r\n everything without exception is passed by value\r\n and so an object's attribute cannot change: "
+ someObject.someValue);
System.out.println();
passReferenceByValue(null);
}
) )
从输出中可以很容易地看到,在Java中,一切都通过价值,如此简单!
Here is the original value: 27
As ´Java is pass by value´,
everything without exception is passed by value
and so an object´s attribute cannot change: 49
'Exception in thread "main" java.lang.NullPointerException: This Object Reference was passed by value,
that´s why you don´t get a value from it.
at JavaIsPassByValue.passReferenceByValue(JavaIsPassByValue.java:26)
at JavaIsPassByValue.main(JavaIsPassByValue.java:43)
其他回答
数据通过参数在函数之间共享,现在有两种方式通过参数:
通过参数 : 呼叫器和呼叫器使用相同的变量为参数. 通过值 : 呼叫器和呼叫器有两个独立的变量与相同的值。
Java 使用 Pass by Value
在传输原始数据时,它复制原始数据类型的值;在传输对象时,它复制对象的地址,并转移到转换方法变量。
Java 在存储变量中遵循以下规则:
原始和对象参考等本地变量在 Stack 记忆中创建,对象在 Heap 记忆中创建。
使用原始数据类型的例子:
public class PassByValuePrimitive {
public static void main(String[] args) {
int i=5;
System.out.println(i); //prints 5
change(i);
System.out.println(i); //prints 5
}
private static void change(int i) {
System.out.println(i); //prints 5
i=10;
System.out.println(i); //prints 10
}
}
使用对象的例子:
public class PassByValueObject {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("prem");
list.add("raj");
new PassByValueObject().change(list);
System.out.println(list); // prints [prem, raj, ram]
}
private void change(List list) {
System.out.println(list.get(0)); // prem
list.add("ram");
list=null;
System.out.println(list.add("bheem")); //gets NullPointerException
}
}
Java 只通过值,这是一个很简单的例子来验证这一点。
public void test() {
MyClass obj = null;
init(obj);
//After calling init method, obj still points to null
//this is because obj is passed as value and not as reference.
}
private void init(MyClass objVar) {
objVar = new MyClass();
}
Java 总是通过价值,没有例外,永远。
因此,怎样才能让任何人完全困惑,相信Java是通过参考,或者认为他们有一个Java作为通过参考的例子?关键点是Java从来没有提供直接访问对象本身的价值,在任何情况下。
因此,当呼叫一种方法时
对于原始论点(int、long等)而言,值的过渡是原始的实际价值(例如,3)。
所以,如果你有DoSomething(foo)和公共空白DoSomething(Foo foo) {.. } 两个 Foos 有复制的参考,指向相同的对象。
当然,通过值对一个对象的参考看起来非常相似(并且在实践中不可分辨的)通过对象的参考。
很难理解,但Java总是复制值 - 点是,通常值是参考。
在我所知道的范围内,Java只知道值的呼叫,这意味着对于原始数据类型,您将使用复印件工作,对于对象,您将使用对象的参考复印件工作。
public static void swap(StringBuffer s1, StringBuffer s2) {
StringBuffer temp = s1;
s1 = s2;
s2 = temp;
}
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer("Hello");
StringBuffer s2 = new StringBuffer("World");
swap(s1, s2);
System.out.println(s1);
System.out.println(s2);
}
这将人口Hello World而不是World Hello,因为在交换函数中,您使用复印件,这些复印件不会对主要的参考产生影响。
public static void appendWorld(StringBuffer s1) {
s1.append(" World");
}
public static void main(String[] args) {
StringBuffer s = new StringBuffer("Hello");
appendWorld(s);
System.out.println(s);
}
如果您将 StringBuffer 更改为 String,它只会产生 Hello 因为 String 是不可变的。
public static void appendWorld(String s){
s = s+" World";
}
public static void main(String[] args) {
String s = new String("Hello");
appendWorld(s);
System.out.println(s);
}
但是,你可以为 String 做一个插槽,这将使它能够与 Strings 一起使用:
class StringWrapper {
public String value;
public StringWrapper(String value) {
this.value = value;
}
}
public static void appendWorld(StringWrapper s){
s.value = s.value +" World";
}
public static void main(String[] args) {
StringWrapper s = new StringWrapper("Hello");
appendWorld(s);
System.out.println(s.value);
}
编辑:我认为这也是使用 StringBuffer 的理由,当涉及到“添加”两个线条时,因为你可以修改原始对象,你不能用像 String 这样的不可变的对象。