Java基础 方法-方法执行的内存空间

鳄鱼君

发表文章数:642

热门标签

, , , , ,

Vieu四代商业主题

高扩展、安全、稳定、响应式布局多功能模板。

¥69 现在购买
首页 » Java » Java基础 方法-方法执行的内存空间

现在我们需要计算两个int变量的和:

public class MethodTest
{
	public static void main(String[] args){
		int a = 10;
		int b = 20;
		int c = a + b;
		System.out.println(a + "+" + b + "=" + c);
	}
}

方法

如果我们要计算的int类型很多,呢么就会出现很多重复的代码,这时候就可以单独定义一个方法:

public class MethodTest
{
        //类体
	public static void main(String[] args){
		//计算两个int类型数据的和
		MethodTest.sumInt(10,20);
	}

	//定义一个方法,实现求和
	public static void sumInt(int a,int b){
		int c = a + b;
		System.out.println(a + "+" + b + "=" + c);
	}
}

需要注意的是方法定义在类体中,在一个类当中可以定义多个方法,方法编写的位置没有先后顺序,在方法体当中不能定义方法

会定义方法,我们再来看一下定义方法的语法结构:

[修饰符列表] 返回值类型 方法名(形式参数列表){
    方法体;
}
  1. 修饰符列表:可选项,例如public static。方法的修饰符列表当中有static关键字的时候,调用方法的时候使用:类名.方法名(实际参数列表)
  2. 返回值类型:方法结束之后返会的执行结果,这里就是指定返回值的具体类型,包括基本数据类型和引用数据类型!返回值类型如果不是void,表示这个方法结束之后必须返回一个具体的数值,当方法执行结果结束的时候,没有返回任何数据的话,编译器就会报错!return 值;中的“值”的数据类型需要跟“返回值的数据类型”一致,否则编译器报错!
  3. 返回值类型是void的时候,在方法体中不能写return 值;,但是可以写return;
  4. 只要有return关键字的语句执行,return语句所在的方法结束,不是JVM结束!
  5. 方法名:合法的标识符,最好是动词,首字母小写,后面每个单词首字母大写!
  6. 形式参数列表:简称形参,是局部变量,例如int a,个数可以是0~n个,多个形参之间用逗号隔开,形参的数据类型起决定性作用,例如int
  7. 方法定义
    public static int sum(int a,int b){
    }
    
    方法调用
    sum("abc","abc"); //编译报错
    sum(10,20); //实参列表
  8. 实参列表和形参列表数量必须相同,类型一致!
  9. 方法体:必须要有大括号括起来,方法体有java语句构成,每个java语句以分号结尾!

再来看一下具体的代码分析:

/*	
	public 公开的
	class  定义类
    MethodTest 类名
*/

//定义一个公开的类,类名MethodTest,由于是公开的类,源文件的名字必须是MethodTest
public class MethodTest  
{
	//类体,类体中不能直接编写java语句,除声明变量之外
	//方法出现在类体当中


	//方法
	//public 公开的
	//static  静态的
	//void    方法执行结束之后不返回任何数据
	//main    方法名,主方法
	//(String[] args) 形式参数列表,String[] 是一种应用数据类型,args是一个局部变量的变量名
	//所以args这个局部变量的变量名是随意的
	//主方法就需要按照固定的编写方式,这是程序的入口
	public static void main(String[] args){
		//这里的程序一定会执行,main方法是JVM负责调用的,是一个入口
		//可以在这里编写java语句调用其它方法
		//调用MethodTest的sum方法,传递两个实参
                //一个方法可以被重复使用,重复调用
		MethodTest.sum(10,20);
		
	}

	//自定义方法,不是程序的入口
	//计算两个int类型数据的和,不要求返回结果,但是要求将结果输出到控制台
	//修饰符列表 public static
	//返回值类型 void
	//形式参数列表 (int a,int b)
	//方法体 输出计算结果
	public static void sum(int a,int b){
		System.out.println(a + "+" + b + "=" + (a + b));
	}
}

