¿Las matrices se pasan por valor o se pasan por referencia en Java?

Posible duplicado:
¿Java es “pass-by-reference”?

Las matrices no son un tipo primitivo en Java, pero tampoco son objetos , ¿se pasan por valor o por referencia? ¿Depende de qué contiene la matriz, por ejemplo, referencias o un tipo primitivo?

Su pregunta se basa en una premisa falsa.

Las matrices no son un tipo primitivo en Java, pero tampoco son objetos … “

De hecho, todas las matrices en Java son objetos 1 . Cada tipo de matriz de Java tiene java.lang.Object como su supertipo, y hereda la implementación de todos los métodos en Object API.

Como todos los objetos de Java, las matrices se pasan por valor … pero el valor es la referencia a la matriz.

El paso real por referencia implica pasar la dirección de una variable para que la variable se pueda actualizar. Esto NO es lo que sucede cuando pasas una matriz en Java.

Aquí hay algunos enlaces que explican la diferencia entre “pass-by-reference” y “pass-by-value”:

Pregunta SO relacionada:

  • ¿Java es “pass-by-reference” o “pass-by-value”?

Antecedentes históricos:

La frase “paso por referencia” fue originalmente “llamada por referencia”, y se usó para distinguir el argumento que pasaba la semántica de FORTRAN (llamada por referencia) de los de ALGOL-60 (llamada por valor) y llamar por nombre).

  • En call-by-value, la expresión del argumento se evalúa a un valor, y ese valor se copia al método llamado.

  • En llamada por referencia, la expresión de argumento se evalúa parcialmente a un “lvalue” (es decir, la dirección de una variable o elemento de matriz) que se pasa al método de llamada. El método de llamada puede leer directamente y actualizar la variable / elemento.

  • En call-by-name, la expresión de argumento real se pasa al método de llamada (!!) que puede evaluarlo varias veces (!!!). Esto fue complicado de implementar, y podría ser usado (abusado) para escribir código que era muy difícil de entender. Llamar por nombre solo se usó en Algol-60 (¡afortunadamente!).

ACTUALIZAR

En realidad, la llamada por nombre de Algol-60 es similar a pasar expresiones lambda como parámetros. La dificultad es que estas expresiones no exactamente lambda (se las denominó “thunks” en el nivel de implementación) pueden modificar indirectamente el estado de las variables que están en el scope en el procedimiento / función de llamada. Eso es parte de lo que los hizo tan difíciles de entender. (Ver la página de Wikipedia en el dispositivo de Jensen, por ejemplo).


1. Nada en el Q & A vinculado ( Arrays en Java y cómo se almacenan en la memoria ) indica o implica que los arrays no son objetos.

Everything in Java are passed-by value. . En el caso de Matriz (que no es más que un Objeto), la referencia de matriz se pasa por valor … (Al igual que una referencia de objeto se pasa por valor).

Cuando pasa una matriz a otro método, en realidad se copia la referencia a esa matriz.

  • Cualquier cambio en el contenido de la matriz a través de esa referencia afectará la matriz original.
  • Pero cambiar la referencia para apuntar a una nueva matriz no cambiará la referencia existente en el método original.

Ver esta publicación …

¿Java es “pass-by-reference” o “pass-by-value”?

