方法的参数传递机制,调用方法的内存分析,成员变量和局部变量的区别,可变参数,方法的重载,String[] args命令行参数,递归方法(九)

422 阅读3分钟

方法的参数传递机制

1、方法的参数

​ 方法名后面()中称为参数。

2、分类

​ (1)形参 ​ 在声明/定义方法时,在()中写的参数,格式:(数据类型 形参名, 数据类型 形参名) 如果方法还没有调用,形参的值是不确定的,它相当于就是一个标识符,为了在方法体中使用外部传入的数据。 ​ (2)实参 ​ 在调用方法时,在()中写的数据(常量值、变量、表达式)

​ 表达式可以作为实参,但是不是所有的表达式都可以作为实参。

其中,调用没有返回值的方法的表达式是不能作为实参的,其他的都可以。

表达式:

  • 运算表达式:a+b,a<b,a=b等 数据(变量/常量)+运算符
  • 方法调用表达式 Math.random()也是一个表达式 System.out.println(1)也是一个表达式

语句:

  • 空语句
  • 表达式语句

不是所有表达式都可以作为语句,只有赋值表达式,和自增自减表达式,方法调用表达式可以加;称为语句 a = 1; a++; ++a; System.out.println(1); Math.random(); (3)复合语句 if.else,switch..case,for,while,do...while (4)跳转语句 break; continue; return 返回值; return ;

3、谁给谁传值?

实参负责给形参传值。

4、传的是什么值?

如果参数是基本数据类型,那么传的是数据值,即实参把数据值复制了一份给形参。 如果参数是引用数据类型,那么传的是地址值,即实参把地址值复制了一份给形参。

5、有什么区别?

当形参是基本数据类型时,形参的修改和实参无关。 形参是引用数据类型,形参修改了成员变量,会影响实参。因为实参把对象的首地址给形参了,实参和形参指向同一个对象。

方法调用内存分析

1、JVM中有一个叫做Java方法栈的内存。

方法栈中是以方法为单位分配的。 当方法调用时JVM就会在方法栈中给这个方法开辟一块独立的空间,用来存储方法的局部变量等信息,这个过程称为“入栈”。 当方法调用结束后,JVM会释放这个方法在栈中的内存,这个过程称为“出栈”。 栈是一种数据结构,这个结构有个特点,先进后出 或者 后进先出。

成员变量与局部变量的区别

1.变量:用来存储数据的,它本质上代表一块内存区域

2.内存的三要素:数据类型、变量名、变量值

内存有内存地址,时数字编号,对于程序员来说,如果针对内存地址进行编程的话,是非常麻烦的,因为内存地址不好记忆。

就如同网络中,每一台联网的机器都有一个IP地址,但是IP地址是数字,用户也不方便记忆,用域名:www.baidu.com 用字母/字符/单词来代替IP地址。

3.变量的使用分为两步:

(1)声明

(2)初始化

4.变量的声明的位置

(1)方法里面:局部变量

(2)类中方法外面:成员变量

成员变量又可以根据是否有static修饰,分为:静态变量和实例变量,(所谓的实例变量就是非静态的成员变量)。

5.区别

(1)声明的位置不同

(2)在内存中存储值的位置不同

​ 局部变量:栈中

​ 静态变量:方法去

​ 实例变量:堆

(3)初始化方式

​ 局部变量:必须手动初始化。

​ 成员变量:有默认值。

​ (静态变量:在类初始化的时候一起初始化)

​ (实例变量:new对象的时候)

(4)生命周期:

​ 局部变量:在方法被调用时初始化,每一次调用都是独立的。方法调用结束随着方法的出栈就结束了。生命周期比较短。

​ 静态变量:类加载后初始化时,所有对象共享的,随着类的卸载才结束。一般不会发生类的卸载。生命周期一般很长。

​ 实例变量:new对象时,而且每一个对象的实例变量都是独立的。当对象成为垃圾对象,被GC回收就结束了。生命周期中等。

(5)作用域

局部变量:从声明处开始,到他所属的{}结束

成员变量:本类中

(6)修饰符

局部变量:唯一可以加的修饰符时final,表示不能修改。

成员变量:public static final等,很多修饰符。

总结:

​ Java的数据类型分为:基本数据类型和引用数据类型

