2010-11-30 11 views

Respuesta

67

No hay una forma de pasar una primitiva directamente por referencia en Java.

Una solución alternativa es pasar una referencia a una instancia de una clase contenedora, que a continuación contiene la primitiva como un campo miembro. Tal clase de contenedor podría ser extremadamente fácil de escribir por sí mismo:

public class IntRef { public int value; } 

Pero ¿qué tal un poco de pre-construidos clases de contenedor, por lo que no tenemos que escribir nuestra propia?OK:

Los Apache commons-lang mutables clases *:
Ventajas: buen rendimiento para el uso de un solo subproceso. Lo completo.
Desventajas: presenta una dependencia de biblioteca de terceros. Sin controles de simultaneidad incorporados.
Clases representativas: MutableBoolean, MutableByte, MutableDouble, MutableFloat, MutableInt, MutableLong, MutableObject, MutableShort.

Los java.util.concurrent.atomic atómicos * clases:
Ventajas: parte del estándar de Java (1.5 +) API. Controles de simultaneidad incorporados.
Desventajas: pequeño golpe de rendimiento cuando se utiliza en una configuración de un solo hilo. Falta soporte directo para algunos tipos de datos, p. no hay AtomicShort.
Clases representativas: AtomicBoolean, AtomicInteger, AtomicLong y AtomicReference.
Nota: como usuario ColinD shows in his answer, AtomicReference se puede utilizar para aproximar algunas de las clases que faltan, p. AtomicShort.

Longitud 1 matriz primitiva
OscarRyz's answer muestra el uso de una matriz de longitud 1 de "envolver" un valor primitivo.
Ventajas: Rápido de escribir. Performant. No se necesita una biblioteca de terceros.
Desventajas: Un poco sucio. Sin controles de simultaneidad incorporados. Resultados en un código que no (claramente) se auto-documenta: ¿está la matriz en la firma del método allí para que pueda pasar múltiples valores? ¿O está aquí como andamio para la emulación de paso por referencia?

ver también
Las respuestas a la pregunta StackOverflow "Mutable boolean field in Java".

Mi opinión
En Java, debe esforzarse por utilizar los enfoques anteriores con moderación o no en absoluto. En C, es común usar el valor de retorno de una función para retransmitir un código de estado (SUCCESS/FAILURE), mientras que la salida real de una función se transmite a través de uno o más parámetros de salida. En Java, es mejor usar Excepciones en lugar de códigos de retorno. Esto libera los valores de retorno del método que se utilizarán para transportar la salida del método real, un patrón de diseño que la mayoría de los programadores de Java consideran más natural que los parámetros externos.

+0

Atomics son muy útiles para pasar un contador a una función que se llama varias veces, especialmente si el aumento del contador es condicional en la función, pero no aumentarlo no necesariamente significa que algo falló. De todos modos, gracias por esta respuesta. Es muy útil. – Nyerguds

1

Eso no es posible en Java

13

Nothing in java se pasa por referencia. Todo pasó por valor.

Editar: Tanto las primitivas como los tipos de objetos se pasan por valor. Nunca puede alterar el valor/referencia pasado y esperar que cambie el valor/referencia de origen. Ejemplo:

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" 
} 

La única manera de evitar este obstáculo, independientemente de que sea una primitiva o de referencia, es pasar un objeto contenedor, o utilizar el valor de retorno.

Con un titular:

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. 
} 

Con valor de retorno

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

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

técnicamente correcto, pero no terriblemente útil –

+0

Ok, aclararé. –

+0

"Correcto" es una condición booleana, y no admite modificadores de grado o tipo. – tchrist

2

pasar un objeto que tiene ese valor como un campo.

-2

Una opción es utilizar clases como java.lang.Integer, entonces no está pasando un primitivo en absoluto.

Por otra parte, sólo puede utilizar un código como:

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

y func han devolver el valor modificado.

+6

java.lang.Entero y amigos son inmutables. java.util.concurrent.atomic.AtomicInteger y sus amigos son mutables. Otra opción (algo burda) que he visto es usar una matriz de 1 elemento. –

+0

¡Esta es una forma de lograrlo, por un solo valor! –

3

No puede. Pero se puede devolver un número entero que es un valor modificado

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

Si está de paso en más de una puede que desee crear una (una clase específicamente para contener un conjunto de variables que se pueden pasar a clases) Data Transfer Object .

13

Pase un AtomicInteger, AtomicBoolean, etc. en su lugar. No hay uno para cada tipo primitivo, pero puede usar, por ejemplo, un AtomicReference<Short> si es necesario también.

Nota: raramente debería haber una necesidad de hacer algo como esto en Java. Cuando quiera hacerlo, le recomendaría que reconsidere lo que está tratando de hacer y que vea si no puede hacerlo de otra manera (usando un método que devuelva int, digamos ... qué es exactamente lo mejor para do es variará de una situación a otra).

+0

+1 aunque creo que esto podría ser pesado en comparación con solo usar un objeto envoltorio/titular. –

+0

Si solo usa 'set (int)' para mutarlo, no creo que haya ningún impacto en el rendimiento que valga la pena preocuparse por ... crear su propio contenedor mutable para hacer esto (o importar commons-lang, para el caso ...) sería una ofensa mucho peor en mi opinión. Además, espero que esto no se haga con mucha frecuencia, ya que no creo que haya muchos casos en que esto realmente se necesite. – ColinD

+0

Estoy de acuerdo en importar commons-lang siendo una mala idea. Supongo que OP es un programador de C y quiere seguir usando los mismos paradigmas que conducen a la mayoría de las complejidades para comprender un programa de C, así que imagino que usará esta solución "pasar primitivo por referencia" con bastante frecuencia. . –

10

Eso no es posible en Java, como alternativa puede envolverlo en una única matriz de elementos.

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

Pero siempre hay mejores opciones.

Cuestiones relacionadas