专栏首页我的技术专栏java与C++变量初始化的对比

java与C++变量初始化的对比

java尽力保证:所有变量在使用前都能得到恰当的初始化

①函数/方法局部变量的初始化

在C/C++中,变量的初始化还是得依赖于程序员的自觉性。对于函数局部变量,编译器不会为基本类型赋予默认初始值,新手经常会使用未初始化的指针访问内存,导致程序崩溃。对于类对象,编译器将使用类的默认构造函数对对象进行初始化。而在java中,对于方法的局部变量,java以编译时错误来保证变量在使用前都能得到恰当的初始化。

void f(){
    int i ;
    i ++ ; //Error- - i not initialized
}

尽管java编译器也可以为方法的局部变量赋予一个初值,但局部变量未初始化更有可能是程序员的疏忽,采用默认值反而会掩盖这种错误。

②类数据成员的初始化

C++程序员刚接触到java的类时可能会很不习惯,java类的数据成员居然可以在定义时就初始化:

public class InitialValues{
boolean bool = true;
char ch = ‘x’;
int i = 999;
double d = 3.14;
Depth d = new Depth();
}

这种方式在java中称为指定初始化。在指定初始化之前,编译器还会为这些数据成员进行默认初始化,实际上是把刚分配的对象内存都置零。

// java数据成员的默认初始化
public class InitialValues{
    boolean t;  //flase
    char c;     //[]
    short s;    //0
    byte b;   //0
    int i; //0
    long l; //0
    float f; //0.0
    double d; //0.0
}

在对象里定义一个引用,且不将其初始化时,默认初始化为null。这种默认初始化的实现是,在创建(new)一个对象时,在堆上对对象分配足够的空间之后,这块存储空间会被清零,这样就自动把基本类型的数据成员都设置成了默认值。默认初始化动作之后,才执行指定初始化。也就是说下面的i经历过被初始化为0后,再赋值为999的过程。

public class InitialValues{
int i = 999;
}

java也可以使用构造函数来进行初始化,但构造函数的初始化无法阻止指定初始化和默认初始化的进行,而且总是在它们之后,才会执行构造函数初始化。总结起来说,java中数据成员的初始化过程是:

  • ① 先默认初始化
  • ② 进行定义处的初始化(指定初始化)
  • ③ 构造函数初始化

C++禁止在定义数据成员时就进行指定初始化,而且C++也没有默认初始化。有人会问,下面这段代码不是默认初始化了吗?

class Test {
public:
    int i;
    double b;
    char ch;
};
int main()
{
    Test *t = new Test();
    cout << t->b; //输出0
    cout << t->i; //输出0
    cout << t->ch; //输出[]
    return 0;
}

这实际上是C++的默认构造函数进行的构造函数初始化。当类没有构造函数时,编译器会为类声明并实现一个默认构造函数,默认构造函数将数据成员初始化为默认值。所以C++数据成员的初始值,只能依赖:

  • 成员初始化列表
  • 构造函数

成员初始化列表与java的指定初始化相似,也是在进入构造函数函数体之前,对数据成员进行的初始化。在数据成员的初始化顺序上,java与C++倒是一致的,定义的顺序决定了初始化的顺序。

关于static成员的初始化

在java中不允许有static的局部变量,只能够有static的域,如static数据成员。static数据成员在对象被第一次创建时才会被实例化,而且只实例化一次。例如:

class StaticTest{
    int _a ;
    StaticTest (int a ){
        _a = a;
        System.out.println("StaticTest("+a+")");
    }
}

class Test{
    static StaticTest st1= new StaticTest(1);
    StaticTest nonSt = new StaticTest(0);     
    static StaticTest st2= new StaticTest(2);
}

public class Main {
    public static void main(String[] args) throws Throwable {
        Test t = new Test(); //直到这个时候, st1与st2才会被实例化
    }
}

//程序输出
StaticTest(1)
StaticTest(2)
StaticTest(0)

从输出可以看出在java中,初始化顺序是这样的:先初始化静态数据成员,再初始化非静态数据成员。

在C++中,static数据成员必须在类之外初始化。关于C++的static,http://www.cnblogs.com/QG-whz/p/4473384.html 我以前的总结放在这里挺合适的。

回到篇首的话。

java尽力保证:所有变量在使用前都能得到恰当的初始化(《java编程思想》)

java在变量初始化上,普通变量以编译错误、成员变量以默认初始化等手段,尽力使所有的变量在使用前都可得到初始化,在安全性上大大强于C++。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 浅谈 GPU图形固定渲染管线

    图形渲染管道被认为是实时图形渲染的核心,简称为管道。管道的主要功能是由给定的虚拟摄像机、三维物体、灯源、光照模型、纹理贴图或其他来产生或渲染一个二维图像。由此可...

    Tencent JCoder
  • 关于传值与传引用的讨论

    对于用户自定义的类型来说,传引用一般要比传值高效。传引用不需要经过对象构造的过程,在《Effective C++》中作者举了个例子:

    Tencent JCoder
  • 记一次数据库死锁

    死锁发生在一个事务中,事务对多个表进行了操作。在报错日志中,死锁发生在tableA与tableB。一开始怀疑此次发布的某个改动中对上面这两张表新增了select...

    Tencent JCoder
  • 一文读懂神经网络初始化!吴恩达Deeplearning.ai最新干货

    初始化会对深度神经网络模型的训练时间和收敛性产生重大影响。简单的初始化方法可以加速训练,但使用这些方法需要注意小心常见的陷阱。本文将解释如何有效地对神经网络参数...

    数据派THU
  • 一文看懂神经网络初始化!吴恩达Deeplearning.ai最新干货

    初始化会对深度神经网络模型的训练时间和收敛性产生重大影响。简单的初始化方法可以加速训练,但使用这些方法需要注意小心常见的陷阱。本文将解释如何有效地对神经网络参数...

    新智元
  • 吴恩达深度学习课最新补充教程:交互式demo助你轻松理解神经网络初始化

    这篇教程共包括四部分:有效初始化的重要性、梯度爆炸或消失问题、什么是恰当的初始化,以及 Xavier 初始化的数学证明。

    机器之心
  • 吴恩达团队:神经网络如何正确初始化?

    初始化对训练深度神经网络的收敛性有重要影响。简单的初始化方案可以加速训练,但是它们需要小心避免常见的陷阱。

    AI科技大本营
  • 一文看懂神经网络初始化!吴恩达Deeplearning.ai最新干货

    初始化会对深度神经网络模型的训练时间和收敛性产生重大影响。简单的初始化方法可以加速训练,但使用这些方法需要注意小心常见的陷阱。本文将解释如何有效地对神经网络参数...

    磐创AI
  • Java的初始化块及执行过程详解

    针对上面的问题,想必大家脑海中首先浮现出的答案是构造器,没错,构造器是Java中常用的对象初始化方式。

    硕人其颀
  • 吴恩达深度学习课最新补充教程:交互式demo助你轻松理解神经网络初始化

    这篇教程共包括四部分:有效初始化的重要性、梯度爆炸或消失问题、什么是恰当的初始化,以及 Xavier 初始化的数学证明。

    用户2769421

扫码关注云+社区

领取腾讯云代金券