静态代码块,普通代码块,同步代码块,构造代码块和构造函数解

时间:2021-11-05 19:31:24
构造函数
用于给对象进行初始化,是给与之对应的对象进行初始化,它具有针对性,函数中的一种。
特点:
1:该函数的名称和所在类的名称相同。
2:不需要定义返回值类型。
3:该函数没有具体的返回值。
记住:所有对象创建时,都需要初始化才可以使用。

注意事项:一个类在定义时,如果没有定义过构造函数,那么该类中会自动生成一个空参数的构造函数,为了方便该类创建对象,完成初始化。如果在类中自定义了构造函数,那么默认的构造函数就没有了。

一个类中,可以有多个构造函数,因为它们的函数名称都相同,所以只能通过参数列表来区分。所以,一个类中如果出现多个构造函数。它们的存在是以重载体现的。

构造函数和一般函数有什么区别呢?
1:两个函数定义格式不同。
2:构造函数是在对象创建时,就被调用,用于初始化,而且初始化动作只执行一次。
    一般函数,是对象创建后,需要调用才执行,可以被调用多次。
   
什么时候使用构造函数呢?
分析事物时,发现具体事物一出现,就具备了一些特征,那就将这些特征定义到构造函数内。

构造代码块和构造函数有什么区别?
构造代码块:是给所有的对象进行初始化,也就是说,所有的对象都会调用一个代码块。只要对象一建立。就会调用这个代码块。
构造函数:是给与之对应的对象进行初始化。它具有针对性。

普通代码块

  直接在一个方法中出现的{}就称为普通代码块,例子程序如下:
静态代码块,普通代码块,同步代码块,构造代码块和构造函数解
  public class CodeDemo01{

  public static void main(String[] args){

  //普通代码块

  {

  int x = 10;

  System.out.println("x=" + x);

  }

  int x = 100;

  System.out.println("x=" + x);

  }

 
静态代码块,普通代码块,同步代码块,构造代码块和构造函数解
构造代码块

  直接在类中定义的没有加static关键字的代码块{}称为构造代码块,例子程序如下:

静态代码块,普通代码块,同步代码块,构造代码块和构造函数解
  public class CodeDemo02{

  public CodeDemo02(){

  System.out.println("========这是构造方法=========");

  }

  //这是构造代码块,而且在new对象时,构造代码块优先构造方法执行

  {

  System.out.println("=========这是构造块!=========");

  }

  public static void main(String[] args){

  new CodeDemo02();

  new CodeDemo02();

  }

  }
静态代码块,普通代码块,同步代码块,构造代码块和构造函数解
静态代码块
就是一个有静态关键字标示的一个代码块区域。定义在类中。

  使用static关键字声明的代码块称为静态代码块,静态块的主要目的是用来为静态属性初始化,例子程序如下:
 
静态代码块,普通代码块,同步代码块,构造代码块和构造函数解
 public class CodeDemo03

  {

  static{

  System.out.println("这是主类中的静态代码块!");

  }

  public static void main(String[] args){

  new Demo();

  new Demo();

  new Demo();

  }

  }

  class Demo

  {

  static{

  System.out.println("这是Demo类中的静态代码块!");

  }

  {

  System.out.println("这是Demo类中的构造块!");

  }

  public Demo(){

  System.out.println("这是构造方法!");

  }

  }
静态代码块,普通代码块,同步代码块,构造代码块和构造函数解
静态块优先于主方法的执行,静态块优先于构造方法的执行,而且只执行一次!

作用:可以完成类的初始化。
静态代码块随着类的加载而执行,而且只执行一次(new 多个对象就只执行一次)。如果和主函数在同一类中,优先于主函数执行。
静态块的特点是在类加载的时候就执行,先说一下类加载,一个程序要想运行,首先要把代码加载到内存中对吧?然后才能去和CPU交流,
这是冯诺依曼计算机规定的。Java也是一样,Java的.class字节码文件要想执行,首先也要加载到内存,由类加载器把字节码文件的代码加载到内存中,这一步就叫类加载,这是首先要进行的。
public class Test {
static {
System.out.println("我是静态块");
}
}
当创建Test类的一个对象的时候,比如new Test() ,是这样,首先是类加载,然后才能new对象,静态块在类加载的时候就执行了,
这就说明静态块在new对象之前就会执行,而且一个类在第一次被使用的时候会被加载,然后在整个应用程序的生命周期当中不会再次被加载了,就加载这一次,所以这就说明,静态块就执行一次,不会执行第二遍!
静态代码块,普通代码块,同步代码块,构造代码块和构造函数解
public class Test {
public Test() {// 构造方法
System.out.println("我是构造方法,创建对象的时候我会执行,我执行完,对象就造出来了");
}

static {
System.out.println("我是静态块,类加载的时候我就执行了,而且只执行这一次");
}
}
静态代码块,普通代码块,同步代码块,构造代码块和构造函数解
然后这样:
new Test();
new Test();
你会发现首先打印出静态块的信息,然后才打印出构造方法信息,然后再次new Test();的时候,只打印出了构造方法的信息,这个例子证明了我上面说的是对的!

这就是静态块,静态块中初始化Map。
下面就可以说是在静态块中初始化Map,
public class Test {
private static Map m;
static {
m = new HashMap();
}
}
静态代码块是当类在加载时,静态代码块就会被自动执行,先于main方法被执行且只执行一次,常用来对一些类的属性进行初始化
构造代码块是每次进行对象的建立时都会被执行到

同步代码块。
如果在代码块前加上 synchronized关键字,则此代码块就成为同步代码块。 同步代码块的格式: synchronized(同步对象){ 需要同步的代码; } 同步对象一般为当前对象,即使用this关键字 静态代码块,普通代码块,同步代码块,构造代码块和构造函数解
package cn.sunzn.synchronize;

public class SynchronizeCode {
public static void main(String[] args) {
new Thread() {
public void run() {
while (true) {
System.out.println("同步代码");
}
};
}.start();
new Thread() {
public void run() {
while (true) {
System.out.println("SynchronizeCode");
}
};
}.start();
}
}
静态代码块,普通代码块,同步代码块,构造代码块和构造函数解

结果为:

静态代码块,普通代码块,同步代码块,构造代码块和构造函数解
SynchronizeCode
SynchronizeCode
SynchronizeCode
SynchronizeCode
同步代码
同步代码
同步代码
同步代码
静态代码块,普通代码块,同步代码块,构造代码块和构造函数解
静态代码块、构造代码块、构造函数同时存在时的执行顺序
静态代码块 -->构造代码块 --> 构造函数;
也就是 先执行静态代码块,接着就是构造代码块。再接着就是构造函数。如果在主类里面的话。执行顺序是:先执行静态代码块。在执行main方法、在执行构造代码块。在接着才是构造函数。
 
静态代码优先于非静态的代码,是因为被static修饰的成员都是类成员,会随着JVM加载类的时候加载而执行,而没有被static修饰的成员也被称为实例成员,需要创建对象才会随之加载到堆内存。所以静态的会优先非静态的。 
执行构造器(构造方法)的时候,在执行方法体之前存在隐式三步: 
1,super语句,可能出现以下三种情况: 
1)构造方法体的第一行是this语句,则不会执行隐式三步, 
2)构造方法体的第一行是super语句,则调用相应的父类的构造方法, 
3)构造方法体的第一行既不是this语句也不是super语句,则隐式调用super(),即其父类的默认构造方法,这也是为什么一个父类通常要提供默认构造方法的原因; 
下面我们来一一验证这三种情况:
第一种情况:构造方法体的第一行是this语句,则不会执行隐式三步。

