Java,程序执行,函数调用,传值调用和引用调用,递归调用

createh53周前 (12-05)技术教程18

程序执行&函数调用

1、程序执行的基本原理

CPU中包含指令指示器,指向下一条要执行的指令,这个指令要么是顺序执行,要么是进行跳转(有条件跳转或无条件跳转)。

程序从main()开始顺序执行,函数调用可以看作一个无条件跳转,跳转到对应函数的指令处开始执行,碰到return语句或函数结尾时,再执行一次无条件跳转,跳转回调用方,执行调用函数后的下一条指令。

2、栈:函数调用的约定

函数调用过程中,函数的调用方和函数自己是如何存放和使用这些数据,达成一个一致的协议或约定。存放这些数据的内存有一个相同的名字,叫栈。

栈是一块特别约定的内存,先进后出,往栈里添加数据称为入栈,最下面的栈称为栈底,最上面的栈称为栈顶,从栈顶拿出数据通常称为出栈(弹栈)。栈一般是从高位地址向低位地址扩展,栈底的内存地址是最高的,栈顶的是最低的。

3、函数的调用

计算机系统主要用栈来存放函数调用过程中需要的数据,包括:参数,返回地址,以及函数内定义的局部变量。返回值不太一样,可能放在栈中,有的系统使用CPU内的一个存储器来存储返回值。

函数调用,可以简单地认为存在一个专门的返回值存储器。main()的相关数据放在栈的最下面,每调用一次函数,都会将相关函数的数据入栈,调用结束会出栈。

Java中的函数调用

形参====>形式参数

在函数定义中出现的参数可以看做是一个占位符,它没有数据,只能等到函数被调用时接收传递进来的数据。

实参====>实际参数

函数被调用时给出的参数包含了实实在在的数据,会被函数内部的代码使用。

模型图:

对应代码:

public class FunctionDemo {

    public static void method2() {
        System.out.println("method2()");
    }

    public static void method1() {
        System.out.println("method1()");
    }


    public static void main(String[] args) {
        System.out.println("main()");
        method1();
    }

}

Java中传值调用和引用调用

传值调用&&引用调用

实参====>形参(实参传数值给形参,形参获得实参的数值),改变形参不改变原来的实参,因为两者在获得值之后没有任何关系。

实参====>形参(实参传地址给形参,形参获得实参的地址),改变形参会表现在存储单元中,实参则会被改变。

案例代码

/**
 * 传值调用和引用调用
 */
public class FunctionInvokeTest {


    public static void main(String[] args) {
        //===================================================================//
        // 基本数据类型:传值调用
        //===================================================================//
        int i = 99999;
        plus(i);
        System.out.println("传值调用结果: " + i);
        //===================================================================//
        // 包装数据类型:传值调用
        //===================================================================//
        Integer I = new Integer(99999);
        plus(I);
        System.out.println("传值调用结果: " + I);
        //===================================================================//
        // 字符串类型:传值调用
        String str = "aaaaa";
        plus(str);
        System.out.println("传值调用结果: " + str);
        //===================================================================//
        // 引用调用
        //===================================================================//
        ObjPlus o = new ObjPlus();
        o.i = 99999;
        o.I = 99999;
        o.str = "aaaaa";
        plus(o);
        System.out.println("引用调用结果: " + o.i);
        System.out.println("引用调用结果: " + o.I);
        System.out.println("引用调用结果: " + o.str);
        //===================================================================//
        // The end
        //===================================================================//
    }

    /**
     * @param i
     */
    public static void plus(int i) {
        i = i + i;
        i = i + 11111;
    }

    /**
     * @param I
     */
    public static void plus(Integer I) {
        I = I + I;
        I = I + 22222;
    }

    /**
     * @param str
     */
    public static void plus(String str) {
        str = str + str;
        str = str + "33333";
    }

    /**
     * @param o
     */
    private static void plus(ObjPlus o) {
        o.i = o.i + o.i;
        o.I = o.I + o.I;
        o.str = o.str + o.str;
    }

}

class ObjPlus {
    public int i;
    public Integer I;
    public String str;
}

Java中递归调用

递归本质:程序调用自身的编程技巧叫做递归( recursion)。

递归作为一种算法在程序设计语言中广泛应用,一个过程或函数(方法)在其定义或说明中有直接或间接的调用。

用自身的一种方法,通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。

案例代码:

import java.io.File;

public class FunctionRecursiveTest {

    public static void main(String[] args) {
        int size = 10;
        int start = 1;

        int result = 0;
        for (int i = start; i < size; i++) {
            result = result + i;
        }
        System.out.println("循环结果: " + result);
        // 递归调用是一种特殊的嵌套调用,是某个函数(方法)自己调用自己
        System.out.println("递归结果: " + forPlus(start, size));

        // 递归调用Windows目录
        files(new File("D://"), 0);
    }

    /**
     * @param i
     * @param size
     * @return
     */
    public static int forPlus(int i, int size) {
        int result = 0;
        if (i < size) {
            result = i + forPlus(i + 1, size);
        }
        return result;
    }

    /**
     * @param file
     */
    public static void files(File file, int deep) {
        if (file.isDirectory()) {
            File[] subFiles = file.listFiles();
            if (subFiles != null) {
                for (File subFile : subFiles) {
                    files(subFile, deep + 1);
                }
            }
        } else {
            for (int i = 0; i < deep; i++) {
                System.out.print("-");
            }
            System.out.println(file.getAbsolutePath());
        }
    }

}

相关文章

C语言函数递归调用理解

函数除了在其他地方被调用之外,也可以自己调用自己(好家伙,套娃是吧),这种玩法我们称为递归。#include <stdio.h> void test(){ printf("...

5.3 函数调用及执行过程

5.3 函数调用及执行过程上一节讲解了函数的定义方法和函数的一般设计原则。本讲将介绍如何使用自定义函数,以及在调用函数时的参数传递方法和函数的执行过程。定义好的函数仅是一段不会被执行的代码,静静地呆着...

Java 到底是值传递还是引用传递?

作者:Hollis关于这个问题,引发过很多广泛的讨论,看来很多程序员对于这个问题的理解都不尽相同,甚至很多人理解的是错误的。还有的人可能知道Java中的参数传递是值传递,但是说不出来为什么。在开始深入...

java8精华-函数式编程-Predicate(四)

在之前的文章Java8精华-函数式编程(一)读完这篇,你将彻底理解Java8精华-函数式编程-Consumer(二)java8精华-函数式编程-BiConsumer(三)我们已经了解了Consumer...