JVM虚拟机

参考链接:https://blog.csdn.net/kuangay/article/details/81485324
首先,.java(.java)文件经过javac编译,成为字节码(.class)文件,后通过jvm经过操作系统联系硬件。

JVM的组成

jvm由三部分组成:类装载子系统(加载.class文件),运行时数据区,执行引擎(进行垃圾回收操作【GC】)。其中重点介绍运行时数据区。运行时数据区分为五个部分:堆区,方法区,栈区,本地方法栈,程序计数器(其中堆区与方法区所有线程共享,栈区,本地方法栈,程序计数器每个线程之间独立开辟)

  • 栈区:存储线程在运行期间产生的局部变量,每个线程分配一块栈空间。一个栈区含有三部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。每个栈帧含有四个部分:局部变量表,操作数栈,动态链接,方法出口,动态链接。
    栈帧:每一个方法的范围为一个栈帧
    局部变量表: 存储的为局部变量名
    操作数栈:存储的是局部变量值(用于对局部变量表中的变量进行赋值)
    方法出口:存储的是返回值与当前程序所在的行号
    动态链接:程序访问方法时,会通过符号引用来找到源代码。即通过符号引用来使方法名与方法代码进行联系
  • 方法区:存储的使静态变量,常量,类元信息(程序代码,类信息【父类,接口…】),并且直接存储到电脑上(不再jvm内存中)
  • 堆区:存储new开辟出的空间(引用数据类型)。分为伊甸区,from,to,老年区四部分。
    执行步骤:new开辟出的对象首先存储到伊甸区中,当伊甸区满后,有执行引擎执行GC操作。将需要处理的对象存到from中,带from满后,存储到to中,等到to满后重新存到from中。当一个对象被GC手机15次后,对象存储到老年区中,带老年区满后,进行fullGC操作。
  • 本地方法栈:线程私有,运行java的native方法,后进先出。
  • 程序计数器:记录档期那进程所执行的字节码的行号

JAVA运行

eg1:

package lianxi;

 class Person{
    static{
        System.out.println("person static");
    }
    public Person(String str) {
        System.out.println("person "+str);
    }
}


class MyClass extends P {
    Person person = new Person("MyClass");
    static{
        System.out.println("myclass static");
    }

    public MyClass() {
        System.out.println("myclass constructor");
    }
}
class P {
    Person person = new Person("Test");
    static{
        System.out.println("test static");
    }

    public P() {
        System.out.println("test constructor");
    }

    public static void main(String[] args) {
        new MyClass();
    }
}

运行结果:
test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor

分析:首先P.java由javac进行编译成字节码文件(.class)文件,随后在P类中寻找main方法,(若P类中无main方法,则程序会报错,main方法必须在P类中),所以应首先加载P类,在加载P类时,应先执行static方法段。接着main方法开始运行,执行第一行语句,加载MyClass类,若加载MyClass应首先加载父类P,而P类已经加载,加载完MyClass后,实例化MyClass类后,应先加载父类(P类的成员变量)进而加载并实例化Person类,在进行P类,与MyClass的实例化。

若想深入了解static关键字,请参考: https://mp.csdn.net/mdeditor/102839816#

eg2:

package lianxi;
public class P {
	public static void main(String args[]) {
		QQ q=new QQQ();
		q.setName("张三");
		q.info();  //当q为Q q=new QQQ()时,则不能调用info()方法。
	}
}
abstract class Q{
	String name="nihao";
	public abstract void setName(String name);
	public String getName() {
		return name;
	}
	
}
abstract class QQ extends Q{
	public abstract void info();
}
class QQQ extends QQ{

	@Override
	public void info() {
		System.out.println("姓名为:"+name);
		
	}

	@Override
	public void setName(String name) {
		this.name=name;
		
	}
	
}

分析:首先找到mian方法,在运行数据去为该线程建立一个栈区,实例化QQQ,加载QQQ父类类及本类,实例化QQQ类,并在堆中开辟空间存储QQQ对象(只存储属性),接着根据动态链接找到setName方法,加载并执行(在执行的时候开辟出一个栈帧存储本方法中的局部变量),修改name之后,栈帧被弹出。同理调用info方法。

若有不足,请多多指点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值