Java学习笔记整理
在学习这一部分之前,需要明确几个问题:
1.什么是函数?
2.Java中怎么定义函数?
3.Java中怎么调用函数?
4.函数调用的内存模型分析(压栈)-- 内存的分析
5.函数的分类:
(1)返回值
(2)参数
6.值传递和引用传递问题
7.函数重载
8.递归的概念
1.什么是函数
函数:具有名称为了实现某一特定功能的代码的集合。封装代码,提高代码的复用性。
2.Java中怎么定义函数?
语法结构:
访问修饰符 static 返回值的类型 函数名称([参数名称]){
// 函数体
[return 返回值;]
}
函数必须定义在类里,不能在main函数里
3.函数的分类
(1)void表示没有返回值;如果需要返回值,则需要在void位置写明返回值类型并在参数名称在中声明参数类型。
(2)如果不调用,函数不会执行;调用函数时如有参数,需要在括号内写明。
4.函数调用
举例:
(1)say函数:打印一句话
(2)showInfo函数:显示自己的基本信息
public class Test{
// main函数是程序的入口,必须这样写
public static void main(String[] args){
// 静态(static)函数中只能调用静态函数,静态函数中,无法调用非静态函数
// 调用函数
say();
showInfo();
}
// 定义了一个say的函数
public static void say() {
System.out.println("hello,I`m a function.");
}
static void showInfo() {
System.out.println("我叫ABC");
System.out.println("456");
}
}
如果函数增加了参数,在主函数内调用时也要增加相应的参数。
public class Test{
public static void main(String[] args){
showInfo("王力宏",20,"陕西西安");
}
static void showInfo(String name,int age,String address) {
System.out.println("我叫"+ name);
System.out.println("我今年"+ age +"岁");
System.out.println("我住在"+ address);
}
}
5.Java的函数分类
判断方式:通过是否存在参数分为有参函数和无参函数,是否存在返回值分为有返回值的函数和无返回值的函数。
(1)加法运算
public class Test{
public static void main(String[] args){
int res = add(10,50);
System.out.println(res);
}
public static int add(int x,int y) {
// 函数中,执行到return关键字,函数直接返回
return x + y;
}
}
(2)判断质数
import java.util.Scanner;
public class Test{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个数:");
int num = sc.nextInt();
boolean flag = isPrimer(num);
if (flag) {
System.out.println("该数是质数");
} else {
System.out.println("该数是合数");
}
}
public static boolean isPrimer(int num) {
for (int i = 2; i < num; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
}
在函数中,定义的参数可以和主函数中定义的参数使用相同的字符,它们分属不同的作用域。
6.内存的调用分析
栈stack:一种线性结构,先进后出FILO(后进先出LIFO),
堆heap:内存中最大的区域,函数存储在堆里
代码区:
数据区:
int a = 10; add(a,20);
在栈中创建一个变量a,存储一个数据10;在堆中储存函数add。同时,在栈中储存着一个add变量,里面储存着函数add的地址,即栈中的add指向内存中的函数add。当函数调用时,栈中的add找到函数,将函数中的程序压到栈中,这个过程即压栈的过程,压栈(put)是将堆里储存的函数在栈中执行的过程。当函数调用完之后,会出栈(弹栈pop)。
public class Test{
public static void main(String[] args){
System.out.println(a);
}
public static int add(int x,int y) {
int a = 10;
return x + y;
}
}
Q:函数中定义的变量,主函数中能否调用?
A:在以上程序中,函数中定义了一个变量a,数据为10,它是在堆中定义的,属于局部变量。当执行压栈的过程,int a = 10从堆中进入栈,函数调用完成后,这部分内存随着弹栈被回收,因此主函数中不能调用该变量。
在上面的程序中提到了局部变量这一概念,局部变量是定义在函数内部的变量,必须初始化(赋值),否则无法使用。
7.函数重载
重载(overload)是多个函数形成的一种关系,函数名称相同,参数的类型或者参数的个数不同。该现象只存在于强数据类型语言中,弱数据类型语言中不存在(如:JavaScript、PHP、Python)。
public static int add(int x,int y) {
return x + y;
}
public static int add(int x,int y,int z) {
return x + y + z;
}
以上两个函数构成重载,我们可以套入参数测试一下:
public class Test{
public static void main(String[] args){
System.out.println(add(5,4));
}
public static int add(int x,int y) {
System.out.println(111);
return x + y;
}
public static int add(int x,int y,int z) {
System.out.println(222);
return x + y + z;
}
}
输出结果:
如果将参数由两个改为三个:
public class Test{
public static void main(String[] args){
System.out.println(add(5,4,10));
}
public static int add(int x,int y) {
System.out.println(111);
return x + y;
}
public static int add(int x,int y,int z) {
System.out.println(222);
return x + y + z;
}
}
输出结果:
public static int add(int x, int y) {
return x + y;
}
public static int add(int y, int x) {
return x + y;
}
以上两个函数参数类型和个数相同,不构成重载。
public static int add(int x, int y) {
return x + y;
}
public static double add(double a, int b) {
return x + y;
}
以上两个函数,函数名称相同,参数类型不同,构成重载。
public static double add(double a, int b) {
return x + y;
}
public static double add(int b,double a,) {
return x + y;
}
函数名相同,参数类型不同,构成重载。
需要注意,函数重载和重写是不同的概念。
8.递归的使用
递归(recursive)是函数自身调用自身的现象,是一种分治思想的体现。
递归的必要条件:
(1)函数必须自身调用自身。
(2)递归必须要有终止条件;若无终止条件,递归是一个死循环----调用函数的过程中,因为递归的关系,每次执行完函数的程序之后,函数在栈空间内再次调用自身,直达栈空间消耗完为止,JVM抛出StackOverflowError异常。
以下是递归的一个例子:
public class Test{
public static void main(String[] args){
int sum = getSum(100);
System.out.println("1~100的和是"+ sum);
}
// 使用递归完成1 ~ 100的和
public static int getSum(int num) {
if (num <= 1) {
return 1;
}
return num + getSum(num - 1);
}
}
将参数改为20000,执行程序:
栈空间消耗完了,报错。
栈空间可以修改,先编译,然后
>java -Xss空间大小 文件名
(3)递归实例
斐波那契数列:从第三个数开始,每一个数的值是前两项之和。
使用递归,求第N项的对应的值(n > 2)
要求:第一项是1, 第二项的值是2。
import java.util.Scanner;
public class Test{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入项数:");
int num = sc.nextInt();
int res = Fibonacci(num);
System.out.println(res);
}
public static int Fibonacci(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
}