JVM 栈 堆 方法区以及递归+值传递的理解

 我这里很多事白话阐述个人理解

栈:对象名 + 方法(局部变量)

堆:基本类型、引用类型地址

方法区:常量池->存放引用类型       类的信息-->属性、方法(这里是实例化时类的信息,调用时去栈中找到对应的方法)

 

实例化对象时,jvm内存运行流程:
Person p1 = new Person();
方法区加载类型信息(属性,方法)-->堆内存开辟空间,并给属性赋默认值,将p1对象名指向这个堆内存,如果new之后并给与赋值,赋值的对象是引用类型会在方法区常量池中创建应用类型的值,并指向堆内存中;如果为基本类型,则直接会在堆内存中存储

 

递归、值传递

java每次调用方法都会在栈中开辟一个独立的栈空间用于存储方法,因此能联想到递归的本质也是栈,每次调用自己也会在栈中开辟一个独立的栈空间存储;

1754029796414

 递归理解

1.执行一个方法就是在栈中,新开辟一个独立的栈空间

2.方法的变量是独立的,不会相互影响比如n变量(我们循环的调用方法自身,传入的变量为n,并非是一个n,而是在栈空间新开辟的独立栈空间,并在参数中传递了n,因为是两块不同独立栈空间所以两个n不是同一个n)

3.如果方法中使用的是引用类型变量(比如数组),就会共享该引用类型的数据

4.递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowErro

 

值传递:

  调用方法时参数是基本类型,每次都是在独立的栈空间复制过去一个基本类型而非变量本身,因此a调用b的方法,b将a的参数修改了不会影响a方法中的参数;

  参数是引用类型也是复制一个引用地址并非本身,不同的是引用类型会指向堆内存的实例,如果复制过来的引用地址对堆内存实例的属性进行了修改那么,会直接影响引用地址本身;如果复制过来的引用地址重新new了一个对象对其堆内存实例的属性进行修改和原本的引用地址不发生任何关系,不会改变原来引用地址的实例,举例:

  class Person{

    String name;

    public Person(String name){

      this.name = name;

    }

  }

  class Test{

    Person p = new P("张三");

    public void changeNew(Person p){p = new Person("李四")}

    public void changeAttr(Person p){p.setName = "李四"}

    public static void main(){

      Test t = new Test();

      changeAttr(t.p);   栈中changeAttr的 t 虽然修改了name值,但是本身却还是堆中的Person实例,只是修改了Person的属性

      changeNew(t.p); 栈中changeNew也修改了name值,但是确实通过new了个Person来实现的,这时main方法中的p的地址引用和changeNew的地址引用已经不是一个了,所以更加证明了Java的值传递

    }

  }

    

 

posted @ 2025-08-01 14:34  lds100115  阅读(4)  评论(0)    收藏  举报