方法调用的时候,实参和形参要求个数对应相同,数据类型对应相同,类型不同的时候,要求能够进行自动类型转换:

public class MethodTest  
{
	
	public static void main(String[] args){
		//编译错误,参数数量不同
		//MethodTest.sum();

		//编译错误,实参和形参的类型不一致
		//MethodTest.sum(true,false);
		
		//编译报错,大容量转换为小容量,损失精度
		//MethodTest.sum(10L,20L);

		MethodTest.sum((int)10.0,20);

	}

	public static void sum(int a,int b){
		System.out.println(a + "+" + b + "=" + (a + b));
	}
}

方法的修饰符列表当中有static关键字,调用方法:类名.方法名(实参列表)\;,但是在同一个类当中可以省略类名.

public class MethodTest  
{
	
	public static void main(String[] args){
		//
		sum(10,20);

		//调用其它类中的方法
		//省略 类名.
		//编译报错,找不到类中的方法
		//默认从当前类MethodTest中寻找方法,当前类中方法不存在
		doSome();
	}

	public static void sum(int a,int b){
		System.out.println(a + "+" + b + "=" + (a + b));
	}
}

class A
{
	public static void doSome(){
		System.out.println("dosome.......");
	}
}

但是一般一个java源文件中只定义一个class!main方法最先被调用,main方法也是最后一个结束:

public class MethodTest  
{
	
	public static void main(String[] args){
		System.out.println("main begin");
		m1();
		System.out.println("main over");
	}

	public static void m1(){
		System.out.println("m1 begin");
		m2();
		System.out.println("m1 over");
	}

	public static void m2(){
		System.out.println("m2 begin");
		System.out.println("m2 over");
	}
	/*
		main begin
		m1 begin
		m2 begin
		m2 over
		m1 over
		main over		
	*/
}

我们定义一个计算两个int类型数据的商的方法,该方法的返回值类型不是void:

public class MethodTest  
{
	
	public static void main(String[] args){
		
	}

	//计算两个int类型数据的商
	//该方法没有void,所以方法必须要包含return 值,没有编译器报错

	//编译报错,没有返回语句
	public static int merchant(int a,int b){

	}
	//编译报错,缺少返回值
	public static int merchant(int a,int b){
		return;
	}
	//编译报错,返回类型不一致,定义的时候要求返回int类型,此时返回布尔类型
	public static int merchant(int a,int b){
		return true;
	}

}

正确的写法:

public class MethodTest  
{
	
	public static void main(String[] args){
		//调用方法,不接收返回值
		merchant(10,20);
		//一个方法有返回值的受,我们调用这个方法,方法会返回一个值
		//这个返回值可以选择接收,也可以不接收
		
		//接收返回值
		//采用变量接收,变量的数据类型要和返回值的数据类型相同
		int c = merchant(30,10);
		System.out.println(c);

		System.out.println(merchant(20,20));
	}

	public static int merchant(int a,int b){
		System.out.println("鳄鱼君");
		return a/b;
	}

}

带有return关键字的java语句只要执行,所在的方法执行结束。在同一个作用域中,return语句下面不能编写任何代码,因为这个代码不会执行,编译报错:

public class MethodTest  
{
	
	public static void main(String[] args){
		//调用方法m(),注意括号
		System.out.println(m());
	}

	//编译报错,缺少返回语句,编译器认为无法百分百保证return 1;
	/*public static int m(){
		int a = 10;
		if (a > 3)
		{
			return 1;
		}
	}*/

	public static int m(){
		int a = 10;
		if (a > 3)
		{
			return 1;
		}else{
			return 0;
		}

	}
        //也可以这样写
	public static int m(){
		//条件为真返回1,否则返回0
		return 10 > 3 ? 1:0;
	}
}

在返回值类型是void的方法中使用return;语句,主要作用就是终止当前方法的执行:

