锚文本对网站,标志设计图片大全简单,杭州余杭网站制作,网站建设奕网情深在java内存模型中规定#xff0c;一个新的变量只能在主存中初始化#xff0c;不允许在工作内存中直接使用一个未被初始化的变量。 工作内存可以理解为局部变量定义的内存区域#xff0c;也就是线程的工作内存。所谓局部变量就是线程私有的不共享的空间。 类加载准备阶段 类变… 在java内存模型中规定一个新的变量只能在主存中初始化不允许在工作内存中直接使用一个未被初始化的变量。 工作内存可以理解为局部变量定义的内存区域也就是线程的工作内存。所谓局部变量就是线程私有的不共享的空间。 类加载准备阶段 类变量赋值 关键词
加载阶段链接阶段验证准备解析初始化阶段在链接得准备阶段进行静态变量得默认值赋值操作 一、面试题请回答下面两段代码得执行结果
public class A {static int a ;public static void main(String[] args) {System.out.println(a);}}public class B {public static void main(String[] args) {int a ;System.out.println(a);}}二、回答
程序1输出 0程序2无法通过编译
三、剖析
1. 类加载子系统介绍 1、类加载子系统负责从文件系统或是网络中加载.class文件class文件在文件开头有特定的文件标识。
2、把加载后的class类信息存放于方法区除了类信息之外方法区还会存放运行时常量池信息可能还包括字符串字面量和数字常量这部分常量信息是Class文件中常量池部分的内存映射
3、ClassLoader 只负责class文件的加载 至于它是否可以运行则由Execution Engine决定
4、如果调用构造器实例化对象则该对象存放在堆区
2. 类加载的执行过程
我们写的程序经过编译后成为了.class文件.class文件中描述了类的各种信息最终都需要加载到虚拟机之后才能运行和使用。而虚拟机如何加载这些.class文件.class文件的信息进入到虚拟机后会发生什么变化
类使用的7个阶段 类从被加载到虚拟机内存中开始到卸载出内存它的整个生命周期包括
加载Loading、验证Verification、准备Preparation、解析Resolution、初始化Initiallization、使用Using卸载Unloading
这7个阶段。其中验证、准备、解析3个部分统称为连接Linking
3. 加载
加载是类加载的第一个阶段。有两种时机会触发类加载 1预加载 虚拟机启动时加载加载的是JAVA_HOME/lib/下的rt.jar下的.class文件这个jar包里面的内容是程序运行时非常常常用到的像java.lang.*、java.util.、 java.io. 等等因此随着虚拟机一起加载。 2运行时加载 虚拟机在用到一个.class文件的时候会先去内存中查看一下这个.class文件有没有被加载如果没有就会按照类的全限定名来加载这个类。
那么加载阶段做了什么其实加载阶段做了有三件事情
获取.class文件的二进制流将类信息、静态变量、字节码、常量这些.class文件中的内容放入方法区中在内存中生成一个代表这个.class文件的java.lang.Class对象作为方法区这个类的各种数据的访问入口。一般这个Class是在堆里的不过HotSpot虚拟机比较特殊这个Class对象是放在方法区中的
4. 链接 面试题得考点
链接包含三个步骤 分别是 验证Verification , 准备Preparation , 解析Resolution 三个过程 1验证Verification 连接阶段的第一步这一阶段的目的是为了确保.class文件的字节流中包含的信息符合当前虚拟机的要求并且不 会危害虚拟机自身的安全。
Java语言本身是相对安全的语言相对C/C来说但是前面说过.class文件未必要从Java源码编译而来可以使用任何途径产生甚至包括用十六进制编辑器直接编写来产生.class文件。在字节码语言层面上Java代码至少从语义上是可以表达出来的。虚拟机如果不检查输入的字节流对其完全信任的话很可能会因为载入了有害的字节流而导致系统崩溃所以验证是虚拟机对自身保护的一项重要工作。
验证阶段将做一下几个工作具体就不细讲了这是虚拟机实现层面的问题
文件格式验证元数据验证字节码验证符号引用验证 2准备Preparation 准备阶段是正式为类变量分配内存并设置其初始值的阶段这些变量所使用的内存都将在方法区中分配。关于这点有两个地方注意一下
这时候进行内存分配的仅仅是类变量被static修饰的变量而不是实例变量实例变量将会在对象实例化的时候随着对象一起分配在Java堆中这个阶段赋初始值的变量指的是那些不被final修饰的static变量比如public static int value 666value在准备阶段过后是0而不是666给value赋值为666的动作将在初始化阶段才进行比如public static final int value 666;就不一样了在准备阶段虚拟机就会给value赋值为666。
注意 : 这是因为局部变量不像类变量那样存在准备阶段。 类变量有两次赋初始值的过程
一次在准备阶段赋予初始值也可以是指定值另外一次在初始化阶段赋予程序员定义的值
因此即使程序员没有为类变量赋值也没有关系它仍然有一个默认的初始值。但局部变量就不一样了如果没有给它赋初始值是不能使用的。
四、总结
类变量在准备阶段进行了默认值赋值操作后续初始化阶段不进行赋值操作也有默认值因此程序可以正常运行局部变量在准备阶段不会进行初始值操作后续初始化阶段也不赋值则不能使用编译失败 1、成员变量
成员变量有默认初始值而方法内的局部变量却没有初始值。这个问题涉及到JVM类加载和字节码执行两个阶段这两个阶段是依次执行的。
JVM类加载是JVM利用类加载器将class文件加载到JVM的过程涉及“加载”、“验证”、“”准备“、“”解析“和”初始化“。 一、类的成员变量初始化 —在JVM类加载阶段完成
类的成员变量又分为静态成员变量和非静态成员变量。
静态成员变量
静态成员变量会被初始化两次第一次在“准备”阶段先进行一次初始化系统附上默认值第二次在“初始化”阶段根据代码中的赋值情况再进行一次初始化。
例如
public static int i 3 ;
第一次初始化后i的值为0第二次初始化后值才为3.
数据最终存放在方法区中。
非静态成员变量
仅“初始化”阶段赋值。根据代码中的赋值情况代码不赋值直接赋默认值有赋值则等于代码中的赋值。对象实例化后该变量随java对象分配到java堆中。
2、局部变量
当我们新建一个对象时Java会在Heap中申请一块内存区域用以存放类的数据。而成员变量就是类的数据也是放在这块内存区域中的。
只需要JVM在申请内存的时候顺便把整块区域都置为零即可完成初始化方便快捷。 而对于方法的局部变量是在线程的Stack中当然Stack他也可以帮我们初始化不过有一个问题。
对于有些局部变量在方法的一开始是没有的有些在循环中的局部变量是要反复的声明多次的。有些局部变量作用域结束后另一个局部变量又会占用这个局部变量的位置。 那么初始化要放在何时呢当然JVM可以帮我们初始化多次不过那样或许会带来性能问题。
for (int i 0; i 10; i) {int n;if (i % 2 0) {n 10;} else {n 20;}
}像是这个n我们完全不用JVM帮我们初始化如果每次循环他都帮我们初始化一次那么是没有必要的。综上所述对于局部变量可能不帮我们初始化是一个不错的选择。而且JVM实现起来也更容易
3、总结
套用《Thinking in Java》作者Bruce Eckel的话
编译器当然可以为局部变量附一个默认值但是未初始化的局部变量更有可能是程序员的疏忽所以采用默认值范围会掩盖这种失误。因此强制程序员提供一个初始值往往能够帮助找出程序里的缺陷。
总结一下为什么局部变量需要手动初始化从技术上来讲局部变量一般来说总量大生命周期短JVM进行初始话开销较大从业务上讲局部变量一般用于实际问题下的运算很少会用到默认值赋值意义不大从编程思想上讲局部变量不初始化而是报错提醒更有助于程序员减少开发过程中出现缺陷的可能