今天在JAVA的研究学习当中发现了构造函数这个神奇但是麻烦的东西, 他在给我感觉很像OC语言中的initWith..., 但是在细节上有很多的不同, 而代码块这个东西更是让我这个敲iOS的眼前一亮, 后来针对代码块这个东西的功能和执行的顺序深究了一番.

首先说说构造函数

开头说道这个东西给我的感觉很像initWith...甚至可以这么去理解, 但是你深究他的写法和功能你就会发现他跟initWith还是有很多的区别的.

什么是构造函数(构造器)

主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。

所以, 构造函数是用来创建时初始化对象所用, 由于他本身可以传递参数的语法, 他可以在初始化的时候直接给你的对象赋值(所以我说这东西很想initWith), 但是在写法和用法上要注意.

构造函数的优点

在开发中分析类的时候,发现类具备某些特征,就可以将这些特征定义在构造函数中,在使用时不仅十分的方便而且快捷,构造函数本身十分符合面向对象的编程思想。

我们来看看构造函数的代码

为了演示, 我们首先创建一个很简单的Person类, 然后给他创建几个成员变量.

class Person{
 String name;
 int age;
 boolean sex;
 double weight;
}

然后该创建Person的构造函数了, 但是先让我们注意一下构造函数的语法和语义规则(语法, 语义有什么区别, 具体指什么,

Person(){
}

因为构造函数可以拥有一个或者多个参数, 并且他还是在创建时初始化对象所用到的一个方法, 所以不免多个参数的情况出现, 这样为了程序的安全性, 按照上面的类为例子, 我就需要这么写构造函数.

Person(){
 this(null, 0, true, 0);
 }
 Person(String name){
 this(name, 0, true, 0);
 }
 Person(String name, int age){
 this(name, age, true, 0);
 }
 Person(String name, int age, boolean sex){
 this(name, age, sex, 0);
 }
 Person(String name, int age, boolean sex, double weight){
 this.name = name;
 this.age = age;
 this.sex = sex;
 this.weight = weight;
 }

这么写构造函数可以十分有效的避免出现你并不需要附加全部的参数, 但是容易出现程序上面的不安全的情况.

用static静态修饰成员变量会在构造器中产生警报

经过上面的讲解, 相信大家已经对构造函数有了具体而完整的认识, 下面我介绍一种我在写构造函数的时候遇到的特殊情况, 这个问题可能也是很多同学都会遇到的坑, 那就是用static静态修饰一个成员变量会出现的一个情况, 例如.

 static String name;
 int age;
 boolean sex;
 double weight;

在这里我用static修饰了name, 现在name是一个静态成员变量了, 而产生的结果就是

java构造函数怎么写(JAVA 构造函数和代码块本身及其执行细节)(1)

这里的this.name产生了警告

后来经过我的研究发现这里是由于代码, 或者说是由于static修饰的原因, name这个成员变量"不属于方法, 属于类的名下了", 因为this这个关键字指的是, 本身类的对象, 由于这个成员变量"属于类的名下", 所以单纯的用this. 这个成员变量才会产生警告, 我对this进行了修改, 改成Person这个类.

java构造函数怎么写(JAVA 构造函数和代码块本身及其执行细节)(2)

可以看到用Person.name警告消失了

代码块

代码块这个东西光是定义就很有意思

{}

没错, 你没有看错, 就两个大括号, 这就是代码块.

代码块和构造函数联动, 先于构造器来调用, 构造函数每被执行一次, 代码块就被执行一次, 而因为这个特性, 通常做所有构造器调用的准备工作.

代码块还能用static来修饰

static{
 }

而这个东西有几个重点需要记住:

对代码块和构造函数有一定了解之后很明显的就会产生了一个疑问, 代码的执行顺序, 或者说编译的顺序是什么样的?

经过了一些神秘小软件的帮助, 成功的找到了编译的结果.

经过对多个编译结果的研究发现代码的执行顺序是显式 ----> 静态代码块 ----> 代码块 -----> 构造器

综合上文可以得到一个结论

创建对象的流程

  1. 开辟内存
  2. **静态变量的显式初始化
  3. 静态代码块(如果有多个的情况, 按照代码书写的顺序执行)
  4. 成员变量的显式子初始化(反编译结果, 添加到了构造器中)
  5. 代码块(反编译结果, 添加到了构造器中)
  6. 构造器

但是经过我的调试研究, 又发现了一个细节.

 static {
 System.out.println("静态代码块");
 }

如果你在静态代码块中什么都没写的情况下, 编译程序, 其结果显而易见.

java构造函数怎么写(JAVA 构造函数和代码块本身及其执行细节)(3)

反编译结果

可以看到跟结果一样, 但是如果你在静态代码块中调用静态成员变量的话, 你就会看到编译结果有了一个变化.

调用静态变量

 static {
 System.out.println(name);
 System.out.println("静态代码块");
 }

java构造函数怎么写(JAVA 构造函数和代码块本身及其执行细节)(4)

编译结果有了一个显著的变化

由此我可以得出第二条结论需要添加一个条件.

代码的执行顺序或者细节是在程序开发中很重要的事情, 老手们都知道这个东西是多重要多好用,