(一)方法的相关概念
1.方法优点:提高代码复用性
2.方法本质:
方法就是一段代码片段,并且这段代码片段可以完成某个特定的功能,并且可以被重复的使用。
3.方法定义在类体当中,在一个类当中可以定义多个方法,方法的定义位置没有先后顺序,方法体当中不能再定义方法;方法体当中的java语句是自上而下的顺序执行。
(二)方法定义
1、方法怎么定义,语法结构
[修饰符列表] 返回值类型 方法名(形式参数列表){
方法体;
}
1.1 关于修饰符列表
1)可选项,不是必须的
2)方法的修饰符列表当中有static关键字,按如下形式调用该方法:
类名.方法名(实际参数列表);
1.2 返回值类型
1)什么是返回值?
一个方法是可以完成某个特定功能的,这个功能结束之后大多数都是需要返回最终执行结果的,执行结果可能是一个具体存在的数据,而这个具体存在的数据就是返回值。
2)返回值类型是什么?
返回值是一个具体存在的数据,数据都是有类型的,此处需要指定的是返回值的具体类型。
3)返回值类型都可以指定哪些类型呢?
Java的任意一种类型都可以,包括基本数据类型和所有的引用数据类型。
4)也可能这个方法执行结束之后不返回任何数据,java中规定,当一个方法执行结束之后不返回任何数据的话,返回值类型位置必须编写: void 关键字。
5)返回值类型若不是void,表示这个方法执行结束之后必须返回一个具体的数值,当方法执行结束的时候没有返回任何数据的话编译器报错。
返回值代码的编写:
return 值;
并且要求"值"的数据类型必须和"方法的返回值类型"一致。
6)返回值类型是void的时候,在方法体当中不能编写"return 值;"这样的语句,但要注意可以编写"return;"这样的语句。
7)只要带有return关键字的语句执行,return语句所在的方法结束【不是JVM结束,是return所在的方法结束】。
1.3 方法名
1)只要是合法的标识符就行
2)方法名最好见名知意
3)方法名最好是动词
4)方法名首字母要求小写,后面每个单词首字母大写
1.4 形式参数列表,简称形参
1)形参是局部变量: int a,...
2)形参的个数可以有:0~N个
3)多个形参之间用逗号隔开
4)形参中起决定性作用的是形参的数据类型,形参的名字就是局部变量的名字。
5)方法在调用的时候,实际给这个方法传递的真实数据被称为实际参数,简称实参。
6)实参列表和形参列表必须满足:
①数量相同
②类型对应相同【类型不同可以进行类型转换:自动和强制类型转换】
1.5方法体
方法体必须由大括号括起来,方法体当中的代码有顺序,遵循自上而下的顺序依次执行。
2、方法的调用
1)方法的调用不一定在main方法当中,也可以在其他的方法当中。
2)方法的修饰符当中有static关键字时:
①调用的语法规则:
类名.方法名(实参列表);
②调用方法的时候如果负责调用的方法和被调用的方法在同一个类体当中的调用规则:
方法名(实参列表);【省略了“类名.”】
3、定义class的注意事项:
建议在一个java源文件当中只定义一个class。
4、方法的返回值
4.1 在"同一个作用域"当中,return语句下面不能编写任何代码,因为这些代码永远都执行不到,所以编译报错。
4.2 一个方法有返回值的时候,当我们调用这个方法的时候,方法返回了一个值,对于调用者来说,这个返回值可以选择接收,也可以选择不接收【大部分时候是选择接收的】。
【练习一:方法的调用】
代码如下:
public class Test{
public static void main(String[] args){
System.out.println("求素数:");
//编译正确
Test.dosome(10L,20L);
//存在自动类型转换:int--->long
Test.dosome(10,20);
//存在强制类型转换
Test.dosome((long)3.5,(long)2.9);
}
public static void dosome(long a,long b){
System.out.println(a+" + "+b+" = "+(a+b));
}
}
【练习二:方法的返回值】
代码如下:
public class Test{
public static void main(String[] args){
//采用变量接收
//变量的数据类型需要和返回值的数据类型相同,或者可以自动类型转换。
int shang01 = divide(10,3);
System.out.println(shang);
//自动类型转换
long shang02 = divide(10,3);
System.out.println(shang);
//直接输出
System.out.println(divide(10,3));
}
public static int divide(int a,int b){
return a/b;
}
}
【练习三:return关键字】
代码如下:
public class Test01{
public static void main(String[] args){
System.out.println(test_Return01);
System.out.println(test_Return02);
}
/*
编译报错:缺少返回语句,一下程序编译器认为无法百分之百保证"return 1;"会执行;
public static int test_Return00(){
int a = 10;
if(a > 10){
return 1;
}
}
*/
//以下程序可以保证“return 1;”或“return 0;”执行,编译通过。
public static int test_Return01(){
int a = 10;
if(a > 10){
return 1;
}else{
return 0;
}
}
//test_Return02和test_Return01方法执行结果完全相同
public static int test_Return02(){
int a = 10;
if(a > 10){
return 1;
//这里不能编写代码。编译错误,因为是无法访问的语句
//System.out.println("hello!");
}
//这里的代码可以执行到
System.out.println("hello!");
return 0;
//这里不能编写代码。编译错误,因为是无法访问的语句
//System.out.println("hello!");
}
public static int test_Return03(){
return 10 > 3 ? 1 : 0;
}
public static void test_Return04(){
for(int i = 1;i<=10;i++){
if(i == 5){
//return; //不是终止for循坏,终止的是test_Return04()方法
break; //终止的是for循环
}
System.out.println("i ---> "+i);
}
System.out.println("hello world");
}
}
public class Test02{
public static void main(String[] args){
for(int i=10;i>0;i--){
if(i == 2){
return;//结束的是main方法
}
System.out.println("data:--->"+i);
}
System.out.println("Execute Here!");
//编译报错:返回值类型是void,不能返回值。
//return 100;
}
}
(三)、方法执行过程中,在JVM中内存的分配
1、方法只定义,不调用,是不会执行的,并且在JVM中也不会给该方法分配“运行所属”的内存空间。
只有在调用这个方法的时候,才会动态的给这个方法分配所属的内存空间。
2、在JVM内存划分上有这样三块主要的内存空间(当然除了这三块之外还有其他的内存空间)
① 方法区内存
② 堆内存
③ 栈内存
3、关于“栈”数据结构
1)栈:stack,是一种数据结构。
2)数据结构反应的是数据的存储形态。
3)数据结构是独立的学科,不属于任何编程语言的范畴,只不过在大多数编程语言当中要使用数据结构。
4)作为程序员需要提前精通:数据结构+算法【计算机专业必修的一门课程】。
5)常见的数据结构:
①数组
②队列
③栈
④链表
⑤二叉树
⑥哈希表/散列表
......
4、方法代码片段存在哪里?方法执行的时候执行过程中的内存在哪里分配?
1)方法代码片段属于.class字节码文件的一部分,字节码文件在类加载的时候,将其放到了方法区当中,所以JVM中的三块主要的内存空间中方法区内存最先有数据,存放了代码片段。
2)代码片段虽然在方法区内存当中只有一份,但是可以被重复调用。
每一次调用这个方法的时候,需要给该方法分配独立的活动场所,在栈内存中分配。【栈内存中分配方法运行所属的内存空间】
5、方法调用的瞬间,会给该方法分配内存空间,会在栈中发生压栈动作,方法执行结束之后,给该方法分配的内存空间全部释放,此时发生弹栈动作。
1)压栈:给该方法分配内存
2)弹栈:释放该方法的内存空间
6、局部变量在“方法体”中声明,在运行阶段局部变量的内存在栈中分配。
7、方法执行内存分析
`
【代码如下】
【Notes】
①只要是类名就一定是标识符,我们自定义的类Method_Memory_Analyze是标识符,JavaSE类库中自带的带,例如:String.class、System.class,这些类的类名也是标识符。
②方法调用的时候,在参数传递时,实际上传递的是变量中保存的那个"值"传过去了。
public class Method_Memory_Analyze{
public static void main(String[] args){
int a = 10;
int b = 20;
int retValue = sumInt(a,b);
System.out.println("retValue = " + retValue);
}
public static int sumInt(int i,int j){
int result = i + j;
int num = 3;
int retValue = divide(result,num);
return retValue;
}
public static int divide(int x,int y){
int z = x / y;
return z;
}
}
(四)、方法重载
1、方法重载的定义
方法重载又叫overload,是方法名称进行重用的一种技术形式,其最主要的特点为“方法名称相同,参数的数据类型或个数不同”,在调用时会根据传递的参数类型和个数不用而执行不同的方法体。
2、方法重载的优点
1)程序员调用方法的时候,比较方便,虽然调用的是不同的方法,但是就感觉在使用一个方法一样,不需要记忆更多的方法名。
2)代码美观
3、什么时候考虑使用方法重载
功能相似的时候,尽可能让方法名可以相同
功能不同的时候,尽可能让两个方法的名字不同
4、什么条件满足之后构成了方法重载?
1)在同一个类当中
2)方法名相同
3)参数列表不同
①数量不同
②顺序不同
③类型不同
5、方法重载和什么有关系?和什么没有关系?
①方法重载和方法名+参数列表有关系
②方法重载和返回值类型无关
③方法重载和修饰符列表无关
【代码如下】
public class Method_Overload—_Test01{
public static void main(String[] args){
//调用方法的时候就像在使用一个方法一样
//参数的类型不同,对应调用的方法不同。
//此时区分方法不再依靠方法名了,依靠的是参数的数据类型。
System.out.println(sum(1,2));
System.out.println(sum(1.0,2.0));
System.out.println(sum(1L,2L));
}
//以下三个方法构成了方法的重载机制
public static int sum(int a,int b){
System.out.println("sum(int,int)");
return a + b;
}
public static int sum(long a,long b){
System.out.println("sum(long,long)");
return a + b;
}
public static int sum(double a,double b){
System.out.println("sum(double,double)");
return a + b;
}
}
【代码如下】
public class Method_Overload_Test02{
public static void main(String[] args){}
//以下两个方法构成重载
//参数列表中的参数数量不同
public static void m1(){}
public static void m1(int a){}
//以下两个方法构成重载
//参数列表中的参数顺序不同
public static void m2(int a,double b){}
public static void m2(double a,int b){}
//以下两个方法构成重载
//参数列表中的参数数据类型不同
public static void m3(int x){}
public static void m3(double x){}
//编译错误:以下两个方法不构成重载,是发生了方法重复了
//public static void m4(int a,int b){}
//public static void m4(int b,int a){}
}
【代码如下】
public class Method_Overload_Test02{
public static void main(String[] args){
T.p("hello World!");
}
}
public class T{
public static void p(byte b){
System.out.println(b);
}
public static void p(char b){
System.out.println(b);
}
public static void p(short b){
System.out.println(b);
}
public static void p(int b){
System.out.println(b);
}
public static void p(float b){
System.out.println(b);
}
public static void p(double b){
System.out.println(b);
}
public static void p(long b){
System.out.println(b);
}
public static void p(boolean b){
System.out.println(b);
}
public static void p(String b){
System.out.println(b);
}
}