在java中传递给方法的对象在原始副本上工作

在java中传递给方法的对象在原始副本上工作,java,object,reference,biginteger,Java,Object,Reference,Biginteger,我有一个带有一个字段的Sample类,我正在做以下事情: 以此类的对象作为参数调用方法 在此对象上执行一些操作 原来的对象毕竟变了 我用biginger类对象做同样的事情,但它的工作方式不同。为什么会这样 我的班级: public class Sample { private int number; public int getNumber(){ return number; } public void setNumber(int number

我有一个带有一个字段的
Sample
类,我正在做以下事情:

  • 以此类的对象作为参数调用方法
  • 在此对象上执行一些操作
  • 原来的对象毕竟变了
  • 我用
    biginger
    类对象做同样的事情,但它的工作方式不同。为什么会这样

    我的班级:

    public class Sample {
        private int number;
    
        public int getNumber(){
            return number;
        }
    
        public void setNumber(int number){
            this.number = number;
        }
    
        public Sample add(int number){
            this.number += number;
            return this;
        }
    }
    
    调用:

    public class Main {
    
        public static void main(String[] args) {
            Main m = new Main();
            BigInteger b1 = new BigInteger("5");
            Sample s1 = new Sample();
            s1.setNumber(3);
            System.out.println(s1.getNumber());
            Sample s2 = m.checkSample(s1);
            BigInteger b2 = m.checkBig(b1);
            System.out.println(s1.getNumber()+" "+s2.getNumber());
            System.out.println(b1.toString()+" "+b2.toString());
    
    
        }
        public Sample checkSample(Sample k){
            k = k.add(5);
            return k;
        }
        public BigInteger checkBig(BigInteger big){
            big = big.add(new BigInteger("2"));
            return big;
        }
    }
    
    输出:

    3
    8 8
    5 7
    

    对于
    biginger
    ,您没有做同样的事情-您正在调用
    add
    方法,该方法返回对新
    biginger
    的引用,并将该值赋回到
    big

    您的
    示例.add
    方法改为更改现有对象:

    public Sample add(int number){
        this.number += number;
        return this;
    }
    
    如果将其更改为返回对新对象的引用,则其行为类似于
    biginger

    public Sample add(int number){
        Sample sample = new Sample();
        sample.setNumber(sample.number + number);
        return sample;
    }
    
    但是,与
    biginger
    不同,您的
    Sample
    类目前基本上是可变的。
    biginger
    上的任何操作都不会更改现有对象的状态;相反,它们都会创建新对象。如果您想在
    示例
    中复制该行为,可以这样编写:

    public final class Sample {
        private final int number;
    
        public Sample(int number) {
            this.number = number;
        }
    
        public int getNumber(){
            return number;
        }
    
        public Sample add(int number){
            return new Sample(this.number + number);
        }
    }
    
    重要的是要理解,在Java中永远不会传递对象——只传递用于导航到对象的引用。例如:

    StringBuilder a = new StringBuilder();
    StringBuilder b = a;
    b.append("hello");
    System.out.println(a); // Prints hello
    

    这里有一个
    StringBuilder
    对象,但两个变量(
    a
    b
    )都有引用同一对象的值。通过一个变量所做的任何更改仍然可以通过另一个变量看到。(有关详细信息,请参阅。)

    BigInteger是不可变的,每次都返回一个新对象

    示例类是可变的,当您更改它时,它只保留一个副本/值