【问题标题】:How do I pass a primitive data type by reference?如何通过引用传递原始数据类型?
【发布时间】:2011-05-18 04:47:27
【问题描述】:

如何在 java 中通过引用传递原始类型?例如,如何使 int 传递给可修改的方法?

【问题讨论】:

  • 我认为这也适用于Integer

标签: java pass-by-reference primitive-types


【解决方案1】:

在 Java 中没有直接通过引用传递原语的方法。

一种解决方法是将引用传递给包装类的实例,然后将原语作为成员字段包含在内。为自己编写这样一个包装类可能非常简单:

public class IntRef { public int value; }

但是一些预先构建的包装类怎么样,这样我们就不必自己编写了?好的:

Apache commons-lang Mutable* 类:
优势:单线程使用性能好。完整性。
缺点:引入了第三方库依赖项。没有内置的并发控制。
代表类MutableBooleanMutableByteMutableDoubleMutableFloatMutableIntMutableLongMutableObjectMutableShort

java.util.concurrent.atomic Atomic* 类:
优势:标准 Java (1.5+) API 的一部分。内置并发控制。
缺点:在单线程设置中使用时性能损失很小。缺少对某些数据类型的直接支持,例如没有 AtomicShort。
代表类AtomicBooleanAtomicIntegerAtomicLongAtomicReference
注意:作为用户 ColinD shows in his answer,AtomicReference 可用于近似一些缺失的类,例如原子短。

长度为 1 的原始数组
OscarRyz's answer 演示了使用长度为 1 的数组来“包装”原始值。
优点:写起来快。高性能。不需要第三方库。
缺点:有点脏。没有内置的并发控制。导致代码不(清楚地)自记录:方法签名中的数组是否在那里,所以我可以传递多个值?还是在这里作为传递引用仿真的脚手架?

另请参阅
StackOverflow 问题“Mutable boolean field in Java”的答案。

我的意见
在 Java 中,您应该尽量少用或根本不使用上述方法。在 C 语言中,通常使用函数的返回值来传递状态代码(SUCCESS/FAILURE),而函数的实际输出通过一个或多个输出参数传递。在 Java 中,最好使用异常而不是返回码。这释放了用于承载实际方法输出的方法返回值——大多数 Java 程序员发现这种设计模式比输出参数更自然。

【讨论】:

  • 原子非常方便将计数器传递给多次调用的函数,特别是如果计数器的增加是函数中的条件,但不增加它并不一定意味着失败.无论如何,谢谢你的回答。很有帮助。
【解决方案2】:

java 中没有任何东西是通过引用传递的。都是按值传递的。

编辑:原语和对象类型都是按值传递的。您永远不能更改传递的值/引用并期望原始值/引用发生变化。示例:

String a;
int b;

doSomething(a, b);

...

public void doSomething(String myA, int myB) {
   // whatever I do to "myA" and "myB" here will never ever ever change
   // the "a" and "b"
}

绕过这个障碍的唯一方法是传递一个容器对象,或者使用返回值。

带支架:

private class MyStringHolder {
  String a;
  MyStringHolder(String a) {
    this.a = a;
  }
}

MyStringHolder holdA = new MyStringHolder("something");

public void doSomething(MyStringHolder holder) {
   // alter holder.a here and it changes.
}

有返回值

int b = 42;
b = doSomething(b);

public int doSomething(int b) {
  return b + 1;
}

【讨论】:

  • “正确”是一个布尔条件,不接受程度或种类的修饰符。
  • @tchrist:您可以在不实际回答问题的情况下做出正确的陈述。我可以说“1 + 1 = 2”,这是正确的,但不能回答问题。这里的原始答案比那个更接近于回答问题,但仍然没有提供任何对提问者真正有用的答案。
【解决方案3】:

改为传递AtomicIntegerAtomicBoolean 等。并非每种原始类型都有一个,但如果需要,您也可以使用 AtomicReference<Short>

请注意:在 Java 中应该很少需要做这样的事情。当您想这样做时,我建议您重新考虑您正在尝试做的事情,看看您是否不能以其他方式做到这一点(使用返回int的方法,比如说......什么是最好的要做的事情会因情况而异)。

【讨论】:

  • +1 虽然我认为与仅使用包装器/持有者对象相比,这可能是沉重的。
  • 如果您只是使用set(int) 对其进行变异,我认为不会有任何值得担心的性能影响...创建自己的可变包装器来执行此操作(或导入 commons-lang ,就此而言...)在我看来将是更糟糕的冒犯。另外,我希望不要经常这样做,因为我认为在很多情况下都不需要这样做。
  • 同意导入 commons-lang 是个坏主意。我猜 OP 是 C 程序员,他想继续使用相同的范式,这会导致理解 C 程序的大部分复杂性,所以我想他会经常使用这种“通过引用传递原语”解决方案.
  • 我同意;传递 C 风格的可变原语在 Java 中几乎总是错误的做法。它所做的只是让代码变得不必要的复杂。
【解决方案4】:

这在 Java 中是不可能的,作为替代方案,您可以将其包装在单个元素数组中。

void demo() { 
    int [] a = { 0 };
    increment ( a ) 
}
void increment( int [] v ) { 
     v[0]++;
}

但总有更好的选择。

【讨论】:

    【解决方案5】:

    你不能。但是你可以返回一个整数,它是一个修改后的值

    int i = 0;
    i = doSomething(i);
    

    如果您要传递多个,您可能希望创建一个Data Transfer Object(一个专门包含一组可以传递给类的变量的类)。

    【讨论】:

      【解决方案6】:

      将具有该值的对象作为字段传递。

      【讨论】:

        【解决方案7】:

        这在 Java 中是不可能的

        【讨论】:

          【解决方案8】:

          一种选择是使用 java.lang.Integer 之类的类,那么您根本不会传递原语。

          另一方面,您可以使用如下代码:

          int a = 5;
          a = func(a);
          

          并让 func 返回修改后的值。

          【讨论】:

          • java.lang.Integer 和朋友是不可变的。 java.util.concurrent.atomic.AtomicInteger 和朋友是可变的。我见过的另一种(粗略)选项是使用单元素数组。
          • 这是实现它的一种方式,对于一个单一的价值!
          猜你喜欢
          • 2023-03-22
          • 2015-02-22
          • 2011-04-09
          • 1970-01-01
          • 2011-06-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-27
          相关资源
          最近更新 更多