Vea este ejemplo de trabajo:

 public static void changeContent(int[] arr) { // If we change the content of arr. arr[0] = 10; // Will change the content of array in main() } public static void changeRef(int[] arr) { // If we change the reference arr = new int[2]; // Will not change the array in main() arr[0] = 15; } public static void main(String[] args) { int [] arr = new int[2]; arr[0] = 4; arr[1] = 5; changeContent(arr); System.out.println(arr[0]); // Will print 10.. changeRef(arr); System.out.println(arr[0]); // Will still print 10.. // Change the reference doesn't reflect change here.. } 

Las matrices son, de hecho, objetos, por lo que se pasa una referencia (la referencia en sí misma se pasa por valor, ¿está confundida?). Ejemplo rápido:

 // assuming you allocated the list public void addItem(Integer[] list, int item) { list[1] = item; } 

Verá los cambios en la lista del código de llamada. Sin embargo, no puede cambiar la referencia en sí, ya que se pasa por valor:

 // assuming you allocated the list public void changeArray(Integer[] list) { list = null; } 

Si pasa una lista no nula, no será nula en el momento en que regrese el método.

No, eso está mal. Las matrices son objetos especiales en Java. Por lo tanto, es como pasar otros objetos donde pasa el valor de la referencia, pero no la referencia en sí misma. Es decir, cambiar la referencia de una matriz en la rutina llamada no se reflejará en la rutina de llamada.

Todo en Java se pasa por valor.

En el caso de la matriz, la referencia se copia en una nueva referencia, pero recuerde que todo en Java se pasa por valor.

Echa un vistazo a este interesante artículo para más información …

La discusión definitiva de las matrices está en http://docs.oracle.com/javase/specs/jls/se5.0/html/arrays.html#27803 . Esto deja en claro que las matrices de Java son objetos. La clase de estos objetos se define en 10.8.

La sección 8.4.1 de la especificación de idioma, http://docs.oracle.com/javase/specs/jls/se5.0/html/classes.html#40420 , describe cómo se pasan los argumentos a los métodos. Como la syntax de Java se deriva de C y C ++, el comportamiento es similar. Los tipos primitivos se pasan por valor, como con C. Cuando se pasa un objeto, una referencia de objeto (puntero) se pasa por valor, reflejando la syntax C de pasar un puntero por valor. Consulte 4.3.1, http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.3 ,

En términos prácticos, esto significa que modificar el contenido de una matriz dentro de un método se refleja en el objeto de la matriz en el scope de la llamada, pero reasignar un nuevo valor a la referencia dentro del método no tiene efecto sobre la referencia en el scope de la llamada, que es exactamente el comportamiento que se esperaría de un puntero a una estructura en C o un objeto en C ++.

Al menos parte de la confusión en la terminología proviene de la historia de los lenguajes de alto nivel antes del uso común de C. En los lenguajes de alto nivel anteriores y populares, la referencia directa a la memoria por la dirección era algo que debía evitarse en la medida de lo posible, y se consideró el trabajo del lenguaje para proporcionar una capa de abstracción. Esto hizo necesario que el lenguaje admitiera explícitamente un mecanismo para devolver valores de subrutinas (no necesariamente funciones). Este mecanismo es lo que se entiende formalmente al referirse a “pasar por referencia”.

Cuando se introdujo C, vino con una noción simplificada de llamada a procedimientos, donde todos los argumentos son solo de entrada, y el único valor devuelto a la persona que llama es el resultado de una función. Sin embargo, el propósito de pasar referencias podría lograrse a través del uso explícito y amplio de punteros. Como sirve para el mismo propósito, la práctica de pasar un puntero como referencia a un valor a menudo se refiere coloquialmente a pasar por referencia. Si la semántica de una rutina requiere que un parámetro pase por referencia, la syntax de C requiere que el progtwigdor pase explícitamente un puntero. Pasar un puntero por valor es el patrón de diseño para implementar la semántica de paso por referencia en C.

Dado que a menudo puede parecer que el único propósito de los punteros crudos en C es crear fallas, los desarrollos posteriores, especialmente Java, han buscado regresar a los medios más seguros para pasar parámetros. Sin embargo, el dominio de C hizo que incumbiera a los desarrolladores imitar el estilo familiar de la encoding C. El resultado son referencias que se pasan de manera similar a los punteros, pero se implementan con más protecciones para hacerlas más seguras. Una alternativa habría sido la rica syntax de un lenguaje como Ada, pero esto habría presentado la apariencia de una curva de aprendizaje no deseada, y habría disminuido la probable adopción de Java.

En resumen, el diseño del paso de parámetros para los objetos, incluidas las matrices, en Java, es esencialmente servir a la intención semántica de pasar por referencia, pero está implícito con la syntax de pasar una referencia por valor.

Una especie de truco real … Incluso las referencias se pasan por valor en Java, por lo tanto, un cambio en la referencia se establece en el nivel de función llamado. El comstackdor y / o JVM a menudo convierten un tipo de valor en una referencia.