父类:
public class AA {
public AA(){
System.out.println("AA");
}
}

子类一:
public class BB extends AA {

/**
* @param args
*/
public BB(){
System.out.println("original Constructor BB");
}
public BB(String str){
this();
System.out.println(str+"Constructor BB");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
BB bb = new BB("second");
}

}


子类二:
public class BB extends AA {

/**
* @param args
*/
public BB(){
System.out.println("original Constructor BB");
}
public BB(String str){
//this();
System.out.println(str+"Constructor BB");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
BB bb = new BB("second");
}

}


结果一:
AA
original Constructor BB
secondConstructor BB

结果二:
AA
secondConstructor BB

第二种情况:略
第三种情况:隐式调用super()

父类:
public class AA {public AA(){System.out.println("AA");}}
子类:
public class BB extends AA {

/**
* @param args
*/
public BB(){
System.out.println("BB");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
BB bb = new BB();
}

}


结果:
AA
BB

class Father {
{
System.out.println("父类构造块");// 3
}
static {
System.out.println("父类静态块");// 1
}


Father() {
System.out.println("父类构造函数");//4
}
}


public class Lianxi14 extends Father {
{
System.out.println("子类构造块");// 5
}
static {
System.out.println("子类静态块");// 2
}


Lianxi14() {
System.out.println("子类构造函数");//6
}


public static void main(String[] args) {
new Lianxi14();
}


}<span style="font-family:microsoft yahei;"><span style="font-size: 14px; line-height: 26px; background-color: rgb(255, 255, 255);">
</span></span>

执行顺序如下:
父类静态块子类静态块父类构造块父类构造函数子类构造块子类构造函数


class X{    Y y=new Y();    public X(){        System.out.print("X");    }}class Y{    public Y(){        System.out.print("Y");    }}public class Z extends X{    Y y=new Y();    public Z(){        System.out.print("Z");    }    public static void main(String[] args) {        new Z();    }}


初始化过程:  1. 初始化父类中的静态成员变量和静态代码块 ;  2. 初始化子类中的静态成员变量和静态代码块 ;  3.初始化父类的普通成员变量和代码块,再执行父类的构造方法; 4.初始化子类的普通成员变量和代码块,再执行子类的构造方法;    (1)初始化父类的普通成员变量和代码块,执行  Y y = new Y(); 输出Y  (2)再执行父类的构造方法;输出X (3) 初始化子类的普通成员变量和代码块,执行  Y y=new Y(); 输出Y  (4)再执行子类的构造方法;输出Z  所以输出YXYZ