¡Quiero aclararle a fondo que Java es un valor que pasa y no acepta el tipo de argumento!

Prólogo

En cuanto a cuál es exactamente el paso de parámetros entre métodos en Java, por qué muchas personas dicen que Java solo tiene valor para pasar, y así sucesivamente, muchas personas me han intrigado. Incluso cuando entrevisté a muchos desarrolladores experimentados durante la entrevista, también son muy difíciles. La explicación es clara.

También escribí un artículo durante mucho tiempo, pensé que lo había dejado claro, pero recientemente, al resolver esta parte del conocimiento, descubrí que no entendía lo suficiente en ese momento, así que pensé en leerlo a través de Google Vea cómo otras personas entienden, pero desafortunadamente, no se puede decir claramente una buena información.

Entonces, decidí tratar de resumir este tema y volver a comprender el problema.

Tiempo de rumores

Con respecto a este tema, también ha habido una extensa discusión sobre StackOverflow. Parece que muchos programadores tienen diferentes interpretaciones de este problema, e incluso muchas personas lo entienden mal. Algunas personas pueden saber que pasar parámetros en Java es pasar por valor, pero no pueden decir por qué.

Antes de comenzar una explicación en profundidad, es necesario corregir esos conceptos erróneos anteriores. Si tiene las siguientes ideas, debe leer este artículo.

Malentendido uno: transferencia de valor y transferencia de referencia, la condición distintiva es el contenido de la transferencia, si es un valor, es la transferencia de valor. Si es una referencia, es por referencia.


Malentendido 2: Java está pasando por referencia.


Malentendido 3: si el parámetro pasado es un tipo común, se pasa por valor, si es un objeto, se pasa por referencia.

Parámetro de participación real

Todos sabemos que los parámetros se pueden definir al definir métodos en Java. Por ejemplo, el método principal en Java, public static void main (String [] args), donde args es el parámetro. Los parámetros se dividen en parámetros formales y parámetros reales en el lenguaje de programación.

Parámetros formales: los parámetros utilizados al definir el nombre de la función y el cuerpo de la función, el propósito es recibir los parámetros pasados ​​al llamar a la función.


Parámetros reales: cuando se llama a una función parametrizada, existe una relación de transferencia de datos entre la función que llama y la función llamada. Cuando se llama a una función en la función de llamada, el parámetro entre paréntesis después del nombre de la función se llama "parámetro real".

Un simple ejemplo:

public static void main(String[] args) {
  ParamTest pt = new ParamTest();
  pt.sout("Hollis");//实际参数为 Hollis
}
public void sout(String name) { //形式参数为 name
  System.out.println(name);
}复制代码

Los parámetros reales son el contenido que realmente se pasa cuando se llama al método parametrizado, y los parámetros formales son los parámetros utilizados para recibir el contenido del parámetro real.

Estrategia de evaluación

Dijimos que cuando se llama a un método, los parámetros reales deben pasarse a los parámetros formales, entonces, ¿qué se pasa exactamente en el proceso de pasar?

Este es en realidad el concepto de estrategias de evaluación en la programación .

En informática, una estrategia de evaluación es un conjunto de reglas (generalmente deterministas) que determinan la evaluación de expresiones en lenguajes de programación. La estrategia de evaluación define cuándo y en qué orden se evalúan los parámetros reales de la función, cuándo se sustituyen en la función y en qué forma se produce la sustitución.

Las estrategias de evaluación se dividen en dos categorías básicas, en función de cómo manejar los parámetros reales de la función, divididos en estrictos y no estrictos.

Evaluación estricta

En "evaluación estricta", durante la llamada a la función, los parámetros reales dados a la función siempre se evalúan antes de aplicar la función. La mayoría de los lenguajes de programación existentes utilizan una evaluación estricta de las funciones. Por lo tanto, solo nos centramos en una evaluación estricta.