​ 数据类型可以用在:

(1)声明变量、局部变量、成员变量

(2)表示方法的返回值

(3)方法的形参列表中参数的类型,本质上形参是属于方法的局部变量的。

​ 基本数据类型:8种类型,可以支持很多运算符

​ 引用数据类型:支持的运算符有‘==’ ,‘==’比较的是对象的内存地址,其中字符串String比较特殊,多支持一个+,表示拼接。

​ 基本数据类型不允许'.'的使用。

​ 引用类型:可以使用'.';

​ '.'称为成员访问符, 一个引用数据类型的变量可以'.'出什么,看这个类型里面声明了什么成员。

可变参数

1.什么叫可变参数?

​ 当某个方法被调用时,某个形参对应的实参个数是可变的,称为可变参数。

2.为什么会有可变参数?

​ 例如:声明一个方法,实现一个功能:可以求任意个整数的和。

public static long sum(int...arr){
int sum = 0;
	for(int i = 0;i<arr.length;i++){
		sum += arr[i];
	}
	return sum;
}

当某个形参的个数不确定时,可以使用可变参数,可变参数当作数组来使用。

3.注意

(1)一个方法最多只能有一个可变参数

(2)可变参数必须时形参列表的最后一个

(3)调用方法时,可变参数对应的个数可以是0~n个

​ 非可变参数对应的实参个数必须与形参的个数一样

(4)在声明它的方法中,当作数组来处理就可以了。

方法重载

1.什么是方法的重载?

​ 在一个类中,声明两个或两个以上同名的方法,这些同名的方法形参列表不同,它们构成了方法的重载。

​ 形参列表不同,可以是数据类型不同,也可以是个数不同。

​ 方法的重载,和返回值类型无关。

或者换句话说,如果两个方法只有返回值不同,它们不属于方法的重载。

2.为什么需要方法的重载?

​ 方法:代表一个独立的可以复用的功能。

​ 方法名:要见名知意,能体现方法的功能。

​ 有时候我们实现一个功能有几种方式,而且几种方式分别适用于不同的情况,通常都是因为要传入的数据不同,我们就用同意个方法名,代表他们的功能是一样的,只是使用的情况不同。

比如:

System.out.println()方法就是使用了方法的重载,因为我们要输出的数据有很多种,可能使用一个int,可能是一个小数,可能是字符串等等。那么我们就需要定义很多个println方法,来适应不同的数据类型,但是他们的功能都一样。

3.如果存在两个或者多个重载的方法,怎么确定它是调用哪一个?

​ (1)先找最匹配的

​ 形参和实参的个数、类型完全一致

​ (2)找类型可以兼容的 或 个数满足可变参数

byte可以自动升级为short,int。。。

但byte[]不能自动升级为short[],int[]....

byte[]是引用数据类型

​ (3)如果(1)(2)找不到就报错

​ (4)如果找到了多个兼容的,也会报错。如:add(int... nums)和add(int a,int... nums);

add(int... nums)和add(int[] nums)不能算重载,因为底层都会把他们两个当作数组处理。

命令行参数(了解)

1.命令行参数是指main方法传入的参数,称为命令行参数。(String[] args)

2.如何给main方法传递参数

(1)在idea中

在idea中点击Run->Run/Debug Configurations...->Main Class(选主类:包含main方法的类,找到自己要传递main参数的类)->在Program arguments输入要传递的参数,参数之间使用空格分隔。

(2)在命令行中

​ 打开java所在文件的命令行,

	javac -d . 源文件.java

​	java 包.主类名 参数1 参数2 参数3.....

递归

1.什么是递归?

​ 一个方法直接或间接的调用自己就叫做递归。

2.为什么要使用递归?

​ 当完成方法的功能时,其中一个步骤的完成的代码和当前的方法是一样的,就可以调用自己来完成。

package com.dyy.exam;
/*计算n的阶乘*/
public class Exam4 {
    public static void main(String[] args) {
        System.out.println(jieCheng(5));
    }
    public static int jieCheng(int n){
        if(n==1){
            return 1;
        }
        return n*jieCheng(n-1);
    }
}

3.注意

(1)递归的过程必须有出口,满足if()不用递归,否则会出现死递归,发生栈内存溢出StackOverflowError