目录
1. 基本介绍
2. 基本语法
3. 代码块的好处和案例演示
我们创建一个类
class Movie{
private String name;
private double price;
private String director;
public Movie(String name) {
System.out.println("电影屏幕打开...");
System.out.println("广告开始...");
System.out.println("电影正式开始...");
this.name = name;
}
public Movie(String name, double price) {
System.out.println("电影屏幕打开...");
System.out.println("广告开始...");
System.out.println("电影正式开始...");
this.name = name;
this.price = price;
}
public Movie(String name, double price, String director) {
System.out.println("电影屏幕打开...");
System.out.println("广告开始...");
System.out.println("电影正式开始...");
this.name = name;
this.price = price;
this.director = director;
}
}
此时这个类里面的3个构造器构成了重载,我们在3个构造器里都要输出3个内容:电影屏幕打开,广告开始,电影正式开始。
这样的话代码就比较冗余了,每个构造器都有这三句话,这时我们可以把相同的语句放入到一个代码块中即可
public class CodeBlock01 {
public static void main(String[] args) {
Movie movie = new Movie("你好,李焕英");
}
}
class Movie {
private String name;
private double price;
private String director;
{
System.out.println("电影屏幕打开...");
System.out.println("广告开始...");
System.out.println("电影正式开始...");
}
public Movie(String name) {
System.out.println("Movie(String name) 构造器 被调用");
this.name = name;
}
public Movie(String name, double price) {
this.name = name;
this.price = price;
}
public Movie(String name, double price, String director) {
this.name = name;
this.price = price;
this.director = director;
}
}
这样的话,不管当我们调用哪个构造器创建对象,都会调用代码块的内容。
此时我们执行一下:
也就是说,代码块调用的顺序是优先于构造器的。
4. 代码块使用注意事项和细节讨论
(2) 类什么时候被加载
1. 创建对象实例时
public class CodeBlockDetail01 { public static void main(String[] args) { //类加载情况举例 //1.创建对象实例(new) AA aa = new AA(); } } class AA { //静态代码块 static{ System.out.println("AA 的静态代码块1被执行.."); } }
此时我们new一个AA创建对象实例,然后我们去运行
这时候,AA的静态代码块被执行
2. 创建子类对象实例,父类也会被加载
public class CodeBlockDetail01 { public static void main(String[] args) { //类加载情况举例 //2.创建子类对象实例,父类也会被加载 AA aa = new AA(); } } class AA extends BB{ //静态代码块 static{ System.out.println("AA 的静态代码块1被执行.."); } } class BB{ static{ System.out.println("BB 的静态代码块1被执行.."); } }
此时创建子类对象实例,父类也会被加载,而且父类先被加载,子类后被加载
3. 使用类的静态成员时(静态属性、静态方法)
public class CodeBlockDetail01 { public static void main(String[] args) { System.out.println(Cat.n1); } } class Cat{ public static int n1 = 999; //静态属性 static{ System.out.println("Cat 的静态代码块1被执行.."); } }
此时我们在Cat类里面写一个静态属性,还写一个静态代码块,我们在main方法里去使用静态属性,也会导致静态代码块执行,并且是先执行静态代码块。
public class CodeBlockDetail01 {
public static void main(String[] args) {
//类加载情况举例
//1.创建对象实例(new)
//AA aa = new AA();
//2.创建子类对象实例,父类也会被加载
//AA aa = new AA();
//System.out.println(Cat.n1);
DD dd = new DD();
DD dd1 = new DD();
}
}
class DD{
static{
System.out.println("DD 的静态代码1被执行...");
}
{
System.out.println("DD 的普通代码块...");
}
}
public class CodeBlockDetail01 {
public static void main(String[] args) {
System.out.println(DD.n1);
}
}
class DD{
public static int n1 = 88888; //静态属性
static{
System.out.println("DD 的静态代码1被执行...");
}
{
System.out.println("DD 的普通代码块...");
}
}
可以这样理解,普通代码块是构造器的补充,构造器被调用了,那么普通代码块也会被调用。构造器没被调用,普通代码块也不会被调用
public class CodeBlockDetail02 {
public static void main(String[] args) {
A a = new A();
}
}
class A{
//静态属性的初始化
private static int n1 = getN1();
static{ //静态代码块
System.out.println("A 静态代码块...");
}
public static int getN1(){
System.out.println("getN1被调用...");
return 100;
}
}
那么此时我们将静态代码块放在最前面,输出顺序就变了
public class CodeBlockDetail02 {
public static void main(String[] args) {
A a = new A();
}
}
class A{
static{ //静态代码块
System.out.println("A 静态代码块...");
}
//静态属性的初始化
private static int n1 = getN1();
public static int getN1(){
System.out.println("getN1被调用...");
return 100;
}
}
public class CodeBlockDetail02 {
public static void main(String[] args) {
A a = new A();
}
}
class A{
private int n2 = getN2();//普通属性的初始化
{ //普通代码块
System.out.println("A 普通代码块01");
}
static{ //静态代码块
System.out.println("A 静态代码块01");
}
//静态属性的初始化
private static int n1 = getN1();
public static int getN1(){
System.out.println("getN1被调用...");
return 100;
}
private int getN2() { //普通方法/非静态
System.out.println("getN2被调用...");
return 200;
}
}
前面的静态属性和静态代码块肯定是没变的,那在输出完静态后,肯定是普通代码块了,普通代码块和普通属性的初始化也是按定义的顺序进行调用
最后调用的才是构造器
public class CodeBlockDetail02 {
public static void main(String[] args) {
A a = new A();
}
}
class A{
private int n2 = getN2();//普通属性的初始化
{ //普通代码块
System.out.println("A 普通代码块01");
}
static{ //静态代码块
System.out.println("A 静态代码块01");
}
//静态属性的初始化
private static int n1 = getN1();
public static int getN1(){
System.out.println("getN1被调用...");
return 100;
}
private int getN2() { //普通方法/非静态
System.out.println("getN2被调用...");
return 200;
}
public A(){
System.out.println("A() 构造器被调用");
}
}
结论:
public class CodeBlockDetail03 {
public static void main(String[] args) {
new BBB();
}
}
class AAA{
public AAA() {
//(1)super()
//(2)调用本类的普通代码块
System.out.println("AAA() 构造器被调用....");
}
}
class BBB extends AAA{
{
System.out.println("BBB的普通代码块...");
}
public BBB() {
//(1)super()
//(2)调用本类的普通代码块
System.out.println("BBB() 构造器被调用");
}
}
如果在AAA类里面加一个普通代码块,那就是在输出AAA的构造器之前,先输出父类的普通代码块
public class CodeBlockDetail04 {
public static void main(String[] args) {
new B02();
}
}
class A02 { //父类
private static int n1 = getVal01();
static {
System.out.println("A02的一个静态代码块...");
}
{
System.out.println("A02的一个普通代码块...");
}
public int n3 = getVal02();
public static int getVal01() {
System.out.println("getVal01");
return 10;
}
public int getVal02() {
System.out.println("getVal02");
return 10;
}
public A02() {
System.out.println("A02的构造器");
}
}
class B02 extends A02 {
private static int n3 = getVal03();
static {
System.out.println("B02 的一个静态代码块..");
}
public int n5 = getVal04();
{
System.out.println("B02 的第一个普通代码块..");
}
public static int getVal03() {
System.out.println("getVal03");
return 10;
}
public int getVal04() {
System.out.println("getVal04");
return 10;
}
public B02() {//构造器
System.out.println("B02 的构造器");
}
}
首先是类加载:
1.先是父类的静态代码块和静态属性
getVal01
2.A02的一个静态代码块...
3.然后是子类的静态代码块和静态属性
getVal03
4.B02 的一个静态代码块..
5.这时候类加载好了,我们在main方法里new了一个子类B02;由于子类构造方法里super()和普通方法块,那么先去父类那里
A02的一个普通代码块...
6.getVal02
7.最后要记得执行父类的构造器,不然回不去子类.
A02的构造器
8.那么现在回到子类的构造器继续执行子类的普通代码块
getVal04
9.B02 的第一个普通代码块..
10.B02 的构造器
这是一个相对完整的一个对象构建顺序
class C02{
private int n1=100;
private static int n2 = 200;
private void m1(){}
private static void m2(){}
static{
//静态代码块只能调用静态成员
// System.out.println(n1); 错误
System.out.println(n2); //ok
// m1(); 错误
m2();//ok
}
{
//普通代码块,可以使用任意成员
System.out.println(n1);
System.out.println(n2);
m1();
m2();
}
}
5. 代码块练习题
输出结果:
in static block!
total = 100
total = 100
因为Person.total会让类加载,此时先去输出静态代码块的内容,然后再输出total的值 。
输出内容:
静态成员sam初始化
static块执行
sam1成员初始化
Test默认构造函数被调用