Hay unos pocos estrategia clave de evaluación es que estamos más preocupados por la evaluación estricta de esa llamada por (llamada por valor), llamadas por referencia (llamada por referencia) y pasar las llamadas de objetos compartidos (llamar para compartir).

  • Llamada por valor (transferencia de valor)
    • En la llamada de paso por valor, el parámetro real se evalúa primero, y luego su valor se copia al parámetro formal de la función llamada. Debido a que el parámetro formal es solo una "copia local", por lo que si el valor del parámetro formal se cambia en la función llamada, el valor del parámetro real no se cambiará.
  • Llamar por referencia (pase de solicitud)
    • En una llamada de paso por referencia, la referencia implícita a sus parámetros reales se pasa a la función en lugar de una copia de los parámetros reales. Debido a que se pasa la referencia, si el valor del parámetro formal se cambia en la función llamada, la persona que llama puede ver el cambio.
  • Pasar una llamada de objeto compartido (transferencia de objeto compartido)
    • En una llamada para pasar un objeto compartido, primero obtenga la dirección del parámetro real, luego cópielo y pase la copia de la dirección al parámetro formal de la función llamada. Debido a que la dirección del parámetro apunta al mismo objeto, lo llamamos "pasar objeto compartido", por lo que si el valor del parámetro formal se cambia en la función llamada, la persona que llama puede ver este cambio.

No sé si usted ha descubierto, de hecho, que el proceso de invocar objetos compartidos y llamar por valor es casi el mismo: todos son "evaluación", "copia" y "aprobación". Tu producto, tu producto.

¡Quiero aclararle a fondo que Java es un valor que pasa y no acepta el tipo de argumento!

Sin embargo, el resultado de la llamada al objeto compartido y la llamada de referencia interna son los mismos: si el contenido del parámetro se cambia en la función llamada, este cambio también afectará a la persona que llama. Pruebas de nuevo, pruebas de nuevo.

Entonces, ¿cuál es la relación entre entrega de objeto compartido, entrega de valor y entrega de referencia?

Para este problema, debemos prestar atención al proceso, no al resultado, porque el proceso de llamar al objeto compartido es el mismo que el proceso de llamar por valor, y hay una operación clave, es decir, "copiar", por lo tanto, generalmente pensamos que el paso La llamada a un objeto compartido es un caso especial de llamada por valor

Dejemos de lado la llamada para pasar el objeto compartido, repasemos la diferencia principal entre la llamada por valor y la llamada por referencia:

La llamada de paso por valor se refiere a pasar una copia del parámetro real a la función cuando se llama a la función, y la llamada de paso por referencia se refiere a pasar la referencia del parámetro real a la función directamente cuando se llama a la función.

¡Quiero aclararle a fondo que Java es un valor que pasa y no acepta el tipo de argumento!

Por lo tanto, la principal diferencia entre los dos es si se pasa directamente o si es una copia.

Aquí damos un ejemplo de la imagen. Vamos a comprender mejor las llamadas de paso por valor y las llamadas de paso por referencia:

Tienes una llave. Cuando tu amigo quiere ir a tu casa, si le das tu llave directamente, esta es una referencia.


En este caso, si le hizo algo a la clave, por ejemplo, grabó su nombre en la clave, luego, cuando la clave se le devuelva, su propia clave también tendrá su nombre grabado.


Tienes una llave. Cuando tu amigo quiere ir a tu casa, le grabas una nueva llave y la tuya aún está en tus manos. Esto es transferencia de valor.


En este caso, lo que haga con esta llave no afectará la llave en su mano.

Estrategia de evaluación de Java

Anteriormente, introdujimos llamadas de valor, llamadas de referencia y casos especiales de llamadas de valor para pasar llamadas de objetos compartidos. Entonces, ¿qué estrategia de evaluación se usa en Java?

Mucha gente dice que los tipos de datos básicos en Java se pasan por valor. Básicamente no hay nada que discutir sobre esto. Generalmente se cree que.

Sin embargo, muchas personas creen erróneamente que el paso de objetos en Java pasa por referencia. La razón de este malentendido es principalmente porque hay una relación de referencia entre variables y objetos en Java. Los objetos se manipulan por referencia a objetos en el lenguaje Java. Por lo tanto, muchas personas piensan que la transferencia de objetos es la transferencia de referencias.

Y muchas personas también pueden citar los siguientes ejemplos de código:

public static void main(String[] args) {
      Test pt = new Test();
      User hollis = new User();
      hollis.setName("Hollis");
      hollis.setGender("Male");
      pt.pass(hollis);
      System.out.println("print in main , user is " + hollis);
    }
