0 首先来看一段代码
package edu.zxp.main;
public class ExtendsSorts {
public static void main(String[] args) {
System.out.println("先运行main方法");
Zi zi = new Zi();
}
}
class Fu{
public static String name = setName();
static{
System.out.println("父类静态代码块");
}
public static String setName(){
System.out.println("父类的设置类属性");
return "zxp";
}
private String job = setjob();
{
System.out.println("父类的构造代码块");
}
public Fu() {
System.out.println("父类的构造方法");
}
String setjob(){
System.out.println("父类设置对象属性");
return "engineer";
}
}
class Zi extends Fu{
public static String name = setName();
static{
System.out.println("子类静态代码块");
}
public static String setName(){
System.out.println("子类的设置类属性");
return "zxp";
}
{
System.out.println("子类的构造代码块");
}
public Zi() {
System.out.println("子类的构造方法");
}
}
1从JVM的层次分析整个类的运行过程
1.1java中的main函数
1.1java中的main函数
java中的main函数为什么是public static void的?
public说明要运行的这个类是一个公共类,也就是在使用java命令执行这个类的时候不需要考虑到该类的权限问题
static这个很重要,因为你在第一次运行java程序的时候还没有实例化任何一个对象的,因此main方法只能属于类方法
void这个main方法没有被任何方法调用,他本身就是一个程序运行的入口,因此即使有返回值也是没有任何意义的。这属于JVM规范
main函数中的参数列表(String args[ ])的含义
这个的含义就是在运行main函数的时候可以指定参数,比如在将一个java工程打包成一个jar文件(hadoop中的wordcount.jar),在运行这个jar的时候就需要在jar命令+jar文件+参数,这里的参数就是wordcount的指定输入目录与输出目录。实际上这里的两个目录最后都传递给了args这个参数数组
1.2java中main函数的执行过程
首先在编译好之后执行java命令的时候,java + 类名,这个类一定是含有main函数的主类,这个时候JVM就会自动去去寻找这个类中的
public static void main(Stirng args[ ]),这个必须一模一样,少一个也不行(public static void main(Stirng args[ ])这三个加粗的都不能没 有),如果找到这个方法,那么就将这个main方法入栈然后开始执行整个工程。JVM自动寻找main函数也属于JVM规范
2java开始执行main中的内容
在java中,main方法是java程序的入口,JVM通过main(严格匹配)方法找到需要启动的类,并且检查这个主类有没有被加载进来。如果没有被加载那就加载这个类。并且加载所有相关的其他类。类加载完成后根据.class文件中记录的main方法入栈,并且为之分配一个栈帧(存放于栈内存中)。
2.1第一句:System.out.println("先运行main方法");
这句不解释,这句话只涉及到一个简单方法的入栈以及·
2.2第二句:详细解析第二句
Zi zi = new Zi();
首先是在这个main方法的栈内存中开辟一个空间存放一个指向Zi的引用变量zi。
然后执行new
这个new关键字很特殊,这个关键字不是去调用一个方法,这个关键字java规定了可以返回一个地址(或者一个引用),但是这个new关键字又是与构造方法配套使用的,所以一般就写成了new……。new关键字是一个可以返回一个地址的关键字。
1.JVM遇到这个new后首先会检查这个指令的参数是否能在常量池中定位一个类的符号引用,并检查这个类是否被加载、解析和初始化。
2.在类加载检查通过后,接下来是为新生对象分配内存。
3.内存分配完成后,JVM需要讲分配到的内存空间全部置零,这样做是为了保证变量可以不赋值就可以使用,即便是零值。
4.JVM进行一些对象的必要设置,也就是对象头(Object Header),讲对象的元数据信息、对象的hash码、对象的GC分代年龄信息
5.貌似一个对象创建好了,但是实际上对象的创建才刚刚开始,因为实例对象的<init()>方法黑没有运行呢,这个方法跟类的<clinit()>比较类似,也是会将对象的成员和快(普通块或者构造代码块)收集并执行,这也有一个收集顺序影响运行顺序的问题。即对象成员写到普通块的前面就先执行偶痛块,反之先对对象成员进行初始化赋值(例如String name="zxp"这个操作)。
在之后是Zi()这个空参的构造器。或者根据程序员的要求来至执行有参数的构造器。
具体为JVM就会根据.Class文件去查找这个方法的地址(直接引用),找到地址之后将这个方法入栈,并为之开辟一个栈帧用来存放这个方法中的变量。