代码块又称为初始化块,属于类中的成员【即是类的一部分】,类似于方法,将逻辑语句封装在方法中,通过{}包围起来。但和方法名不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显示调佣,而是加载类时,或创建对象时隐式调用。 基本语法 [修饰符]{ 代码 } 1、修饰符 可选,要写的话,只能写static。 2、代码块分为俩类,使用static修饰的叫做静态代码块,没有static修饰的,叫做普通代码块。 3、逻辑语句可以为任何逻辑语句(输入,输出,方法调用,循环,判断等)。 4、; 号可以写上,也可以省略。 1、static代码块也叫静态代码块,作用就是对类进行初始化,而却它随着 类的加载 而执行,并且只会 执行一次。如果是普通代码块,每创建一个对象,就执行。 2、类什么时候被加载【重要背!!】 创建对象实例时(new)。 创建子类对象实例,父类也会被加载。 使用类的静态成员的时(静态属性,静态方法)。 3、普通的代码块,在创建对象实例时,会被隐式的调用。 被创建一次就会被调用一次。 如果只是使用类的静态成员时,普通代码块并不会执行。
public class CodeBlockDetail01 {
public static void main(String[] args) {
A a = new A();
A a2 = new A();
A.num();
}
}
class A{
private static int i =10;
static {
System.out.println("我是static代码块....");
};
{
System.out.println("我是普通代码块.....");
};
public static void num(){
System.out.println(i);
}
}
输出结果:
我是static代码块....
我是普通代码块.....
我是普通代码块.....
10
创建一个对象时,在一个类 调用顺序是: 1、调用惊天代码块和静态属性初始化 注意:静态代码块和静态属性初始化的优先级一样,如果有多个 静态变量初始化,则按他们定义的顺序调用。 2、调用普通代码块和普通属性的初始化 注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个 普通代码块和多个普通属性初始化,则按定义调用。 3、调用构造方法。
例子:
public class CodeBlockDetail02 {
public static void main(String[] args) {
AA aa = new AA();//get被调用 静态代码块 num被调用 普通代码块 构造器
}
}
class AA{
//无参构造器
public AA(){
System.out.println("构造器");
}
private static int a = AA.get();
private int b = AA.num();
{
System.out.println("普通代码块");
}
static {
System.out.println("静态代码块...");
}
public static int get(){
System.out.println("get被调用");
return 100;
}
public static int num(){
System.out.println("num被调用");
return 20;
}
}
可以看到输出的顺序是:
get被调用
静态代码块...
num被调用
普通代码块
构造器
构造器的最前面其实隐含了 super() 和 调用普通代码块,静态相关的代码块和属性初始化, 在类加载时就执行完毕,因此是优先于 构造器和普通代码块 执行的。以下例子可以看出:
public class CodeBlockDetail03 {
public static void main(String[] args) {
BB bb = new BB();
}
}
class AAA{
{
System.out.println("AAA的代码块");
}
public AAA(){
//隐藏的第一个:super();
//第二个:调用本类的普通代码块
System.out.println("AAA构造器");
}
}
class BB extends AAA{
{
System.out.println("BBB的普通代码块");
}
public BB(){
//隐藏的第一个:super();
//第二个:调用本类的普通代码块
System.out.println("BB构造器");
}
}
输出的结果:
AAA的代码块
AAA构造器
BBB的普通代码块
BB构造器
我们来看一下创建一个子类时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化, 构造方法的调用顺序如下: 1、父类的静态代码块和静态属性(优先级一样,按定义顺序执行) 2、子类的静态代码块和静态属性(优先级一样,按定义顺序执行) 3、父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行) 4、父类的构造方法 5、子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行) 6、子类的构造方法 //面试题 静态代码块只能直接调用静态成员,普通代码可以调用任意成员。
以下是例子和结果,大家可以理解一下
public class CodeBlockDetail04 {
public static void main(String[] args) {
F f = new F();
}
}
class D{
private static int a = D.sum();
static{
System.out.println("父类的静态代码块");
}
{
System.out.println("父类的普通代码块");
}
private int aa = sum1();
public static int sum(){
System.out.println("static 父类的sum方法被调用");
return 100;
}
public int sum1(){
System.out.println("父类的sum1 方法被调用");
return 100;
}
public D(){
System.out.println("父类的构造器");
}
}
class E extends D{
private int s = eee();
public int eee(){
System.out.println("eee 方法");
return 100;
}
private static int D = E.ee();
{
System.out.println("E的普通代码块");
}
public static int ee(){
System.out.println("static 子类E的DD方法被调用");
return 100;
}
static{
System.out.println("E的静态代码块");
}
public E(){
//super();
//代码块
System.out.println("E的构造器");
}
}
class F extends E{
static{
System.out.println("子类F的静态代码块");
}
{
System.out.println("子类F的普通代码块");
}
public F(){
System.out.println("F的构造器");
}
}
输出:
static 父类的sum方法被调用
父类的静态代码块
static 子类E的DD方法被调用
E的静态代码块
子类F的静态代码块
父类的普通代码块
父类的sum1 方法被调用
父类的构造器
eee 方法
E的普通代码块
E的构造器
子类F的普通代码块
F的构造器
进程已结束,退出代码0