为何 Java 中全局变量不必定初始化,局部变量必须初始化?

前几天,有个大佬考了我一个问题:为何类的成员变量不须要指定值就能够自动赋予初始值,而方法内的局部变量就必须指定初始值呢?

说实话,这个问题确实难倒我了,以后我在网上一顿操做,终于把这个问题弄得稍微明白一点了。
首先我给出一个具体的场景来讲明这个事情:
image.png
定义一个Cat类,里面有各类属性,包括8大基本数据类型和String类型,咱们把String类视为复杂数据类型。Cat类里面有一个setAge方法。咱们在main方法里面给tom这个Cat赋值年龄,结果发现,若是给定的年龄没有赋初始值,编译器会报错:
image.png
那咱们来看下未给Cat里面的各类属性初始化,各项属性的初始值到底是怎样的:
重写一下toString方法:
image.png
而后输出结果为:
image.png
咱们可以看到,对于8大基本类型的初始化已经实现了,分别是如图所示的值。对于复杂的类,会赋予null做为默认值。(这里char的默认值为'/u0000'也就是null)
那么问题来了,为何Java会有这样的操做呢,为何不能将方法内的局部变量也自动赋值一个默认值呢?java


首先,我在网上找到了这样的一个答案以下,若是不想看原文,能够直接跳过至引用答案的结尾处直接看个人总结:
这位做者在读《深刻理解Java虚拟机》的时候记录了一个相关知识点。程序员

类的成员变量有默认初始值,而方法内的局部变量却没有初始值。这个问题涉及到 JVM类加载字节码执行两个阶段,这两个阶段是依次执行的。

JVM类加载是JVM利用类加载器将class文件加载到JVM的过程,涉及“加载”、“验证”、“”准备“、“”解析“和”初始化“。
1、类的成员变量初始化   ---在JVM类加载阶段完成编程

类的成员变量又分为静态成员变量和非静态成员变量。性能

静态成员变量spa

静态成员变量会被初始化两次,第一次在“准备”阶段,先进行一次初始化,系统附上默认值;第二次在“初始化”阶段,根据代码中的赋值状况再进行一次初始化。.net

例如:线程

public static int i =3 ;code

第一次初始化后i的值为0,第二次初始化后,值才为3.对象

数据最终存放在方法区中。blog

非静态成员变量

仅“初始化”阶段赋值。根据代码中的赋值状况,代码不赋值直接赋默认值,有赋值则等于代码中的赋值。对象实例化后,该变量随java对象分配到java堆中。

2、方法区的局部变量没有初始化

而方法中的局部变量没有初始化步骤,以下图:
image.png
须要在代码中进行初始化。
image.png
————————————————
缘由就是类方法中的代码,实在字节码执行的时候,才会被运行到,此时局部变量是存储在虚拟机栈-栈帧中的局部变量表中。局部变量定义了可是没有赋值是不能使用的。
版权声明:本文为CSDN博主「一步一台阶」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处连接及本声明。
原文连接:https://blog.csdn.net/liufang...


这篇帖子主要是说明了两种变量在JVM编译代码的时候把他们放在了哪里。

  1. JVM加载类的时候,不论是静态类仍是非静态类,都会给每一个类分配内存,存在堆里面,都有初始化的这一步操做。
  2. 对于方法内的局部变量,因为方法要放到堆栈中(堆栈这个词,其实意义就是栈,习惯称为堆栈,其实和堆不要紧),只有字节码执行的时候才会被运行到,因此没有赋值是不能使用的。

………………??? 这是什么意思?也就是说,两种变量的存储位置不同,会对是否初始化有影响,可是没有说明为何成员变量在堆里就有初始化,方法内局部变量为啥放在堆栈里面,只有执行方法的时候才会被运行到就不能初始化呢?
而后我就找到另外一篇文章以下:

为何 Java 中全局变量不必定初始化,局部变量必须初始化?

做者:Intopass
连接:https://www.zhihu.com/questio...
来源:知乎
著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。

  1. 首先 Java 语言就是这么规定的。
  2. 而后为何 Java 语言要这么规定呢?有什么内部机理吗?

可能的缘由以下,当咱们新建一个对象时,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实现起来也更容易!!!)


经过看这位做者的讲解,咱们就可以理解得更清楚一些了。为何堆内的成员变量能够初始化?由于容易,申请内存的时候顺便就实现了初始化。为何栈内的局部变量不能初始化?由于麻烦,并且没有必要。
最后,我又看到了一个内容,同知乎页面另外一个匿名做者的回答:

套用《Thinking in Java》做者Bruce Eckel的话

编译器固然能够为局部变量附一个默认值,可是未初始化的局部变量更有多是程序员的疏忽,因此采用默认值范围会掩盖这种失误。所以强制程序员提供一个初始值,每每可以帮助找出程序里的缺陷。


其实我以为这句话应该是对于为何局部变量不可以初始化的最合理的解释了吧。
总结一下,为何局部变量须要手动初始化?从技术上来说,局部变量通常来讲总量大,生命周期短,JVM进行初始话开销较大;从业务上讲,局部变量通常用于实际问题下的运算,不多会用到默认值,赋值意义不大;从编程思想上讲,局部变量不初始化,而是报错提醒,更有助于程序员减小开发过程当中出现缺陷的可能。一举三得,何乐而不为?回到开头,因此说大佬就是大佬,随随便便问一个问题,看似是一个小问题,可是深究下去居然牵扯到这么多深层次的知识点,甚至有点哲学的意义在里面,佩服佩服!

相关文章
相关标签/搜索