Java——代码块
2018-12-02 15:04
78 查看
前言
在程序编写之中可以直接使用
{...}定义的一段语句就是代码块。根据代码块的位置以及关键字的不同可以分为4种:普通代码块、构造块、静态块以及同步代码块(多线程相关)。下面将先介绍前3种以及Java类的初始化顺序:
普通代码块
写在方法里面的代码块就是普通代码块
public static void main(String args[]){ { int num = 0; } int num=100; }
{...}表示的是一个作用域,内部定义的变量的可以起作用的范围仅在
{...}这个范围内。
上面代码中
{int num=0;}的num在离开
{...}后就被销毁了,于是可以在外部又可以定义
int num=100。
若是写成以下:
public static void main(String args[]){ int num=100; { int num = 0; //报错:Duplicate local variable num } }
因为外部也存在num这个变量,且有效。所以,这样定义会出错。
普通代码块的作用就是为了防止在方法中编写代码过多,产生变量重名,于是对一个方法中的代码进行局部的分割。但是建议一个方法中的代码不要太长,尽量不使用普通代码块
构造块
如果将一个代码块放在类里面,那么就是一个构造块。
构造块的作用是为了给对象进行初始化。我们知道构造函数的作用也是为了给对象进行初始化,那么这两者有什么区别呢?
public class Student { private String name; private int age; //无参构造函数 public Student() { System.out.println("constructor with no args "); System.out.println("name:"+this.name + " age:"+this.age); this.name = "no name"; this.age = 18; } //有参构造函数 public Student(String name, int age){ System.out.println("constructor with args"); System.out.println("name:"+this.name + " age:"+this.age); this.name = name; this.age = age; } //构造块 { System.out.println("constructor block "); name = "cbname"; age = 20; } public static void main(String[] args) { new Student(); System.out.println("=========="); new Student("sakura", 19); } } /* output: constructor block constructor with no args name:cbname age:20 ========== constructor block constructor with args name:cbname age:20 */
可以看出每次创建对象时,都会调用一次构造块,并且构造块的优先于构造函数执行。有对象的创建,才会调用构造快,类是不能调用构造块的。
构造块与构造函数的区别在于:每个对象被构造块初始化的那部分变量拥有的初始值是一样的,构造块对所有对象的效果是一样的。然而每个对象可能会使用不同构造函数,不同的构造函数初始化对象的方式是不同的。
静态块
使用static修饰的代码块就叫做静态代码块或者直接叫静态块。
前面在介绍
static关键字(可以回顾查看)时,介绍了一部分static修饰代码块的知识。
静态块在类加载时执行,且只会执行一次,执行顺序优先主函数、构造函数和构造块。
静态代码块主要用于初始化类中的static属性(类属性),而构造块是初始化对象中的属性
一个类中可以有多个静态代码块, 执行顺序依照静态代码块的声明顺序。静态代码块可以在类的任意位置定义,在方法中不可以声明静态块。
Java类的初始化顺序
对于一个类(没有继承)的初始化情况
public class Student { private String name="no name"; private int age=18; private static int id=1; //无参构造函数 public Student() { System.out.println("======"); System.out.println("无参构造函数"); System.out.println("姓名:"+name+" 年龄:"+age); } //有参构造函数 public Student(String name, int age){ System.out.println("======"); System.out.println("有参构造函数"); System.out.println("姓名:"+this.name+" 年龄:"+this.age); this.name = name; this.age = age; System.out.println("姓名:"+this.name+" 年龄:"+this.age); } //构造块 { System.out.println("======"); System.out.println("构造块"); System.out.println("姓名:"+this.name+" 年龄:"+this.age); this.name = "cbname"; this.age = 18; } //静态代码块 static { System.out.println("======"); System.out.println("静态块"); System.out.println("静态变量id="+id); } public static void main(String[] args) { System.out.println("======"); System.out.println("主方法"); new Student(); new Student("小王",20); } } /* output: ====== 静态块 静态变量id=1 ====== 主方法 ====== 构造块 姓名:no name 年龄:18 ====== 无参构造函数 姓名:cbname 年龄:18 ====== 构造块 姓名:no name 年龄:18 ====== 有参构造函数 姓名:cbname 年龄:18 姓名:小王 年龄:20 */
对于一个类而言:
静态代码块、构造代码块、构造函数和主函数的执行顺序为:
静态代码块>主函数>构造代码块>构造函数
在加上静态属性、普通属性,他们的初始化执行顺序就为:
静态变量、静态代码块 > 主函数 > 指定初始值的属性 > 构造代码块 > 构造函数
对于有继承的情况
class Person{ private String name="Person没有名字"; private int age=10; private static int id=1; //无参构造函数 public Person() { System.out.println("======"); System.out.println("Person无参构造函数"); System.out.println("Person 姓名:"+this.name+" 年龄:"+this.age); } //构造块 { System.out.println("======"); System.out.println("Person 构造块"); System.out.println("Person 姓名:"+this.name+" 年龄:"+this.age); this.name = "pcbname"; this.age =11 ; } //静态代码块 static { System.out.println("======"); System.out.println("Person 静态块"); System.out.println("Person 静态变量id="+id); } } public class Student extends Person{ private String name="Student没有名字"; private int age=18; private static int id=2; //无参构造函数 public Student() { //自动调用父类的无参构造函数 super(); System.out.println("======"); System.out.println("Student无参构造函数"); System.out.println("Student 姓名:"+this.name+" 年龄:"+this.age); } //有参构造函数 public Student(String name, int age) { //自动调用父类的无参构造函数 super(); System.out.println("======"); System.out.println("Student有参构造函数"); System.out.println("Student 姓名:"+this.name+" 年龄:"+this.age); this.name = name; this.age = age; } //构造块 { System.out.println("======"); System.out.println("Student 构造块"); System.out.println("Student 姓名:"+this.name+" 年龄:"+this.age); this.name = "scbname"; this.age = 19; } //静态代码块 static { System.out.println("======"); System.out.println("Student 静态块"); System.out.println("Student 静态变量id="+id); } public static void main(String[] args) { System.out.println("======"); System.out.println("主方法"); System.out.println("\n--------第一次创建Studet对象--------"); new Student(); System.out.println("\n--------第二次创建Studet对象--------"); new Student("小夏",20); } } /* ====== Person 静态块 Person 静态变量id=1 ====== Student 静态块 Student 静态变量id=2 ====== 主方法 --------第一次创建Studet对象-------- ====== Person 构造块 Person 姓名:Person没有名字 年龄:10 ====== Person无参构造函数 Person 姓名:pcbname 年龄:11 ====== Student 构造块 Student 姓名:Student没有名字 年龄:18 ====== Student无参构造函数 Student 姓名:scbname 年龄:19 --------第二次创建Studet对象-------- ====== Person 构造块 Person 姓名:Person没有名字 年龄:10 ====== Person无参构造函数 Person 姓名:pcbname 年龄:11 ====== Student 构造块 Student 姓名:Student没有名字 年龄:18 ====== Student有参构造函数 Student 姓名:scbname 年龄:19 */
观察代码结果,分析,对于有继承关系的类,初始化顺序按如下进行:
- 执行父类的静态代码块,并初始化父类静态成员变量
2. 执行子类的静态代码块,并初始化子类静态成员变量
3. 执行父类的构造代码块,执行父类的构造函数,若普通成员变量指定了初始值则先执行初始值的赋值,然后返回执行构造函数
4.执行子类的构造代码块,执行子类的构造函数,若普通成员变量指定了初始值则先执行初始值的赋值,然后返回执行构造函数
小结
本文介绍的三种代码块,普通块和构造块都不建议使用,静态块可以使用用于初始化静态变量。
理清Java程序初始化的执行顺序可以很清楚地掌握程序的执行过程。
对一个类而言,
静态变量和静态代码块> 主函数 > 指定初始值的属性 > 构造代码块 > 构造函数
对于有继承的来说,
父类静态块和静态变量 > 子类静态块和静态变量 > 父类指定初始值的属性 > 父类构造块 > 父类构造函数 > 子类指定初始值的属性 > 子类构造块 > 子类构造函数
相关文章推荐
- java的代码块
- Java复习笔记(七)-----代码块
- Java的四种代码块
- Java中成员变量、构造方法、代码块执行顺序剖析
- java中静态代码块的用法和static用法详解
- java中静态代码块,构造代码块,静态代码块的区别
- java中代码执行顺序(静态代码块、构造函数)
- Java基础-08总结帮助文档,代码块,继承
- Java Static代码块与构造方法初始化顺序
- java中成员变量、代码块、构造函数执行顺序
- Java的四种代码块说明
- java中的静态变量、静态方法与静态代码块区别
- jsp <%%>java代码块获取<s:property的值
- java四种代码块
- 由阿里巴巴一道笔试题看Java静态代码块、静态函数、动态代码块、构造函数等的执行顺序
- java 静态代码块,构造器(二)
- java中静态代码块的用法 static用法详解
- Java初始代码块的执行顺序
- Java静态代码块和静态方法的区别
- Java初始化顺序总结 - 静态变量、静态代码块、成员变量、构造函数