我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。
什么是解释?
我一直以为Java使用pass-by-reference. 但是,我读了一篇博客文章,声称Java使用pass-by-value. 我不认为我明白作者所做的区别。
什么是解释?
当前回答
只需显示对比,请比较以下 C++ 和 Java 剪辑:
在 C++ 中: 注意: 坏代码 - 记忆泄漏! 但它证明了这一点。
void cppMethod(int val, int &ref, Dog obj, Dog &objRef, Dog *objPtr, Dog *&objPtrRef)
{
val = 7; // Modifies the copy
ref = 7; // Modifies the original variable
obj.SetName("obj"); // Modifies the copy of Dog passed
objRef.SetName("objRef"); // Modifies the original Dog passed
objPtr->SetName("objPtr"); // Modifies the original Dog pointed to
// by the copy of the pointer passed.
objPtr = new Dog("newObjPtr"); // Modifies the copy of the pointer,
// leaving the original object alone.
objPtrRef->SetName("objRefPtr"); // Modifies the original Dog pointed to
// by the original pointer passed.
objPtrRef = new Dog("newObjPtrRef"); // Modifies the original pointer passed
}
int main()
{
int a = 0;
int b = 0;
Dog d0 = Dog("d0");
Dog d1 = Dog("d1");
Dog *d2 = new Dog("d2");
Dog *d3 = new Dog("d3");
cppMethod(a, b, d0, d1, d2, d3);
// a is still set to 0
// b is now set to 7
// d0 still have name "d0"
// d1 now has name "objRef"
// d2 now has name "objPtr"
// d3 now has name "newObjPtrRef"
}
在Java,
public static void javaMethod(int val, Dog objPtr)
{
val = 7; // Modifies the copy
objPtr.SetName("objPtr") // Modifies the original Dog pointed to
// by the copy of the pointer passed.
objPtr = new Dog("newObjPtr"); // Modifies the copy of the pointer,
// leaving the original object alone.
}
public static void main()
{
int a = 0;
Dog d0 = new Dog("d0");
javaMethod(a, d0);
// a is still set to 0
// d0 now has name "objPtr"
}
Java 只有兩種通過: 根據內置類型的價值,並根據對象類型的指標的價值。
其他回答
public void foo(Object param)
{
// some code in foo...
}
public void bar()
{
Object obj = new Object();
foo(obj);
}
它是相同的......
public void bar()
{
Object obj = new Object();
Object param = obj;
// some code in foo...
}
不要考虑在这个讨论中不相关的站点。
你会遇到的最常见的运营商之一是简单的任务运营商“="......它将其右上的值归分为其左上的运营商: int cadence = 0; int speed = 0; int gear = 1; 这个运营商也可以用于对象归分对象参考。
很明显,这个运营商如何以两种不同的方式行动:分配值和分配参考;最后,当它是一个对象......第一,当它不是一个对象,即当它是一个原始的。
真相在代码中,让我们尝试一下:
public class AssignmentEvaluation
{
static public class MyInteger
{
public int value = 0;
}
static public void main(String[] args)
{
System.out.println("Assignment operator evaluation using two MyInteger objects named height and width\n");
MyInteger height = new MyInteger();
MyInteger width = new MyInteger();
System.out.println("[1] Assign distinct integers to height and width values");
height.value = 9;
width.value = 1;
System.out.println("-> height is " + height.value + " and width is " + width.value + ", we are different things! \n");
System.out.println("[2] Assign to height's value the width's value");
height.value = width.value;
System.out.println("-> height is " + height.value + " and width is " + width.value + ", are we the same thing now? \n");
System.out.println("[3] Assign to height's value an integer other than width's value");
height.value = 9;
System.out.println("-> height is " + height.value + " and width is " + width.value + ", we are different things yet! \n");
System.out.println("[4] Assign to height the width object");
height = width;
System.out.println("-> height is " + height.value + " and width is " + width.value + ", are we the same thing now? \n");
System.out.println("[5] Assign to height's value an integer other than width's value");
height.value = 9;
System.out.println("-> height is " + height.value + " and width is " + width.value + ", we are the same thing now! \n");
System.out.println("[6] Assign to height a new MyInteger and an integer other than width's value");
height = new MyInteger();
height.value = 1;
System.out.println("-> height is " + height.value + " and width is " + width.value + ", we are different things again! \n");
}
}
这就是我跑步的结果:
Assignment operator evaluation using two MyInteger objects named height and width [1] Assign distinct integers to height and width values -> height is 9 and width is 1, we are different things! [2] Assign to height's value the width's value -> height is 1 and width is 1, are we the same thing now? [3] Assign to height's value an integer other than width's value -> height is 9 and width is 1, we are different things yet! [4] Assign to height the width object -> height is 1 and width is 1, are we the same thing now? [5] Assign to height's value an integer other than width's value -> height is 9 and width is 9, we are the same thing now! [6] Assign to height a new MyInteger and an integer other than width's value -> height is 1 and width is 9, we are different things again!
我们不能那么确定,因为在 [6] 对象是相同的,然后我们将一个新的对象归分给其中一个,然后,对象有不同的价值! 他们现在如何区分,如果他们是相同的? 他们应该在这里也是相同的!!!
此操作员也可以用于对象分配对象参考。
Java 是严格通过价值的
在Java中,当我们做同样的事情时,我们会用手<unk>做同样的事情;因为它们不被称为指标变量(如上所述),即使我们通过参考,我们不能通过参考,因为我们不用指标变量在Java中收集。
我认为这个简单的解释可以帮助你理解,因为我想在我正在争论这一点时理解这一点。
当您将原始数据传输到函数呼叫时,其内容将复制到函数的论点,当您传输一个对象时,其参考将复制到函数的论点。
考虑到这个简单的例子,线条是Java的对象,当你改变一个线条的内容时,参考变量现在将指向一些新的参考,因为线条对象在Java中是不可变的。
String name="Mehrose"; // name referencing to 100
ChangeContenet(String name){
name="Michael"; // refernce has changed to 1001
}
System.out.print(name); //displays Mehrose
很简单,因为正如我提到的那样,您不允许在呼叫函数中更改复制的参考,但问题在于当您通过 String/Object 序列时,该序列。
String names[]={"Mehrose","Michael"};
changeContent(String[] names){
names[0]="Rose";
names[1]="Janet"
}
System.out.println(Arrays.toString(names)); //displays [Rose,Janet]
你不能这样做
Student student1= new Student("Mehrose");
changeContent(Student Obj){
obj= new Student("Michael") //invalid
obj.setName("Michael") //valid
}
数据通过参数在函数之间共享,现在有两种方式通过参数:
通过参数 : 呼叫器和呼叫器使用相同的变量为参数. 通过值 : 呼叫器和呼叫器有两个独立的变量与相同的值。
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,当然,毫无疑问,是“通过价值”。 此外,由于Java是(主要)对象导向和对象与参考工作,它很容易被困惑,并认为它是“通过参考”
但要测试它是否真的通过值或通过参考,你可以使用原始类型和参考:
@Test
public void sampleTest(){
int i = 5;
incrementBy100(i);
System.out.println("passed ==> "+ i);
Integer j = new Integer(5);
incrementBy100(j);
System.out.println("passed ==> "+ j);
}
/**
* @param i
*/
private void incrementBy100(int i) {
i += 100;
System.out.println("incremented = "+ i);
}
产量是:
incremented = 105
passed ==> 5
incremented = 105
passed ==> 5
因此,在两种情况下,任何在方法中发生的事情都不会改变真正的对象,因为对象的价值已经过去了,而不是对象本身的参考。
但是,当你将自定义对象转移到一种方法,而一种方法并改变它时,它也会改变真正的对象,因为即使你通过了对象,你也将其参考作为一种价值转移到一种方法。
@Test
public void sampleTest2(){
Person person = new Person(24, "John");
System.out.println(person);
alterPerson(person);
System.out.println(person);
}
/**
* @param person
*/
private void alterPerson(Person person) {
person.setAge(45);
Person altered = person;
altered.setName("Tom");
}
private static class Person{
private int age;
private String name;
public Person(int age, String name) {
this.age=age;
this.name =name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Person [age=");
builder.append(age);
builder.append(", name=");
builder.append(name);
builder.append("]");
return builder.toString();
}
}
在这种情况下,产量是:
Person [age=24, name=John]
Person [age=45, name=Tom]