public void pass(User user) {
      user.setName("hollischuang");
      System.out.println("print in pass , user is " + user);
    }复制代码

Resultado de salida:

print in pass , user is User{name='hollischuang', gender='Male'}
print in main , user is User{name='hollischuang', gender='Male'}复制代码

Se puede ver que después de que el tipo de objeto se pasa al método pass, su contenido cambia dentro del método, y finalmente el objeto en el método principal del llamante también cambia.

Por lo tanto, muchas personas dicen que esto es lo mismo que el fenómeno del paso de referencia, es decir, cambiar el valor del parámetro dentro del método afectará a la persona que llama.

Sin embargo, esto es en realidad un malentendido.

Objeto que pasa en Java

Muchas personas muestran que los objetos Java se pasan por referencia a través del fenómeno de los ejemplos de código, por lo que comenzamos con el fenómeno y refutamos esta vista primero.

Como dijimos anteriormente, si se trata de transferencia de valor o transferencia de referencia es solo una de las estrategias de evaluación. Hay muchas estrategias de evaluación. Por ejemplo, el fenómeno de transferencia de objeto compartido mencionado anteriormente es el mismo que la transferencia de referencia. Entonces, ¿por qué dice que el paso de parámetros en Java debe ser paso de referencia en lugar de paso de objeto compartido?

Entonces, ¿cuál es la forma de transferencia de objetos en Java? De hecho, es realmente la transferencia de objetos compartidos.

De hecho, en "The Java ™ Tutorials", hay una descripción de esta parte del contenido. Primero, los tipos básicos se describen a continuación:

Los argumentos primitivos, como un int o un doble, se pasan a los métodos por valor. Esto significa que cualquier cambio en los valores de los parámetros solo existe dentro del alcance del método. Cuando el método regresa, los parámetros desaparecen y cualquier cambio en ellos se pierde.

Es decir, los parámetros originales se pasan al método por valor. Esto significa que cualquier cambio en los valores de los parámetros solo existirá dentro del alcance del método. Cuando el método regrese, los parámetros desaparecerán y se perderán todos los cambios que se realicen en ellos.

La descripción de la transferencia de objetos es la siguiente:

Los parámetros de tipo de datos de referencia, como los objetos, también se pasan a los métodos por valor. Esto significa que cuando el método regresa, la referencia pasada aún hace referencia al mismo objeto que antes. Sin embargo, los valores de los campos del objeto se pueden cambiar en el método, si tienen el nivel de acceso adecuado.

En otras palabras, los parámetros de tipo de datos de referencia (como los objetos) también se pasan al método por valor. Esto significa que cuando el método regresa, la referencia entrante todavía hace referencia al mismo objeto que antes. Sin embargo, si los campos de objeto tienen el nivel de acceso apropiado, puede cambiar los valores de estos campos en el método.

La documentación oficial de este punto ha dejado muy claro que Java está pasando por valor, simplemente pasando la referencia del objeto como un valor al método. Sus detalles, ¿no es esta entrega de objetos compartidos?

De hecho, la estrategia de evaluación utilizada en Java es pasar la llamada al objeto compartido, es decir, Java pasará una copia de la dirección del objeto a los parámetros formales de la función llamada. Es solo que la palabra "pasar llamadas a objetos compartidos" no se usa comúnmente, por lo que la gente de la comunidad Java suele decir "Java es una llamada por valor". Así es, porque llamar a un objeto compartido es en realidad un caso especial de llamada por valor.

¿El fenómeno de transferencia de valor y transferencia de objetos compartidos entra en conflicto?

Al ver aquí, muchas personas pueden tener una pregunta: dado que la transferencia de objetos compartidos es un caso especial de transferencia de valor, ¿por qué sus fenómenos son completamente diferentes?

¿Es posible afectar a la persona que llama si el valor se cambia en el método llamado durante la transferencia de valor? Entonces, ¿cuándo afectará exactamente y cuándo no?

De hecho, no hay conflicto. La razón de esta duda es porque todos tienen un malentendido sobre lo que está "cambiando el valor".

