JAVA加载过程
总觉得有无数想记录的东西但又觉得没什么需要记下来的。
但又不能坏了一周一篇的目标,再三思考下决定写一些基础干货。
基础扎实的话就会和计算机有某种共鸣——你猜测应该是什么样的,实际上计算机就是什么样的
static静态成员
这是我觉得目前以来最重要的java东西——理解静态成员。(本文不讲java实践,只讲java理论)
之前学习一直懵懵懂懂,只是学习了java的规则语法。虽然可以满足日常编程却总是提不起兴趣,缺乏创造力,没有创造力的职业我是坚决拒绝的,所以我一次又一次的从头学习java,这是我第四次从头学起了。
但是直到今天看到看到static ,仿佛和计算机有了某种共鸣,所以本文从static开始讲解java代码运行过程。
从static学习java编译过程
JVM加载顺序摘要:
- 加载所有类(类是默认加载的)
- 加载主函数(即main函数)
稍稍延申一下:
JAVA代码的加载过程简简单单的就这两步,但是还是颇有深意的。
加载所有类
即就是说,类是在加载java代码时候就已经加载,并写入内存中的。加载主函数
即就是说,其他函数是不加载的。
也就是说,其他函数只是逻辑存在,内存中并不真正的存在。并没有加载任何对象和变量
即所有对象都存在于逻辑中,并不存在。
不存在的东西当然是不能调用的。同样的不能调用方法,也就丧失了方法存在的意义。
对于此java给出了两个解决方案:
实例化成员
实例化(即就是执行new操作指令),实例化在JVM的操作就是——将执行new操作的东西(方法或者变量)写进内存中。一般来说抛开访问控制凡是内存中的东西都是可以直接调用的。静态成员
声明静态成员的关键字是static。JVM的操作是——在加载优先级等同于类,加载类的同时就会加载static成员。也就是说static的成员已经存在内存中了就可以进行直接调用。
所以静态变量又称为类变量。
总结static
首先static的成员是在类加载的时候初始化的,JVM的CLASSLOADER的加载,首次主动使用加载,而非static的成员是在创建对象的时候,即new 操作的时候才初始化的;
先后顺序是先加载,才能初始化,那么加载的时候初始化static的成员,此时非static的成员还没有被加载必然不能使用,而非static的成员是在类加载之后,通过new操作符创建对象的时候初始化,此时static 已经分配内存空间,所以可以访问!
简单点说:静态成员属于类,不需要生成对象就存在了.而非静态需要生成对象才产生.所以静态成员不能直接访问非静态.
下面说说静态的特点:
- 着类的加载而加载
也就是,说静态会随着类的消失而消失,说明静态的生命周期最长 - 先于对象的存在
明确一点:静态是先存在的对象是后存在的 - 所有对象共享
- 以直接被类名多调用
实例变量和类变量的区别
- 放位置
变量随着类的加载存在于方法区中,实例变量随着对象的对象的建立存在于堆内存里 - 命周期
变量生命周期最长,随着“类”的加载而加载,随着类的消失而消失,实例变量随着“对象”的消失而消失
静态的使用注意事项:
- 静态方法只能访问静态成员(包括成员变量和成员方法)
静态方法可以访问静态也可以访问非静态 - 态方法中不可以定义this,super关键字。
静态优先于对象存在,所以静态方法中不可以出现this,super关键字 - 函数是静态的。
静态的利弊
利:对对象的共享数据进行单独空间的存储,节省空间,没有必要每一个对象中都存储一份可以直接被类名所调用
弊:生命周期过长,访问出现局限性(只能访问静态)
从内存角度理解java的基础语法
首先需要理解不是java代码本身占用的空间就是内存空间。真正写入内存的也并不是java代码,只是变量。
学过汇编的人应该大致知道,基层语言只是一些指令。
为什么主函数一定是静态的
如之前所说,不是静态的成员不会预先加载。
假如没有static关键词:编译器会主动加载所有的类,可是加载完类之后呢?
虽然写了很多方法,可是都是逻辑的方法并不是实际存在的方法,所以这个类这是一个摆设而已,如果不被调用的话。
所以主函数一定得是静态的,作为整个编译的开始。为什么需要实例化呢?
接上,主函数加载之后,主函数需要调用其他的方法,其他类才能实现这个代码包本身的价值
那么问题来了,怎么调用呢?
之前说了java只能调用内存中的东西,如果不写入内存是不能调用的否则会报错。
如果要写入内存就要执行new指令。
所以我们调用类的方法时候需要实例化:类名 变量名 = new 构造函数();
java中本应该是:类名 变量名 = new 类名();
为了深入理解我一般记上面的语法。为什么静态的方法只能调用静态的成员变量(方法)呢?
如很上很上所说,静态优先存在于普通成员。
只有存在的东西才能调用存在的东西。不存在的东西是不能调用不存在的东西的。
所以静态方法只能调用静态成员。
不过换言之,如上所说“只有存在的东西才能调用存在的东西”
那么如果给普通成员实例化不就存在了吗?
恭喜你已经回举一反三了。事实上就是如此。
这就是为什么静态方法调用静态方法不用实例化,而非静态方法调用静态方法需要实例化。
总结
java运行基本过程:
- 加载所有类预加载,但不加载类的方法
- 加载所有的static成员(即就是加载主函数)
- 主函数里运行,主函数实例化谁就把谁写进内存。
- 主函数调用哪个方法就调用哪个方法。
感谢鼎鼎的鼎力相助