public class MethodTest  
{
	
	public static void main(String[] args){
		m();

		b();
	}

	//编译报错,但对于结果类型为空的方法,无法返回值
	/*public static void m(){
		return 0;
	}*/

	public static void m(){
		return;
	}

	public static void b(){
		for (int i=0; i<10 ; i++)
		{
			if (i == 5)
			{
				return; //终止b方法,不是for循环,此时不会打印 鳄鱼君
				//break;//终止for循环,此时会打印 鳄鱼君
			}
			System.out.println(i);
		}

		System.out.println("鳄鱼君");
	}
}

在main方法里面,return;具有同样的效果:

public class MethodTest  
{
	
	public static void main(String[] args){
		for (int i = 0; i<10 ; i++)
		{
			if (i>5)
			{
				return; //结束main方法
			}
			System.out.println(i);
		}
		System.out.println("鳄鱼君");
		
		//编译报错,返回值类型是void,不能返回值
		//return 1;
	}

}

方法在执行过程当中,JVM的内存是如何分配和变化的?

  1. 方法只定义,不调用,是不会执行的,并且在JVM中也不会给该方法分配“运行所属”的内存空间,只有在调用这个方法的时候,才会动态的给这个方法分欸所属的内存空间。
  2. 在JVM内存划分上有三种主要的内存空间:方法区内存、堆内存、栈内存

数据结构:

  1. 栈stack,是一种数据结构()
  2. 数据结构反应的是数据的存储形式
  3. 数据结构是独立的学科,不属于任何编程语言的范畴
  4. 常见的数据结构:数组、队列、栈、链表、二叉树、哈希表/散列表

方法执行的时候内存在哪里分配?方法代码片段在哪里?

方法代码片段属于.class字节码文件的一部分,字节码文件在类加载的时候,将其放到了方法区当中,所以JVM中的三块主要的内存空间中方法区内存最先有数据,存放代码片段 。代码片段虽然在方法区内存当中只有一份,但是可以被重复调用。每一次调用这个方法的时候,需要给该方法分配独立的活动场所,在栈内存中分配。

一句话:方法在调用的时候,会给该方法分配对立的内存空间,子啊栈中分配,此时发生压栈/入栈/lpush,方法执行结束之后,该方法分配的内存空间全部释放,此时发生弹栈/出栈/pop动作
压栈:给方法分配内存
弹栈:释放该方法的内存空间

局部变量在方法体中声明,局部变量运行阶段内存在栈中分配

再来分析以下,例如以下代码:

public class MethodTest  
{
	
	public static void main(String[] args){
		m();
	}

	public static void m(){
		int i = 1;
	}

}

代码最先存储在方法区内存中,程序会执行main主方法,然后执行m方法,只要开始执行,就会在栈内存中中分配空间,这里先给main分配内存,main内存中包含m方法,执行m的时候又会给m分配内存空间,这样main方法就在栈内存的底部,m方法在main方法的上面,栈遵循先进后出/后进先出,呢么main先调用就会最后结束,m方法是最后调用的,也就是会最先结束,因为在栈中m在main的上面。m方法中定义了一个变量i,属于局部变量,存储在栈中,只要调用m方法就是压栈,m方法执行结束,内存空间全部释放,就是弹栈。m方法执行结束,此时main方法在栈中就是最上面的一个,即栈顶元素,栈顶元素具有活跃的权力,main继续执行,执行结束之后,释放。

未经允许不得转载:作者:鳄鱼君, 转载或复制请以 超链接形式 并注明出处 鳄鱼君
原文地址:《Java基础 方法-方法执行的内存空间》 发布于2020-08-03

分享到:
赞(0) 赏杯咖啡

评论 抢沙发

2 + 3 =


文章对你有帮助可赏作者一杯咖啡

支付宝扫一扫打赏

微信扫一扫打赏

Vieu4.6主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。
切换注册

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册