2009-07-01 24 views

Respuesta

210

Java es confuso porque todo se pasa por el valor. Sin embargo, para un parámetro del tipo de referencia (es decir, no es un parámetro de tipo primitivo) es la referencia en sí que se pasa por valor, por lo que aparece para pasar por referencia (y la gente suele afirmar que es). Este no es el caso, como lo demuestra el siguiente:

Object o = "Hello"; 
mutate(o) 
System.out.println(o); 

private void mutate(Object o) { o = "Goodbye"; } //NOT THE SAME o! 

imprimirá Hello a la consola. Las opciones si se quería que el código anterior para imprimir Goodbye son para uso una referencia explícita de la siguiente manera:

AtomicReference<Object> ref = new AtomicReference<Object>("Hello"); 
mutate(ref); 
System.out.println(ref.get()); //Goodbye! 

private void mutate(AtomicReference<Object> ref) { ref.set("Goodbye"); } 
+46

Además, una matriz de longitud 1 se puede utilizar para crear una referencia si realmente quiere confundir a las personas :) – Christoffer

+1

Esto es muy cierto –

+2

AtomicReference y las clases correspondientes (AtomicInteger) son las mejores para tales operaciones – Naveen

10

no creo que pueda. Su mejor opción podría ser encapsular lo que desea pasar "por ref" en otra instancia de clase, y pasar la referencia de la clase (externa) (por valor). Si ves lo que quiero decir ...

es decir, tu método cambia el estado interno del objeto que se pasa, que luego es visible para la persona que llama.

23

En Java no hay nada a nivel de lenguaje similar a ref. En Java no únicamente de paso por valor semántico

En aras de la curiosidad se puede implementar un ref-como semántica en Java simplemente envolviendo sus objetos en una clase mutable:

public class Ref<T> { 

    private T value; 

    public Ref(T value) { 
     this.value = value; 
    } 

    public T get() { 
     return value; 
    } 

    public void set(T anotherValue) { 
     value = anotherValue; 
    } 

    @Override 
    public String toString() { 
     return value.toString(); 
    } 

    @Override 
    public boolean equals(Object obj) { 
     return value.equals(obj); 
    } 

    @Override 
    public int hashCode() { 
     return value.hashCode(); 
    } 
} 

caso_prueba:

public void changeRef(Ref<String> ref) { 
    ref.set("bbb"); 
} 

// ... 
Ref<String> ref = new Ref<String>("aaa"); 
changeRef(ref); 
System.out.println(ref); // prints "bbb" 
+1

¿Debe la penúltima línea leer "prueba (ref);"? –

+0

@Brian Fisher: corregido, gracias – dfa

+0

¿Por qué no utilizar java.lang.ref.Reference en su lugar? – Hardcoded

62

¿Puedo pasar los parámetros por referencia en Java?

¿Por qué? Java tiene solo un modo de pasar argumentos a métodos: por valor.

Nota:

Por primitivas esto es fácil de entender: se obtiene una copia del valor.

Para todos los demás obtiene una copia de la referencia y esto también se llama pasar por valor.

Todo está en esta imagen:

enter image description here

+14

+1 para nerdness! – dfa

+3

La imagen está rota. – Omar

+8

+1 Ejemplo donde las imágenes proporcionan una explicación más clara que las palabras – bmartins

5

Java siempre se pasan por valor.

Cuando pasa una primitiva es una copia del valor, cuando pasa un objeto, es una copia del puntero de referencia.

18

De James Gosling en "The Java Programming Language":

"... No es exactamente el modo de cruce un parámetro en Java - paso por valor - y que mantiene las cosas simples ..."

+2

El pronunciamiento del dios del lenguaje debe ser declarado la respuesta. – ingyhere

+2

@ingyhere: 'La declaración del dios del lenguaje debe ser declarada la respuesta': No realmente. A pesar de lo que el creador de Java piense o crea, la respuesta absoluta vendría de una cita de la especificación del lenguaje. – paercebal

+0

De hecho, está en [JLS, en la sección 8.4.1] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.1), y el JLS cita a Gosling como primer autor: "Cuando se invoca el método o el constructor (§15.12), ** los valores de las expresiones reales del argumento inicializan las variables de parámetros recién creadas **, cada uno del tipo declarado, antes de la ejecución del cuerpo del método o constructor ". – ingyhere

4

Otra opción es usar una matriz, por ejemplo void method(SomeClass[] v) { v[0] = ...; } pero 1) la matriz se debe inicializar antes de invocar el método, 2) aún no se puede implementar, p. método de intercambio de esta manera ... Esta forma se usa en JDK, p. en java.util.concurrent.atomic.AtomicMarkableReference.get(boolean[]).

Cuestiones relacionadas