目录
我们创建一个类
- 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;
- }
- }
这样的话,不管当我们调用哪个构造器创建对象,都会调用代码块的内容。
此时我们执行一下:
也就是说,代码块调用的顺序是优先于构造器的。
(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();
- }
- }
输出结果:
in static block!
total = 100
total = 100
因为Person.total会让类加载,此时先去输出静态代码块的内容,然后再输出total的值 。
输出内容:
静态成员sam初始化
static块执行
sam1成员初始化
Test默认构造函数被调用