【问题标题】:How to Increment a class Integer references value in java from another methodjava - 如何从另一个方法增加一个类整数引用Java中的值
【发布时间】:2011-01-13 14:46:57
【问题描述】:
package myintergertest;

/**
 *
 * @author Engineering
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        //this one does not increment 
        Integer n = new Integer(0);
        System.out.println("n=" + n);
        Increment(n);
        System.out.println("n=" + n);
        Increment(n);
        System.out.println("n=" + n);
        Increment(n);
        System.out.println("n=" + n);
        Increment(n);

        //this one will increment
        MyIntegerObj myInt = new MyIntegerObj(1);
        Increment(myInt);
        System.out.println("myint = " + myInt.get());
        Increment(myInt);
        System.out.println("myint = " + myInt.get());
        Increment(myInt);
        System.out.println("myint = " + myInt.get());

    }

    public static void Increment(Integer n) {
        //NO.  this doesn't work because a new reference is being assigned
        //and references are passed by value in java
        n++;
    }

    public static void Increment(MyIntegerObj n) {
        //this works because we're still operating on the same object
        //no new reference was assigned to n here.
        n.plusplus();   //I didn't know how to implement a ++ operator...
    }
}

所有这些的结果都是 n=0。整数 n 是一个对象,因此通过引用传递,那么为什么增量没有反映在调用方方法(main)中?我预计输出为 n=0 n=1 n=2 等...

更新: 请注意,我更新了上面的代码示例。如果我理解正确,Jon Skeet 回答了为什么 myInt 会增加而 n 不会增加的问题。这是因为 n 正在获取 Increment 方法中分配的新引用。但是 myInt 没有被分配一个新的引用,因为它正在调用一个成员函数。

这听起来像我理解正确吗哈哈?

【问题讨论】:

    标签: java pass-by-reference


    【解决方案1】:

    不,对象不是通过引用传递的。引用是按值传递的——有很大的不同。 Integer 是不可变类型,因此您无法更改方法内的值。

    您的n++; 声明有效

    n = Integer.valueOf(n.intValue() + 1);
    

    因此,它为 Increment 中的变量 n 分配了不同的值 - 但由于 Java 只有 具有传递值,这不会影响 n 的值在调用方法中。

    编辑:回答您的更新:没错。大概您的“MyIntegerObj”类型是可变的,并在您调用plusplus() 时更改其内部状态。哦,别费心去寻找如何实现一个操作符——Java 不支持用户定义的操作符。

    【讨论】:

    • 你的意思是说'对象是按值传递的 - ...'?
    • 不,他没有。基元和引用按值传递。对象根本不通过;他们住在堆上。
    • 你决定不解释关于通过反射修改Integer 的事情? :-)
    • @Jon Skeet 应该导入哪个 java 包来执行这个算术?
    • @TahirYasin:我不明白你的意思。 Integer 类位于 java.lang...
    【解决方案2】:

    您正在寻找类似于 C++ 的引用或 C# 的 out 参数的东西。 Java(和许多其他语言)不支持这一点。

    这种行为通常是通过将方法从 void 更改为(在这种情况下)int:public static int increment(int n) { return ++n; }

    如果方法已经返回了一些东西,那么你可以创建一个新类,它有两个字段(甚至可以是公共的):原始返回值和 n 的新值。

    或者,您也可以将整数包装在通用 Cell 类中。你只需要编写一次这个 Cell 类:

    public class Cell<T> {
      public Cell(T t) { value = t; }
      public void set(T t) { value = t; }
      public T get() { return value; }
    }
    

    然后,您可以在所有需要更改原语的方法的情况下使用它:

    public static void increment(Cell<Integer> n) {
      n.set(n.get()++);
    }
    
    Cell<Integer> n = new Cell<Integer>(0);
    increment(n);
    increment(n);
    increment(n);
    System.out.println(n.get()); // Output: 3
    

    【讨论】:

      【解决方案3】:

      您可以使用java.util.concurrent.atomic 中的AtomicInteger。它有一个适合您展示的“incrementAndGet”方法。

      【讨论】:

      • 什么?是的,我的意思是它有效,但这并不是一个好主意。它将执行诸如同步处理器缓冲区之类的事情,因为否则它不是原子操作。真的,除非您需要原子性,否则您不应该使用数据类型的原子版本...
      • @Jasper,我无法反驳。它只是我工具箱中的另一个工具。我根据手头的任务进行选择。除非分析器在该特定点指出问题,否则它仍然是一种选择。
      【解决方案4】:

      Integervalue object,这意味着值不能改变。

      请注意,n++ 等同于 n = n + 1。您只是更改了局部变量 n 引用的值,而不是 n 本身的值。

      【讨论】:

        【解决方案5】:

        你不能。 Java 是严格按值传递的。

        http://javadude.com/articles/passbyvalue.htm

        您的选择是将整数包装在一个对象(或数组)中,将其传入并更新,返回一个值,或者使整数成为类/实例变量。

        哪个更好视情况而定。

        【讨论】:

          【解决方案6】:

          正如 Jon Skeet 所提到的,Java 中的所有方法都是按值传递,而不是按引用传递。由于引用类型是按值传递的,所以您在函数体内拥有的是引用的副本——这个副本和原始引用都指向同一个值。

          但是,如果您在函数体内重新分配副本,它将不会影响程序的其余部分,因为该副本将在函数退出时超出范围。

          但请考虑一下,您实际上并不需要通过引用来执行您想做的事情。例如,您不需要增加 Integer 的方法 - 您可以在代码中需要增加它的位置增加它。

          对于更复杂的类型,例如在对象上设置某些属性,您正在使用的对象可能是可变的;在这种情况下,引用的副本就可以正常工作,因为自动取消引用会将您带到您正在调用其设置器的原始对象。

          【讨论】:

            【解决方案7】:

            旁注:以我的拙见,在 Integer 对象上编写 n++ 具有极大的误导性。这依赖于 Java 的一个称为“自动装箱”的功能,它可以自动将原语转换为它们相应的装箱对象(例如 int 到 Integer 或 boolean 到 Boolean),并且不会发出警告。坦率地说,我认为这是一个糟糕的功能。是的,有时它会自动为您进行方便的转换,从而使您的生活变得更简单,但它也可以进行您不打算也没有意识到正在发生的转换,并产生意想不到的副作用。

            无论如何,有两种方法可以完成您显然想要做的事情:

            One:让增量函数返回一个具有更新值的新整数。喜欢:

               public Integer increment(Integer n)
                {
                  Integer nPlus=Integer.valueOf(n.intValue()+1);
                  return nPlus;
                }
            

            然后调用它:

            Integer n=Integer.valueOf(0);
            n=increment(n); // now n==1
            n=increment(n); // now n==2
            

            等等

            二:创建您自己的类,它类似于 Integer 但它是可变的。喜欢:

            class MutableInteger
            {
              int value;
              public MutableInteger(int n)
              {
                value=n;
              }
              public void increment()
              {
                ++value;
              }
              ... whatever other functions you need ...
            }
            

            当然,最大的问题是您几乎必须重新发明 Integer 类。

            【讨论】:

            • 示例 1 完全没用。它只会更新局部变量。该问题询问如何通过method2更新method1中的整数。如果有人在method2中调用increment()方法,它只会更新method2的局部变量。
            • @ManishBansal 我在 10 年前发布了这个帖子,你是第一个指出错误的人。是的,我离开了退货声明。现已修复。
            • 删除了我之前的评论。这将解决作者的问题。谢谢。
            【解决方案8】:

            正如 DerMike 提到的,您可以通过以下方式实现:

            public void doStuff() {
              AtomicInteger i = new AtomicInteger(0);
              increment(i);
              System.out.println(i);
             }
            
              public void increment(AtomicInteger i) {
                i.set(i.get() + 1);
             }
            

            【讨论】:

              【解决方案9】:

              参见 AtomicInteger: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicInteger.html

              您可以使用这个 java.util.concurrent 类实现线程安全。

              【讨论】:

                【解决方案10】:
                public class passByReferenceExample {
                    static void incrementIt(Long b[]){
                        Long c = b[0];
                        c=c+1;
                        b[0]=c;
                
                    }
                    public static void main(String[] args) {
                        Long a[]={1L};  
                
                        System.out.println("Before calling IncrementIt() : " + a[0]);
                        System.out.println();
                        incrementIt(a);
                        System.out.println("after first call to incrementIt() : " + a[0]);
                        incrementIt(a);
                        System.out.println("after second call to incrementIt(): "+ a[0]);
                        incrementIt(a);
                        System.out.println("after third call to incrementIt() : "+ a[0]);
                        incrementIt(a);
                        System.out.println("after fourth  call to incrementIt(): "+ a[0]);    
                    }
                }
                

                输出:

                Before calling IncrementIt() : 1
                
                after first call to incrementIt() : 2
                after second call to incrementIt(): 3
                after third call to incrementIt() : 4
                after fourth  call to incrementIt(): 5
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多