【问题标题】:Let a method modify the reference instead of a new object让方法修改引用而不是新对象
【发布时间】:2014-09-18 05:40:18
【问题描述】:

我打赌这个问题已经回答了,但我不知道如何用简单的话解释这个问题以在谷歌上找到一个简单的答案 - 对不起!

这是我的测试代码:

public class test {
public static void increase(Integer i){
    i++;
}

public static void main(String[] args){
    Integer x = new Integer(10);
    increase(x);
    System.out.println(x);
}

}

我有一个整数 x,想通过 void 方法“increase(..)”修改它。 由于 Integer 是一个对象,因此 x 是指向该对象的指针。 我想要“increase(..)”来修改 Integer 本身,所以“i”指的是与“x”相同的对象。但是,如果我查看 print(x)(即“10”),我假设该方法创建了一个内容为“x”的新整数。

希望大家能理解我...

我需要那个做什么?

我正在尝试使用多个线程来总结从 1 到“n”的数字。 我创建了一个“MyThread”类,它获取一个 lowerLimit 和一个 upperLimit 来总结间隔,以及一个“结果”(但作为参考 - 不是新对象),其中添加了间隔的数量。

最好的问候 tak3r07

【问题讨论】:

    标签: java object methods reference


    【解决方案1】:

    有三种方法可以做到这一点。

    public class test {
    public static void increase(AtomicInteger i){
        i.getAndIncrement()
    }
    
    public static void main(String[] args){
        AtomicInteger x = new AtomicInteger(10);
        increase(x);
        System.out.println(x);
    }
    }
    

    或

    public class test {
    public static void increase(int[] i){
        i[0]++;
    }
    
    public static void main(String[] args){
        int[] x = { 10 };
        increase(x);
        System.out.println(x[0]);
    }
    }
    

    或整数

    public class test {
    public static void increase(Integer[] i){
        i[0]++;
    }
    
    public static void main(String[] args){
        Integer[] x = { 10 };
        increase(x);
        System.out.println(x[0]);
    }
    }
    

    出于兴趣,您能解释一下为什么会这样吗?我以为java是严格按值传递的?

    Java 是按值传递的。引用是按值传递的,但是这是浅拷贝而不是深拷贝。即您不能更改引用,但可以更改引用的对象。

    您不能直接使用 Integer 执行此操作,因为它是不可变的,因此您无法更改任何内容。传递对可变对象的引用,您可以更改它。

    【讨论】:

    • +1 彼得。出于兴趣,您能解释一下为什么会这样吗?我以为java是严格按值传递的? (因此,当您将对象传递给方法时,该方法与对象的副本一起使用)。现在很困惑为什么 Integer 不起作用但 int[] 起作用
    【解决方案2】:

    创建一个单独的类来做你想做的事:

    示例代码:

    public class MyInteger {
        int value;
    
        public MyInteger(int value) {
            this.value = value;
        }
    
        public int getValue() {
            return value;
        }
    
        public void setValue(int value) {
            this.value = value;
        }
    
        public void increase() {
            value++;
        }
    
        @Override
        public String toString(){
            return String.valueOf(value);
        }
    
    }
    
    ....
    
    public static void main(String[] args){
    
        MyInteger x = new MyInteger(10);
        x.increase();
        System.out.println(x.getValue());  // print 11
        System.out.println(x);             // print 11
    
    }
    

    【讨论】:

      【解决方案3】:

      Integer 类像 String 和其他原始包装类是不可变的,这意味着它们的值不能改变,所以每次你试图改变它们的值时,你实际上是在创建它们的一个新实例.您可以为此使用AtomicInteger,AtomicLong,AtomicDouble...。

      【讨论】:

      • 感谢您的解释。我想我已经听说过它们是不可变的,但忘记了。我假设不可变类的派生类也是不可变的?
      • @Tak3r07,不可变是最终的,这意味着你不能创建一个扩展它们的类。
      【解决方案4】:

      e++ 形式的表达式是简写

      E old = e;
      e = (E) (old + 1);
      return old;
      

      其中E 是e 的类型。

      也就是说,你的表达式等价于

      i = (Integer) (i + 1);
      

      计算 i + 1,创建(或重用)一个 Integer 对象来保存该值,并将对该对象的引用存储在变量 i 中。原始 Integer 对象没有被修改,调用者仍然引用该原始对象,因此会看到原始值。

      要解决此问题,您可以返回对新 Integer 对象的引用,并要求调用者存储它,或者将引用传递给支持更改值的类的对象。唉,Integer 不是这样的类,因为一旦创建了对象,它的值就不能改变。有关合适课程的示例,请参阅 Peter 和 Braj 的答案。

      【讨论】:

        猜你喜欢
        • 2021-09-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-13
        • 2021-09-05
        • 1970-01-01
        • 2020-01-23
        相关资源
        最近更新 更多