java内存结构
先通过一段代码段的运行及此project的运行的图解作为引导。
import Fourth.Time1;
import java.util.Scanner;
public class MyTime1
{
private static Time1 t0,t1,t2,t3,t4; //需在此处声明变量给Time1
public static void main(String[] args)
{
System.out.println("输入小时:分钟:秒:");
Scanner in=new Scanner(System.in);
int hour1=in.nextInt();
int minute1=in.nextInt();
int second1=in.nextInt();
t0=new Time1(); //第一个Time1方法
t1=new Time1(11); //第二个Time方法
t2=new Time1(22,22); //第三个Time1方法
t3=new Time1(11,22,33); //第四个Time1方法
t4=new Time1(hour1,minute1,second1); //自己添加的可以输入的Time1方法
System.out.println("t0="+t0.toString()); //调用toString方法时要注意在方法前加对象名
System.out.println("t1="+t1.toString());
System.out.println("t2="+t2.toString());
System.out.println("t3="+t3.toString());
System.out.println("t4="+t4.toString());
}
}
package Fourth;
public class Time1
{
private int hour;
private int minute;
private int second;
public Time1()
{setTime(0,0,0);}
public Time1(int hh)
{setTime(hh,0,0);}
public Time1(int hh,int mm)
{setTime(hh,mm,0);}
public Time1(int hh,int mm,int ss)
{setTime(hh,mm,ss);}
public void setTime(int hh,int mm,int ss)
{
hour=((hh>=0&&hh<=24)?hh:0);
minute=((mm>=0&&mm<=60)?mm:0);
second=((ss>=0&&ss<=60)?ss:0);
}
public String toString() //toString方法是Object里面为了方便所有类的字符串操作而特意加入的一个方法
{ //对toString方法进行重写
return ((hour<10?"0":"")+hour+":"+(minute<10?"0":"")+minute+":"+(second<10?"0":"")+second);
}
}
然后看一下运行结果。
然后我们通过这个project运行时内存图解来了解内存结构。
在这个图中
最开始是main方法压栈,并且输入了hour,minute,second三个int型的变量,这三个变量占据了堆中的地址,随后将这三个变量的地址赋值给hh,mm,ss。然后Time1方法压栈,并将变量赋值给Time1方法。接着setTime方法压栈,接受Time1的变量,并将其打印。随后println方法弹栈,setTime方法弹栈,Time1方法是个方法重载,于是t0弹栈,但t1压栈,最后运行t4后Time1弹栈。在程序最后main方法弹栈。
-
栈
栈最重要的特点是后进先出
一个线程运行时需要一个栈。
一个栈帧就对应着Java中一个方法的调用,即栈帧就是每个方法运行时需要的内存。每个方法运行时需要的内存一般有参数,局部变量,返回地址,这些都需要占用内存,所以每个方法执行时,都要预先把这些内存分配好。
当我们调用第一个方法栈帧时,它就会给第一个方法分配栈帧空间,并且压入栈内,当这个方法执行完了,就会把这个方法栈帧出栈,释放这个方法所占用的内存。 -
堆
通过new关键字创建的对象都会使用堆内存。
堆有垃圾回收机制,不再被引用的对象会被回收。 -
方法区
jdk1.8之前,方法区是用的堆内存,1.8之后,方法区用的操作系统内存。