Mecanismo de transferencia de Java: ¿transferencia de valor o transferencia de referencia? (Versión gráfica detallada)

Prefacio

Comprender el mecanismo de transferencia en Java nos ayuda a comprender mejor la dirección que apunta a Java en la memoria. Explicaré este artículo lo más simple posible para que todos lo comprendan mejor.


1. Tipo de entrega

En primer lugar, debemos saber que el tipo de transferencia se refiere a la forma en que los parámetros pasaron al llamar a la función . Hay dos tipos de transferencia : transferencia de valor y transferencia de referencia.

Transferencia de valor : pasamos la copia del parámetro real del parámetro formal pasado a la función, operar el parámetro formal en la función no cambia el valor del parámetro real

Pasar por referencia: pasa la dirección de referencia del parámetro real al método

Para lenguajes como C ++, hay tanto el paso de valores como el paso de referencias
. La implementación del paso de valores: int func (int a, int b);
y la implementación del paso por referencia se realiza mediante puntero o referencia , por ejemplo: int func (int * a, int & b);

Para Java, solo hay paso de valores, no de referencia


2. Mecanismo de transferencia de valores en Java

Para que todos comprendan mejor, lo mostraré a través de muchos dibujos. Inserte la descripción de la imagen aquí
Aquí encontré un diagrama de estructura de memoria JVM de Internet, puede ver que el programa Java está dividido en varias áreas de la memoria. Para ayudar a todos a comprender, el mecanismo de transferencia de valor de Java que se discutirá aquí se centra principalmente en las dos áreas más comunes del área de pila y el área de pila, e ignora los detalles del interior.

En primer lugar, debemos saber que hay dos tipos de variables en Java: tipos básicos y tipos de referencia . A continuación, utilizo algunos ejemplos para ayudarlo a comprender mejor el mecanismo de transferencia de valor de Java.

Primer ejemplo

public class Main01 {
    
    
	
	public static void main(String[] args) {
    
    
		int a = 10, b = 20;
		exchange(a, b);
		System.out.println("a = " + a + ", b = " + b);
	}
	
	public static void exchange(int a, int b) {
    
    
		int tmp = a;
		a = b;
		b = tmp;
	}
}

Primero mire un ejemplo de un tipo básico, mire este código y adivine cuál es el resultado.

a = 10, b = 20

No debería ser difícil de entender, porque Java usa un mecanismo de transferencia de valor, y lo que se pasa es una copia del parámetro real. Cambiar el valor del parámetro formal en la función no afectará el valor original. Luego, entiéndalo a través de la memoria.

El área de pila en Java se compone de marcos de pila, un marco de pila corresponde a un método, y el inicio y el final del método corresponden al proceso de apilamiento y extracción. Cuando se ejecuta el programa, el marco de pila compuesto por el método principal main () se empuja primero a la pila. Durante la ejecución del método principal, la ejecución del método corresponde a la pila, se encuentra el final del método y la pila se abre. Cuando finaliza la ejecución del método principal, el programa finaliza.

Primer ejemplo

El código anterior se ve así dibujando una imagen, primero abra el marco de pila correspondiente al método principal main (). Luego empuje el marco de la pila correspondiente al método exchange (), salga de la pila después de que finalice el método exchange () y, finalmente, el final del método principal main () significa el final del programa. Se puede ver que cambiar los parámetros formales a'yb'en el método exchange () no afecta los valores de los parámetros reales ayb en el método principal main ().

Luego miramos hacia abajo y analizamos un fragmento de código sobre tipos de referencia

Segundo ejemplo

public class Main01 {
    
    
	
	public static void main(String[] args) {
    
    
		Student s1 = new Student("张三");
		Student s2 = new Student("李四");
		exchange(s1, s2);
		System.out.println(s1);
		System.out.println(s2);
	}
	
	public static void exchange(Student s1, Student s2) {
    
    
		Student tmp = s1;
		s1 = s2;
		s2 = tmp;
	}
}

class Student {
    
    
	
	public Student(String name) {
    
    
		this.name = name;
	}
	
	public String name;
	
	@Override
	public String toString() {
    
    
		return "Student [name=" + name + "]";
	}
	
}

¿Cuál es el resultado esta vez?

Student [name=张三]
Student [name=李四]

Como puede ver, los valores de nombre de s1 y s2 no han cambiado

¿Por qué es esto? El tipo de referencia pasa la dirección, que se intercambia en el método exchange (). ¿Por qué no se intercambian los puntos de s1 y s2 en el método main ()?