Volvamos al ejemplo anterior y veamos qué sucedió realmente durante la llamada.

¡Quiero aclararle a fondo que Java es un valor que pasa y no acepta el tipo de argumento!

En el proceso de transmisión de parámetros, la dirección del parámetro real 0X1213456 se copió al parámetro formal. Este proceso es en realidad la transferencia de valor, pero el contenido de la transferencia es la aplicación del objeto.

Entonces, ¿por qué cambiamos el valor del atributo en el usuario, pero tuvo un efecto en el usuario original?

De hecho, el proceso es el siguiente: usted copió una llave de su casa a su amigo. Después de que él obtuvo la llave, no hizo ningún cambio en la llave, sino que abrió la habitación de su casa a través de la llave. Puerta, entra a la casa y destroza tu TV.

Este proceso no tiene ningún efecto en la llave en su mano, pero alguien ha cambiado el contenido de la casa correspondiente a su llave.

En otras palabras, la transferencia del objeto Java es transferir la relación de referencia copiando. Si no cambiamos la relación de referencia, pero encontramos la dirección referenciada y cambiamos el contenido, afectará al llamador. Porque todos apuntan al mismo objeto compartido.

Entonces, si cambiamos el contenido del método pass:

public void pass(User user) {
    user = new User();
    user.setName("hollischuang");
    System.out.println("print in pass , user is " + user);
}复制代码

En el código anterior, renovamos un objeto de usuario en el método pass y cambiamos su valor. El resultado es el siguiente:

print in pass , user is User{name='hollischuang', gender='Male'}
print in main , user is User{name='Hollis', gender='Male'}复制代码

Mira lo que sucedió en todo el proceso nuevamente:

¡Quiero aclararle a fondo que Java es un valor que pasa y no acepta el tipo de argumento!

Este proceso es como si copiaste una llave a tu amigo, y después de que tu amigo recibió la llave que le diste, encuentra un cerrajero para modificarlo, y la llave en su mano se abrió. La llave de la cerradura de su casa. En este momento, cuando abrió su casa, incluso si hubiera ordenado la casa, no tendría ningún efecto en las llaves en su mano y su casa.

Por lo tanto, la transferencia de objetos en Java no tendrá ningún efecto sobre el objeto original si se modifica por referencia, pero si el valor de la propiedad del objeto compartido se modifica directamente, afectará al objeto original.

Resumen

Sabemos que el paso de parámetros entre métodos se requiere en un lenguaje de programación. Esta estrategia de paso se llama estrategia de evaluación.

En el diseño del programa, hay muchas estrategias de evaluación, la más común es el paso de valores y el paso de referencia. También hay un caso especial de valor que pasa el paso de objetos compartidos.

La mayor diferencia entre la transferencia de valor y la transferencia de referencia es si una copia se copia durante la transferencia. Si la copia se transfiere, es una transferencia de valor, de lo contrario es una transferencia de referencia.

En Java, de hecho, la transferencia de parámetros se realiza mediante transferencia de valor, pero para la transferencia de objetos Java, el contenido pasado es una referencia al objeto.

Podemos concluir que la estrategia de evaluación en Java es la entrega de objetos compartidos, lo cual es completamente correcto.

Sin embargo, para que todos entiendan lo que está diciendo, decimos que en Java solo se pasa el valor, pero el contenido que se pasa es una referencia al objeto. Esto también está bien.

Sin embargo, no debe suponer que hay referencia pasando en Java.

OK, lo anterior es todo el contenido de este artículo, no sé si este artículo te ayuda a resolver las dudas que siempre has tenido en mente. Bienvenido a dejar un mensaje para hablar sobre tus pensamientos.

Materiales de referencia:

https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html

https://en.wikipedia.org/wiki/Evaluation_strategy

https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value

https://blog.penjee.com/passing-by-value-vs-by-reference-java-graphical/

Número público reimpreso: Hollis, una persona con una búsqueda única de Codificación, actualmente un experto en tecnología de Alibaba, blogger de tecnología personal, decenas de millones de artículos técnicos leídos en toda la red, coautor de "Tres cursos para programadores".


Supongo que te gusta

Origin juejin.im/post/5e9557ec51882573b4361126
Recomendado
Clasificación