如何从另一个方法在java中增加类整数引用值

如何从另一个方法在java中增加类整数引用值,java,pass-by-reference,Java,Pass By Reference,所有这些的结果都是n=0。整数n是一个对象,因此通过引用传递,那么为什么增量没有反映回调用方方法(main)中呢?我期望输出为n=0 n=1 n=2等 更新: 注意,我更新了上面的代码示例。如果我理解正确的话,Jon Skeet回答了为什么myInt会增加而n不会增加的问题。这是因为n正在获取增量方法中分配的新引用。但是myInt不会被分配一个新的引用,因为它正在调用一个成员函数 这听起来像是我正确理解了lol吗?不,对象不是通过引用传递的。引用是按值传递的,这有很大的区别Integer是不可变

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

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


这听起来像是我正确理解了lol吗?

不,对象不是通过引用传递的。引用是按值传递的,这有很大的区别
Integer
是不可变的类型,因此不能在方法中更改值

你的
n++语句是有效的

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...
    }
}
因此,这为
Increment
中的变量
n
分配了一个不同的值-但是由于Java只有pass-by值,这不会影响调用方法中
n
的值


编辑:回答你的更新:没错。假设您的“MyIntegerObj”类型是可变的,并且在调用
plusplus()
时会更改其内部状态。哦,不要到处寻找如何实现操作符——Java不支持用户定义的操作符。

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

这种类型的行为通常是通过将方法从void更改为int:
publicstaticintincrement(intn){return++n;}

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

或者,也可以将整数包装在泛型单元格类中。您只需编写此单元类一次:

n = Integer.valueOf(n.intValue() + 1);
公共类单元格{
公共单元(T T){value=T;}
公共无效集(T){value=T;}
public T get(){return value;}
}
然后,您可以在希望使用方法更改基元的所有情况下使用它:

public class Cell<T> {
  public Cell(T t) { value = t; }
  public void set(T t) { value = t; }
  public T get() { return value; }
}
公共静态无效增量(单元n){
n、 set(n.get()+);
}
单元n=新单元(0);
增量(n);
增量(n);
增量(n);
System.out.println(n.get());//产出:3

您可以使用
java.util.concurrent.atomic
中的
原子整数。它有一个“incrementAndGet”方法,适用于您的showcase。

Integer
是一个整数,这意味着它的值不能更改


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

您不能。Java严格按值传递

您的选择是将整数包装在对象(或数组)中,传入并更新该整数,返回值,或将整数设置为类/实例变量


哪个更好取决于具体情况。

正如Jon Skeet提到的,Java中的所有方法都是按值传递的,而不是按引用传递的。由于引用类型是按值传递的,所以函数体中的引用是引用的副本-此副本和原始引用都指向相同的值

但是,如果在函数体内部重新分配副本,则不会对程序的其余部分产生影响,因为当函数退出时,副本将超出范围

<>但是考虑一下,你并不真的需要通过参考来做你想做的事情。例如,不需要方法来递增
整数
——只需在代码中需要递增的点处递增即可


对于更复杂的类型,如在对象上设置某些属性,您正在使用的对象可能是可变的;在这种情况下,引用的副本工作得很好,因为自动取消引用将使您找到要调用其setter的原始对象。

旁注:在我看来,在整数对象上写入n++是非常容易误导的。这依赖于Java的一个称为“自动装箱”的功能,在该功能中,它会自动且无警告地将原语转换为相应的装箱对象,如int到Integer或boolean到boolean。坦率地说,我认为这是一个糟糕的特性。是的,有时它会自动为你做一个方便的转换,从而使你的生活变得更简单,但它也可以做一些你不打算也没有意识到正在发生的转换,产生意想不到的副作用

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

第一:让增量函数返回一个新的整数和更新后的值。比如:

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
然后用以下词语来称呼它:

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

第二:创建自己的类,该类类似于Integer,但它是可变的。比如:

Integer n=Integer.valueOf(0);
n=increment(n); // now n==1
n=increment(n); // now n==2
当然,最大的问题是您必须重新发明Integer类。

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

class MutableInteger
{
  int value;
  public MutableInteger(int n)
  {
    value=n;
  }
  public void increment()
  {
    ++value;
  }
  ... whatever other functions you need ...
}
见原子整数:

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

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

  public void increment(AtomicInteger i) {
    i.set(i.get() + 1);
 }
输出:

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]);    
    }
}

你的意思是说“对象是通过值传递的-…”?不,他没有。原语和引用按值传递。对象根本不被传递;它们生活在堆上。您决定不解释如何通过反射修改
整数了吗?:-)@Jon Skeet应该导入哪个java包来执行这个算法?@TahirYasin:我不知道你的意思。
Integer
类位于
java.lang
…什么?是的,我的意思是这很有效,但这不是一个好主意。它会做一些事情,比如同步处理器的缓冲区,因为它不是一个原子操作。实际上,除非需要atomi,否则不应该使用数据类型的原子版本
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