Java全局变量和局部变量初始化问题

变量的初始化问题

我们先来看一个例子,最近在知乎看到的帖子。

 
  public class TestDemo {
    int a;  //类的成员变量
    public static void main(String[] args) {
        TestDemo td =new TestDemo(); //默认的构造方法
        System.out.println(td.a);
    }
}

    // 第二种类型 
  public  class TestDemo {
    public static void main(String[] args) {
       int a;
       System.out.println(a);
    }
}

  我先验证了一下结果给大家说,上面部分代码运行结果为 0 . 下面部分代码编译执行报错(变量可能未初始化)。

成员变量和局部变量的区别

  上面两部分代码的区别是上面代码,变量 a 是作为类的成员变量,主方法中创建了对象,我们发现此时的 a 结果是 0,如果我们换成字符串就是 null ,boolean型变量默认就是 false ,所以我们发现当变量作为类的成员变量的时候类在创建对象的时候会默认给它们赋初值。

  而下面部分代码则是方法中的变量,也就是局部变量。我们直接打印它或者用到它的时候直接会报错。

  如何解释这一现象?局部变量必须赋初始值?下面我们多方面分析一下。

  首先,Java语言是这么明文规定的。局部变量使用前必须赋值。为什么Java 语言要这么规定呢。我们知道Java 是一门面向对象的语言,它将重点放在 数据 和对象的接口上。就好比一个木匠,一个“面向对象”的木匠始终关注的是所制作的椅子,第二位才是所使用的工具和打造的过程;而一个“非面向对象的”木匠首先考虑的是所用的工具。

  最上面部分代码,将 a 变量作为类的成员变量,当我们创建对象的时候,Java 虚拟机会在系统的堆 (heap)区域申请一块内存区域来存放类的数据,在这里成员变量就是类的数据,这个时候JVM为加载的类要分配内存啦!成员变量作为类的数据是会随着类的加载在堆中分配内存,注意了,JVM 在申请内存时自动给它们赋了初值。这里附上下面一个堆栈简单示意图,
在这里插入图片描述

  至于默认给类的成员变量赋初值有什么机理吗?我们可以想到类都有一个默认的构造方法的。(因为我们没有给出显式的构造方法)我们创建对象的时候实际上是调用了默认的构造方法的,会给成员变量赋一个默认的初始值,这样在打印输出的时候才会有值输出而不报错。这时我们看一下第二段代码,并没有涉及到任何实例化对象的操作,在主函数里面 a 是没有任何东西对其初始化的,所以直接对其输出会直接报错。

  现在我们想一想如果Java 设计的时候也给方法里的局部变量赋初始值会怎样? 一个方法里面可能会有很多个局部变量,类里面也会有很多个方法,而且生命周期短。如果我们都给它们赋初值,一定是一笔很大的开销,而且安全性也达不到要求,所以换成我是虚拟机也不想干这等活儿…但程序员们最好有给局部变量初始化的习惯。我们不妨看下下面这个例子。

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            int a;
            if (i % 2 == 0) {
                a = 1;
            } else {
                a = 2;
            }
        }
    }

如果我们每次都对 a 进行初始化,那真的是丝毫没有必要的。

  我们还可以换个角度来想这个问题,假如你是开发 Java 这门伟大语言的开发者,你在设计的时候,类的成员变量是要在堆中分配内存的,方法中的局部变量是在栈中的。其实,不管是局部变量还是成员变量,都是必须要初始化的,那为什么成员变量会自动初始化?其实正是因为成员变量属于对象,而对象是保存在堆中的,随着类的加载在为对象开辟空间的时候自动为成员变量赋初值,如果我们还要给局部变量都赋初值,那性能影响太大了吧,开发者想到这里的时候可能就直接将给局部变量初始化的想法抹杀掉了吧。同时在一般情况下成员变量也不会有初始值,你可以联想一下,有一个class 比如说是人类,里面的身高体重如果定义时候给了初始值,是不是觉得一点都不抽象了,所以成员变量不初始化可能更符合需求,创建类的对象的时候它们也会有初始值。(ps: static 修饰的成员变量不用创建对象也可以哦)

  最后套用《Thinking in Java》作者的话:

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

果然是大佬,说出来的话就是让人无可反驳。

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值