Después de leer este ejemplo, si ya tiene una respuesta a esta pregunta, sería genial. ¿Debe tener cierta comprensión del paso de valores de Java? Si aún hay dudas, ¡sígueme para continuar con el análisis!

Al analizar, debemos plantear una pregunta, ¿hay alguna diferencia entre los tipos básicos y los tipos de referencia por paso de valor?

También usamos el gráfico de memoria para analizar

Segundo ejemplo
Solo tiene que recordar una cosa, una copia de los parámetros reales pasados ​​por la transferencia de valor de Java. En este ejemplo, la función exchange () también lleva una copia de s1 y s2, pero esta vez, apuntan a El mismo espacio de memoria en el área del montón.

Cuando se ejecuta la función exchange (), se intercambian los puntos de dirección de memoria de los parámetros formales s1 'y s2'. Para los parámetros actuales s1 y s2, los punteros no han cambiado.

Después de leer los dos ejemplos anteriores, parece pensar que tanto los tipos básicos como los tipos de referencia se pasan por valor. ¿Pasar es una copia y realmente no puede cambiar el valor original?

¿Pero es éste realmente el caso?

A continuación, miramos el último ejemplo de tipos de referencia, tal vez pueda ayudarlo a comprender realmente el paso de valores de Java

El tercer ejemplo

public class Main01 {
    
    
	
	public static void main(String[] args) {
    
    
		Student s1 = new Student();
		Student s2 = new Student();
		s1.name = "张三";
		s2.name = "李四";
		exchange(s1, s2);
		System.out.println(s1);
		System.out.println(s2);
	}
	
	public static void exchange(Student s1, Student s2) {
    
    
		Student tmp = new Student();
		tmp.name = "张三";
		s1.name = s2.name;
		s2.name = tmp.name;
	}
}

class Student {
    
    
	
	public String name;
	
	@Override
	public String toString() {
    
    
		return "Student [name=" + name + "]";
	}
	
}

Analiza este código detenidamente, ¿cuál es tu resultado?

¿Crees que s1.name sigue siendo "Zhang San" y s2.name sigue siendo "Li Si"?

Veamos el resultado

Student [name=李四]
Student [name=张三]

¿Eh? ¿Por qué es diferente de lo que piensas? ¿No significa que se pasa el tipo de referencia, incluso si es una copia de la dirección, cambiar el punto de la dirección del parámetro formal no puede cambiar el punto del parámetro real?

¡Correcto! Este es de hecho el caso, la transferencia de valor, el cambio de la dirección del parámetro formal no afecta la dirección del parámetro real, pero en el tercer ejemplo, el valor del espacio de direcciones cambia.

Jaja, ¿estás estupefacto por mí?

Dibujemos entonces un gráfico de memoria para su análisis.

Antes de ejecutar exchange ():
Inserte la descripción de la imagen aquí
en este momento, solo el marco de pila correspondiente al método principal main ()

Luego ejecute el método exchange (), y el marco de pila correspondiente a exchange () se inserta en la pila

Primero, cree un nuevo objeto Student tmp, que su nombre = "Zhang San"

Luego, los parámetros formales s1 'y s2' se intercambian para señalar el valor del nombre del objeto en el espacio de memoria del montón

Entonces se convierte en lo siguiente

Inserte la descripción de la imagen aquí
Viendo esto, ¿entiendes? Note la diferencia entre el tercer ejemplo y el segundo ejemplo.

El segundo ejemplo es cambiar la dirección de los parámetros formales s1 'y s2', pero no cambia la dirección de los parámetros reales s1 y s2, por lo que los parámetros reales no han cambiado.

El tercer ejemplo no cambia los punteros de los parámetros reales s1 y s2, y el espacio de memoria al que apunta el área del montón no ha cambiado, pero cambiamos el valor del nombre del objeto del área del montón correspondiente, por lo que la salida ha cambiado. En esencia, cambiar el valor de un parámetro formal no cambia la dirección del parámetro formal, que se llama transferencia de valor.

A través de los tres ejemplos anteriores, ¿tiene un conocimiento profundo del mecanismo de transferencia de valor de Java?

ps. Soy un perro de segundo año, con capacidad limitada, y el tipo grande está chorreando, si hay alguna parte que no entiendo, ¡deje un mensaje en el área de comentarios!

Supongo que te gusta

Origin blog.csdn.net/qq_45590494/article/details/105978255
Recomendado
Clasificación