【问题标题】:How do I use an equivalent to C++ reference parameters in Java?如何在 Java 中使用与 C++ 引用参数等效的参数?
【发布时间】:2009-01-10 03:06:54
【问题描述】:

假设我在 C++ 中有这个:

void test(int &i, int &j)
{
    ++i;
    ++j;
}

值在函数内部改变,然后在外部使用。我怎样才能编写在 Java 中执行相同操作的代码?我想我可以返回一个封装这两个值的类,但这看起来真的很麻烦。

【问题讨论】:

  • Java 只传递对象引用。您可以认为它们与 boost shared_ptr 基本相同。只需将基元装箱在一个对象中即可。您可能需要更正问题的措辞。
  • 对不起,但我必须插话。在 c++ 中通过引用传递参数是邪恶的。不要这样做。
  • @Steve Lacey - 他们为什么邪恶?

标签: java c++ reference


【解决方案1】:

使用包装器模拟引用。

以某种方式模拟这种行为的一种方法是创建一个通用包装器。

public class _<E> {
    E ref;
    public _( E e ){
        ref = e;
    }
    public E g() { return ref; }
    public void s( E e ){ this.ref = e; }

    public String toString() {
        return ref.toString();
    }
}

我不太相信这段代码的价值,因为我忍不住,我不得不编码:)

原来如此。

示例用法:

public class Test {

    public static void main ( String [] args ) {
        _<Integer> iByRef = new _<Integer>( 1 );
        addOne( iByRef );
        System.out.println( iByRef ); // prints 2

        _<String> sByRef = new _<String>( "Hola" );
        reverse( sByRef ); 
        System.out.println( sByRef ); // prints aloH

    }

    // Change the value of ref by adding 1
    public static void addOne( _<Integer> ref ) { 
        int i = ref.g();
        ref.s( ++i  );

        // or 
        //int i = ref.g();
        //ref.s( i + 1 );

    }
    // Reverse the vale of a string.
    public static void reverse( _<String> otherRef ) { 
        String v = otherRef.g();
        String reversed = new StringBuilder( v ).reverse().toString();
        otherRef.s( reversed );
    }

}

这里有趣的是,通用包装类名称是“_”,它是一个有效的类标识符。所以声明如下:

对于整数:

_<Integer> iByRef = new _<Integer>( 1 );

对于字符串:

_<String> sByRef = new _<String>( "Hola" );

对于任何其他类

_<Employee> employee = new _<Employee>( Employee.byId(123) );

方法“s”和“g”代表set和get:P

【讨论】:

    【解决方案2】:

    Java 没有等效的 C++ 引用。使其工作的唯一方法是将值封装在另一个类中并交换类中的值。

    这是一个关于这个问题的冗长讨论:http://www.yoda.arachsys.com/java/passing.html

    【讨论】:

      【解决方案3】:

      嗯,有几个解决方法。你自己提到了一个。另一个是:

      public void test(int[] values) {
          ++values[0];
          ++values[1];
      }
      

      不过,我会使用自定义对象。这是一种更清洁的方式。另外,尝试重新安排您的问题,以便单个方法不需要返回两个值。

      【讨论】:

        【解决方案4】:

        Java 没有按引用传递。您必须封装以实现所需的功能。 Jon Skeet 简要介绍了 explanation 为什么从 Java 中排除传递引用。

        【讨论】:

          【解决方案5】:

          一个更好的问题:为什么要创建具有这种副作用的方法?

          通常,这强烈表明您应该将数据提取到一个单独的类中,并使用公共访问器来描述操作发生的原因。

          【讨论】:

            【解决方案6】:

            Java 按值传递参数,并且没有允许按引用传递的机制。

            【讨论】:

              【解决方案7】:

              你必须以某种方式(你的方式)装箱。

              整数是不可变的。太没用了。 int 是可变的,但由于 java 是按值传递的,因此在这种情况下它再次无法使用。 有关更多说明,请参阅这些页面:Java is Pass-by-Value, Dammit!int vs Integer

              Apache commons lang 有一个 MutableInt 类。或者你可以自己写。

              无论如何,它不应该那么糟糕,因为它不应该经常发生。如果是这样,那么你应该彻底改变你用 Java 编码的方式。

              【讨论】:

                【解决方案8】:

                这两个整数有关系吗?像一对 x/y 坐标?如果是这样,我会将整数放入一个新类中并将该类传递给方法。

                class A{ 
                  public void test(Coord c)
                  {
                    c.x++;
                    c.y++;
                  }
                  private class Coord{
                    public int x, y;
                  }
                }
                

                如果这两个整数不相关,您可能需要考虑一下为什么首先将它们传递给同一个方法。

                【讨论】:

                  【解决方案9】:

                  恕我直言,虽然它是一种糟糕的设计模式,但另一种可能的解决方案是

                  static void test(AtomicInteger i, AtomicInteger j)
                  {
                      i.incrementAndGet();
                      j.incrementAndGet();
                  }
                  

                  【讨论】:

                    【解决方案10】:

                    最简单的解决方案是使用org.apache.commons.lang.mutable.MutableInt类你不需要自己写。

                    【讨论】:

                      【解决方案11】:

                      你可以构造装箱的对象,即,

                      Integer iObj = new Integer(i);
                      Integer jObj = new Integer(j);
                      

                      把你的例程写成

                      public void test(Integer i, Integer j){
                        i = i.add(1);
                        j = j.add(1);
                      }
                      

                      出于各种原因,Java 的设计者认为按值调用更好。他们故意不包括通过引用调用的方法。 (严格来说,它们将引用的副本传递给对象,原始类型的特殊情况是它们纯粹按值调用。但效果是一样的。)

                      【讨论】:

                      • 这仍然不会改变方法之外的对象,因为整数是不可变的。
                      • 您从哪里得知 Integer 有一个 add() 方法?无论如何,正如 Bombe 指出的那样,整数是不可变的,这会给您带来完全相同的问题(但需要更多的输入)。
                      • 看来我应该把那条评论发给 jinguy;他是添加这些方法的人。
                      • 你可以传入 AtomicInteger 代替,这是可变的。这不是它的预期目的,但几乎可以使这种方法起作用。
                      • 这不起作用,因为对象引用是按值传递的,就像 java 中的所有内容一样。读这个。 stackoverflow.com/questions/373419/…
                      猜你喜欢
                      • 1970-01-01
                      • 2011-12-11
                      • 2015-10-15
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2021-08-10
                      • 1970-01-01
                      • 2020-10-06
                      相关资源
                      最近更新 更多