• 面向对象编程(高级部分)——代码块


    目录

    1. 基本介绍

    2. 基本语法

    3. 代码块的好处和案例演示

    4. 代码块使用注意事项和细节讨论

    5. 代码块练习题


    1. 基本介绍

    2. 基本语法

    3. 代码块的好处和案例演示

    我们创建一个类

    1. class Movie{
    2. private String name;
    3. private double price;
    4. private String director;
    5. public Movie(String name) {
    6. System.out.println("电影屏幕打开...");
    7. System.out.println("广告开始...");
    8. System.out.println("电影正式开始...");
    9. this.name = name;
    10. }
    11. public Movie(String name, double price) {
    12. System.out.println("电影屏幕打开...");
    13. System.out.println("广告开始...");
    14. System.out.println("电影正式开始...");
    15. this.name = name;
    16. this.price = price;
    17. }
    18. public Movie(String name, double price, String director) {
    19. System.out.println("电影屏幕打开...");
    20. System.out.println("广告开始...");
    21. System.out.println("电影正式开始...");
    22. this.name = name;
    23. this.price = price;
    24. this.director = director;
    25. }
    26. }

    此时这个类里面的3个构造器构成了重载,我们在3个构造器里都要输出3个内容:电影屏幕打开,广告开始,电影正式开始。

    这样的话代码就比较冗余了,每个构造器都有这三句话,这时我们可以把相同的语句放入到一个代码块中即可

    1. public class CodeBlock01 {
    2. public static void main(String[] args) {
    3. Movie movie = new Movie("你好,李焕英");
    4. }
    5. }
    6. class Movie {
    7. private String name;
    8. private double price;
    9. private String director;
    10. {
    11. System.out.println("电影屏幕打开...");
    12. System.out.println("广告开始...");
    13. System.out.println("电影正式开始...");
    14. }
    15. public Movie(String name) {
    16. System.out.println("Movie(String name) 构造器 被调用");
    17. this.name = name;
    18. }
    19. public Movie(String name, double price) {
    20. this.name = name;
    21. this.price = price;
    22. }
    23. public Movie(String name, double price, String director) {
    24. this.name = name;
    25. this.price = price;
    26. this.director = director;
    27. }
    28. }

    这样的话,不管当我们调用哪个构造器创建对象,都会调用代码块的内容。

    此时我们执行一下:

    也就是说,代码块调用的顺序是优先于构造器的。


    4. 代码块使用注意事项和细节讨论

    (2) 类什么时候被加载

    1. 创建对象实例时

    1. public class CodeBlockDetail01 {
    2. public static void main(String[] args) {
    3. //类加载情况举例
    4. //1.创建对象实例(new)
    5. AA aa = new AA();
    6. }
    7. }
    8. class AA {
    9. //静态代码块
    10. static{
    11. System.out.println("AA 的静态代码块1被执行..");
    12. }
    13. }

    此时我们new一个AA创建对象实例,然后我们去运行

    这时候,AA的静态代码块被执行

    2. 创建子类对象实例,父类也会被加载

    1. public class CodeBlockDetail01 {
    2. public static void main(String[] args) {
    3. //类加载情况举例
    4. //2.创建子类对象实例,父类也会被加载
    5. AA aa = new AA();
    6. }
    7. }
    8. class AA extends BB{
    9. //静态代码块
    10. static{
    11. System.out.println("AA 的静态代码块1被执行..");
    12. }
    13. }
    14. class BB{
    15. static{
    16. System.out.println("BB 的静态代码块1被执行..");
    17. }
    18. }

    此时创建子类对象实例,父类也会被加载,而且父类先被加载,子类后被加载

    3. 使用类的静态成员时(静态属性、静态方法)

    1. public class CodeBlockDetail01 {
    2. public static void main(String[] args) {
    3. System.out.println(Cat.n1);
    4. }
    5. }
    6. class Cat{
    7. public static int n1 = 999; //静态属性
    8. static{
    9. System.out.println("Cat 的静态代码块1被执行..");
    10. }
    11. }

    此时我们在Cat类里面写一个静态属性,还写一个静态代码块,我们在main方法里去使用静态属性,也会导致静态代码块执行,并且是先执行静态代码块。


    1. public class CodeBlockDetail01 {
    2. public static void main(String[] args) {
    3. //类加载情况举例
    4. //1.创建对象实例(new)
    5. //AA aa = new AA();
    6. //2.创建子类对象实例,父类也会被加载
    7. //AA aa = new AA();
    8. //System.out.println(Cat.n1);
    9. DD dd = new DD();
    10. DD dd1 = new DD();
    11. }
    12. }
    13. class DD{
    14. static{
    15. System.out.println("DD 的静态代码1被执行...");
    16. }
    17. {
    18. System.out.println("DD 的普通代码块...");
    19. }
    20. }


    1. public class CodeBlockDetail01 {
    2. public static void main(String[] args) {
    3. System.out.println(DD.n1);
    4. }
    5. }
    6. class DD{
    7. public static int n1 = 88888; //静态属性
    8. static{
    9. System.out.println("DD 的静态代码1被执行...");
    10. }
    11. {
    12. System.out.println("DD 的普通代码块...");
    13. }
    14. }

    可以这样理解,普通代码块是构造器的补充,构造器被调用了,那么普通代码块也会被调用。构造器没被调用,普通代码块也不会被调用


    1. public class CodeBlockDetail02 {
    2. public static void main(String[] args) {
    3. A a = new A();
    4. }
    5. }
    6. class A{
    7. //静态属性的初始化
    8. private static int n1 = getN1();
    9. static{ //静态代码块
    10. System.out.println("A 静态代码块...");
    11. }
    12. public static int getN1(){
    13. System.out.println("getN1被调用...");
    14. return 100;
    15. }
    16. }

    那么此时我们将静态代码块放在最前面,输出顺序就变了

    1. public class CodeBlockDetail02 {
    2. public static void main(String[] args) {
    3. A a = new A();
    4. }
    5. }
    6. class A{
    7. static{ //静态代码块
    8. System.out.println("A 静态代码块...");
    9. }
    10. //静态属性的初始化
    11. private static int n1 = getN1();
    12. public static int getN1(){
    13. System.out.println("getN1被调用...");
    14. return 100;
    15. }
    16. }


    1. public class CodeBlockDetail02 {
    2. public static void main(String[] args) {
    3. A a = new A();
    4. }
    5. }
    6. class A{
    7. private int n2 = getN2();//普通属性的初始化
    8. { //普通代码块
    9. System.out.println("A 普通代码块01");
    10. }
    11. static{ //静态代码块
    12. System.out.println("A 静态代码块01");
    13. }
    14. //静态属性的初始化
    15. private static int n1 = getN1();
    16. public static int getN1(){
    17. System.out.println("getN1被调用...");
    18. return 100;
    19. }
    20. private int getN2() { //普通方法/非静态
    21. System.out.println("getN2被调用...");
    22. return 200;
    23. }
    24. }

    前面的静态属性和静态代码块肯定是没变的,那在输出完静态后,肯定是普通代码块了,普通代码块和普通属性的初始化也是按定义的顺序进行调用


    最后调用的才是构造器

    1. public class CodeBlockDetail02 {
    2. public static void main(String[] args) {
    3. A a = new A();
    4. }
    5. }
    6. class A{
    7. private int n2 = getN2();//普通属性的初始化
    8. { //普通代码块
    9. System.out.println("A 普通代码块01");
    10. }
    11. static{ //静态代码块
    12. System.out.println("A 静态代码块01");
    13. }
    14. //静态属性的初始化
    15. private static int n1 = getN1();
    16. public static int getN1(){
    17. System.out.println("getN1被调用...");
    18. return 100;
    19. }
    20. private int getN2() { //普通方法/非静态
    21. System.out.println("getN2被调用...");
    22. return 200;
    23. }
    24. public A(){
    25. System.out.println("A() 构造器被调用");
    26. }
    27. }


    结论:  

    1. public class CodeBlockDetail03 {
    2. public static void main(String[] args) {
    3. new BBB();
    4. }
    5. }
    6. class AAA{
    7. public AAA() {
    8. //(1)super()
    9. //(2)调用本类的普通代码块
    10. System.out.println("AAA() 构造器被调用....");
    11. }
    12. }
    13. class BBB extends AAA{
    14. {
    15. System.out.println("BBB的普通代码块...");
    16. }
    17. public BBB() {
    18. //(1)super()
    19. //(2)调用本类的普通代码块
    20. System.out.println("BBB() 构造器被调用");
    21. }
    22. }

    如果在AAA类里面加一个普通代码块,那就是在输出AAA的构造器之前,先输出父类的普通代码块


    1. public class CodeBlockDetail04 {
    2. public static void main(String[] args) {
    3. new B02();
    4. }
    5. }
    6. class A02 { //父类
    7. private static int n1 = getVal01();
    8. static {
    9. System.out.println("A02的一个静态代码块...");
    10. }
    11. {
    12. System.out.println("A02的一个普通代码块...");
    13. }
    14. public int n3 = getVal02();
    15. public static int getVal01() {
    16. System.out.println("getVal01");
    17. return 10;
    18. }
    19. public int getVal02() {
    20. System.out.println("getVal02");
    21. return 10;
    22. }
    23. public A02() {
    24. System.out.println("A02的构造器");
    25. }
    26. }
    27. class B02 extends A02 {
    28. private static int n3 = getVal03();
    29. static {
    30. System.out.println("B02 的一个静态代码块..");
    31. }
    32. public int n5 = getVal04();
    33. {
    34. System.out.println("B02 的第一个普通代码块..");
    35. }
    36. public static int getVal03() {
    37. System.out.println("getVal03");
    38. return 10;
    39. }
    40. public int getVal04() {
    41. System.out.println("getVal04");
    42. return 10;
    43. }
    44. public B02() {//构造器
    45. System.out.println("B02 的构造器");
    46. }
    47. }

     首先是类加载:
    1.先是父类的静态代码块和静态属性
      getVal01
    2.A02的一个静态代码块...
    3.然后是子类的静态代码块和静态属性
      getVal03
    4.B02 的一个静态代码块..
    5.这时候类加载好了,我们在main方法里new了一个子类B02;由于子类构造方法里super()和普通方法块,那么先去父类那里
      A02的一个普通代码块...
    6.getVal02
    7.最后要记得执行父类的构造器,不然回不去子类.
      A02的构造器
    8.那么现在回到子类的构造器继续执行子类的普通代码块
      getVal04
    9.B02 的第一个普通代码块..
    10.B02 的构造器 

    这是一个相对完整的一个对象构建顺序


      

    1. class C02{
    2. private int n1=100;
    3. private static int n2 = 200;
    4. private void m1(){}
    5. private static void m2(){}
    6. static{
    7. //静态代码块只能调用静态成员
    8. // System.out.println(n1); 错误
    9. System.out.println(n2); //ok
    10. // m1(); 错误
    11. m2();//ok
    12. }
    13. {
    14. //普通代码块,可以使用任意成员
    15. System.out.println(n1);
    16. System.out.println(n2);
    17. m1();
    18. m2();
    19. }
    20. }

    5. 代码块练习题

    输出结果:  

    in static block!
    total = 100
    total = 100 

    因为Person.total会让类加载,此时先去输出静态代码块的内容,然后再输出total的值 。


    输出内容:

    静态成员sam初始化
    static块执行
    sam1成员初始化
    Test默认构造函数被调用 

  • 相关阅读:
    macOS输入法卸载
    Python中如何使用__slots__限制对象属性来节约内存
    总不能因为杯子碎了就不再喝水了吧
    解密zkLogin:探索前沿的Sui身份验证解决方案
    分页查询(关键词: limit)
    基于 Stacking 的网络恶意加密流量识别方法
    行泊一体的“进阶战”打响,单芯片方案成主流趋势
    C# 语言在AGI 赛道上能做什么
    webpack构建vue项目 基础04 之图片base64转化、图片压缩
    dockerDesktop使用方法
  • 原文地址:https://blog.csdn.net/qq_44706176/article/details/126433095