java - 有没有办法保证真正引用的对象对调用者函数没有副作用?

标签 java call-by-value

我是一名最近学习JAVA的学生。
我根据我的 C++ 经验来接触这种语言。

所以我花了将近四天的时间才理解 c++ 和 java 在按值调用或引用方面的差距。

Java 是按值调用的,因为调用者函数将引用类型变量本身传递给被调用者。

当我理解上面这句话时,我突然想到一个问题。
我的问题是...

我了解到按值调用的优点之一是无副作用

在JAVA中,保证引用类型变量本身没有副作用。
但是引用变量引用的真实对象可能会产生副作用
之后返回到调用者函数。

那么有没有办法保证堆内存中的引用对象对调用者函数也没有副作用?

(如果我误解了JAVA机制,请告诉我)

================================
添加示例

class Person{
    String  name;
    int     age;
    Person(String name, int age){
        this.name = name;
        this.age =age;
    }

}


public static void foo(){
    Person p = new Person("haha", 17);

    System.out.println(p.name); // haba

    boo(p);


    System.out.println(p.name); // hoho, but foo() wants original value "haha"

}

public static void boo(Person p){
    p.name = "hoho";

}

我希望 boo() 函数不要修改 p 实例的成员变量(这里的 p.name)。

最佳答案

下面是一个小示例,说明如何传递对象的副本,确保原始对象不被修改。

当我使用复制构造函数时,原始对象的内部状态被保留,但是当我简单地声明 TestRef otherRef = testRef; 时,仅复制引用,这样如果新对象被修改,原作也是如此。

请注意,在本例中,我确实复制了 String 引用,因为字符串是 java 中的不可变类。

public class Main {

    public static class TestRef {
        public String a;
        public int b;

        //Copy constructor
        public TestRef(TestRef other) {
            this(other.a, other.b);
        }

        public TestRef(String a, int b) {
            this.a = a;
            this.b = b;
        }

    }

    public static void main(String[] args) throws IOException, TransformerException {

        TestRef testRef = new TestRef("TestRef", 1);
        //Using copyConstructor to make deep copy of object
        System.out.println(testRef.a);
        TestRef deepCopy = new TestRef(testRef);
        modifyClass(deepCopy);
        System.out.println(testRef.a);
        //Shallow copy
        TestRef otherRef = testRef;
        modifyClass(otherRef);
        System.out.println(testRef.a);      
    }

    public static void modifyClass(TestRef testRef) {
        testRef.a = "newString";
        testRef.b++;
    }
}

输出:

TestRef
TestRef
newString

关于java - 有没有办法保证真正引用的对象对调用者函数没有副作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59782351/

相关文章:

java - 架构 微服务 Jhipster

java - 继承示例解释、编码和方法等?

haskell - lambda 演算的按值调用和按名称调用解释器之间的区别

c++ - 按名称调用/按值调用

Java 与 C++(按引用调用?)

java - 嵌套递归错误

java - Java中IPv6地址的奇怪符号

Java正则表达式用于具有两个子字符串且其间不包含特定子字符串的模式

c - 为什么指针的值还是20?

pass-by-reference - 按引用调用和按值调用结果