[color=red][size=large]什么是代码块?[/size][/color]
在Java中,使用”{}”括起来的代码称为代码块,代码块可以分为以下四种:
[color=indigo]1.普通代码块:[/color][b]就是类中方法的方法体 直接在一个方法中出现的{}就称为普通代码块。[/b][i]例子程序如下[/i]:
public void xxx(){
//code
}
[color=indigo]2.构造代码块:[/color][b]用{}裹起来的代码片段,直接在类中定义的没有加static关键字的代码块{}称为构造代码块[/b]。
构造块在创建对象时会被调用,每次创建对象时都会被调用,并且优先于类构造函数执行。[i]例子程序如下:[/i]
public class ConstructBlock{
public ConstructBlock(){
System.out.println("========这是构造方法=========");
}
//这是构造代码块,而且在new对象时,构造代码块优先构造方法执行
{
System.out.println("=========这是构造块!=========");
}
[color=indigo]3.静态块:[/color][b]用static{}裹起来的代码片段,使用static关键字声明的代码块称为静态代码块。[/b]
只会被执行一次(第一次加载此类时执行,比如说用Class.forName("")加载类时就会执行( static block),静态块优先于构造块执行。 ,静态块的主要目的是用来为静态属性初始化,[i]例子程序如下:[/i]
static{
//code
}
[color=indigo]4.同步代码块:[/color][b]使用synchronized(obj){}裹起来的代码块[/b]。
在多线程环境下,对共享数据进行读写操作是需要互斥进行的,否则会导致数据的不一致性。
常见的是synchronized用来修饰方法,其语义是任何线程进入synchronized需要先取得对象锁。如果被占用了,则阻塞,实现了互斥访问共享资源。而synchronized也是有代价的。同步代码块主要出现在多线程中。
一个常见的场景是,一个冗长的方法中,其实只有一小段代码需要访问共享资源,这时使用同步块,就只将这小段代码
裹在synchronized block,既能够实现同步访问,也能够减少同步引入的开销。
synchronized(obj){
//code
}
[color=red]/*
* 几大原则
* 一、静态成员变量(Static)
* 1、静态成员变量为类变量,所有对象共享同一内存空间
* 2、静态成员变量的声明和定义仅在首次加载类时执行一次
* 3、首次加载类时首先对所有静态成员变量根据类型默认赋初值,然后再对有右值的附右值
* 二、静态初始块
* 1、静态初始化块仅在首次加载类时执行一次
* ······多个静态成员变量与静态始化快参照出现顺序先后执行······
* 三、实例成员变量
* 1、实例成员变量定义在每次实例化对象时在构造函数之前执行
* 四、构造初始化块
* 1、构造初始化块在每次实例化对象时在构造函数之前执行
* ······多个实例成员变量与构造初始化块参照出现顺序先后执行······
* 总结:总的来说,在不涉及继承的前提下,当首次加载类时,按照如下顺序执行
* 1、按照出现顺序先后执行静态成员变量定义与静态初始化块
* 2、按照出现顺序先后执行实例成员变量定义与构造初始化块
* 3、执行构造函数
* 再次实例化对象时只执行第2、3步即可
*
* ············实例成员变量与定义与初始化块先于构造函数执行·········
* 五、当涉及到继承时,按照如下顺序执行
* 1、执行父类的静态成员变量定义与静态初始化块,执行子类的静态成员变量定义与静态初始化块
* 2、执行父类的非静态成员变量定义与构造初始化块,执行父类构造方法
* 3、执行子类的非静态成员变量定义与构造初始化块,执行子类构造方法
* 另:父类构造方法中用到的方法如果已被子类重写,那么在构造子类对象时在调用父类构造函数中使用子类重写的方法
*/ [/color]
package com.xjf.java.training;
public class StaticBlock {
public static void main(String[] args) {
int i = 1;
switch(i) {
case 0:
new Super();
new Super();
break;
case 1:
Super s = new Sub();
break;
case 2 :
Client c1 = new Client();
System.out.println("c.i1 = " + c1.i1);//2
System.out.println("c.i2 = " + c1.i2);//3
break;
}
/* 对i=2时的解释
* 为什么是2和3呢?
* 其实代码的执行顺序是这样的:在初始化c1的时候首先加载类
* 定义静态变量t1,i1,i2并赋初值null,0,0
* 然后计算右值表达式new Client(),准备将此对象赋给静态成员变量c
* 然而上步中静态成员变量已定义,直接执行c的构造函数即可
* 这样i1++,i2++被执行,i1,i2都变为1
* 继续执行到int i1;没有赋值语句, i1,i2的值仍然是1
* 继续执行到int i2 = 2时i2被赋值2,即i1 = 1,i2 = 2
* 继续执行到c1的构造函数,i1,i2再执行++,此时i1 = 2,i2 = 3
* 输出i1,i2,结果就是:c1.i1 = 2,c1.i2 = 3
* 通过上面的代码我们可以认为系统默认值的给予比通过等号的赋予先执行。
*/
}
}
class Super {
public Super() {
System.out.println("construct Super");
function();
System.out.println();
}
private int superInstanceVar = getSuperInstanceVar();
{
System.out.println(" contruct block in Super");
}
static {
System.out.println("static block in Super");
}
private static int superStaticVar = getSuperStaticVar();
static int getSuperStaticVar() {
System.out.println("initial static int superStaticVar");
System.out.println();
return 5;
}
static int getSuperInstanceVar() {
// TODO Auto-generated method stub
System.out.println("initial int superInstanceVar");
return 10;
}
public void function() {
System.out.println("super.function()");
}
}
class Sub extends Super{
public Sub() {
System.out.println("construct Sub");
super.function();
function();
}
{
System.out.println("contruct block in Sub");
}
private int subInstanceVar = getSubInstanceVar();
static {
System.out.println("static block in Sub");
}
private static int subStaticVar = getSubStaticVar();
static int getSubStaticVar() {
System.out.println("initial static int subStaticVar");
System.out.println();
return 5;
}
static int getSubInstanceVar() {
System.out.println("initial int subInstanceVar");
return 10;
}
public void function() {
System.out.println("sub.function() subInstanceVar=" + subInstanceVar);
}
}
class Client{
private static Client c = new Client();
public static int i1;
public static int i2 = 2;
public Client(){
i1++;
i2++;
}
}
[color=darkblue]/*
i=0时输出:
static block in Super--父类中静态代码块
initial static int superStaticVar--父类中静态方法显示初始化父类静态变量
initial int superInstanceVar--显示初始化父类实例变量
contruct block in Super--执行父类中的构造代码块
construct Super--执行父类构造方法
super.function()--调用父类方法
initial int superInstanceVar--显示初始化父类实例变量
contruct block in Super--执行父类中的构造代码块
construct Super--执行父类构造方法
super.function()--调用父类的function方法
---------------------------
i=1时输出:
static block in Super--父类中静态代码块
initial static int superStaticVar--父类中静态方法显示初始化父类静态变量
static block in Sub--显示初始化子类代码块
initial static int subStaticVar--显示初始化子类静态变量
initial int superInstanceVar-显示初始化父类实例变量
contruct block in Super--执行父类中的构造代码块
construct Super--执行父类构造方法
sub.function() subInstanceVar=0--父类调用子类复写的function方法,这里出现多态,此时子类中复写的function访问的是子类的subInstanceVar,
由于在父类初始化时子类还没有初始化,所以此时的值为隐式初始化的值即:默认值
contruct block in Sub--执行子类中的构造代码块
initial int subInstanceVar-显示初始化子类实例变量
construct Sub--执行子类构造方法
super.function()--子类调用父类function方法
sub.function() subInstanceVar=10--调用复写父类中的function方法
*/
[/color]