方法调用机制

  1. Person p1 = new Person();
  2. int res = p1.getSum(10,20);
  3. System.out.println("值="+res);
  4. public int getSum(int num1,int num2){
  5. int res = num1 + num2;
  6. return res;
  7. }

image.png
1. 当程序执行到方法时,会在栈里单独开辟一个空间(这也是为什么swap无法使用的原因)。
2. 当方法执行完毕,或者执行到return语句时,就会返回。
3. 返回到调用方法的地方。
4. 返回后继续执行方法后面的代码。
5. 当main方法执行完毕,整个程序退出。

方法调用细节

1. 同一个类中的方法调用

直接调用即可。
image.png

2. 跨类中 A类调用B类的方法

需要通过新建对象,用 对象名.方法名(参数) 进行调用。(注意这种跨类调用要符合访问修饰符的限制)

  1. class first {
  2. public void Hi() {
  3. System.out.print("Hi!");
  4. }
  5. }
  6. class second {
  7. public void useA() {
  8. first a = new first(); //构建一个对象
  9. a.Hi(); //调用跨类的方法
  10. }
  11. }

3. 传递的参数为引用类型详解

  1. public class Practice {
  2. public static void main(String[] args) {
  3. Person a = new Person();
  4. a.age = 20; //初始化的属性值
  5. Test p = new Test();
  6. p.test01(a);
  7. System.out.print(a.age);
  8. }
  9. }
  10. class Person {
  11. int age;
  12. String name;
  13. }

对象的属性修改为另一个值:

  1. class Test {
  2. public void test01(Person b) {
  3. //传递一个对象(引用传递)
  4. b.age = 100000; //修改对象的属性
  5. }
  6. }

image.png
让对象指向null:

  1. class Test {
  2. public void test01(Person b) {
  3. b = null; //对象指向null
  4. }
  5. }

image.pngimage.png
初始化对象:

  1. class Test {
  2. public void test01(Person b) {
  3. b = new Person();
  4. }
  5. }

image.png
可以发现,当传入一个对象时,只有修改对象属性值才会生效,如果把对象指向null,或者让对象指向一个刚new的新对象,对原来的对象并没有什么影响。这是为什么呢?这里就需要考虑到方法调用机制了。
当调用test方法,传入一个对象时,实际上在栈里新开辟了一个空间,在这个空间里创建了一个指向Person对象的新指针 b(参考调用机制),接收传入对象的地址(实际上传入的是地址,注意与C++的引用不同,可以说类似于指针)。
然后 b 就指向堆区域的实际对象了,对 b 的属性进行修改,其实就是对实际对象进行修改。但是,如果把null赋给b,实际上只是 b 指向了null,对主函数声明的 a 没有任何影响,new也是同理,只有 b 指向了一个新的对象,而主函数声明的 a 仍然指向原来的对象。因此,最后输出的都是20。

4. 修改String属性的理解

  1. public static void main(String[] args) {
  2. Person a = new Person();
  3. Person b = new Person();
  4. a.name = "milan";
  5. b.name = "milan";
  6. System.out.println(a.name);
  7. System.out.println(b.name);
  8. b.name = "shang";
  9. System.out.println("==========");
  10. System.out.println(a.name);
  11. System.out.println(b.name);
  12. }

已知String是一个类,因此Person的name属性也是存放的地址。根据上面的代码,a和b的名字相同,name都指向”milan”。这时候修改b的name为”shang”,那么a的name属性会不会发生变化?
是不会的。修改b的name的实质,并不是修改对应地址的内容,而是重新开辟了一块区域,里面的内容是”shang”,然后把这个地址赋给b.name,对原先”milan”所在区域没有任何影响
image.png

递归调用机制

1. 输出递归

  1. class Person {
  2. public void test(int n) {
  3. if(n>2)
  4. test(n-1); //递归调用
  5. System.out.println("n的值为: " + n);
  6. }
  7. }
  8. //主函数 Person a = new Person(); a.test(4);

image.png
由于只是值传递,因此每一层中n的值并不会被下一层改变,最终结果为:
image.png

2. 阶乘

  1. public int factorial(int n) {
  2. //假设n为5
  3. if (n == 1) {
  4. return 1;
  5. } else {
  6. return factorial(n - 1) * n;
  7. }
  8. }

递归调用示意图如下:
image.pngimage.png

3. 递归重要规则

image.pngimage.png