Java学习-Day14(静态方法、main方法、代码块、单例设计模式)

类方法(静态方法)

  • 形式如下

    访问修饰符 static 数据返回类型 方法名(){} 推荐

    static 访问修饰符 数据返回类型 方法名(){}

  • 类方法调用

    类名.类方法名 或者 对象名.类方法名

  • 当方法使用了static修饰后,该方法就是静态方法

  • 静态方法就可以访问静态属性/变量

  • 使用场景:当方法中不涉及到任何和对象相关的常用,则可以将方法设计成静态方法,提高开发效率

  • 注意事项和细节

    1. 类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区;类方法中无this的参数,普通方法中隐含this的参数
    2. 普通方法与对象有关,需要通过对象名调用,不能通过类名调用
    3. 类方法中不允许和对象有关的关键字,如this和super,普通方法是可以的
    4. 类方法中只能访问静态方法和静态变量
    5. 普通成员方法,既可以访问非静态成员,也可以访问静态成员
    6. 要遵守访问权限规则

main()方法

  1. main方法由java虚拟机调用
  2. java虚拟机需要调用main()方法,所以权限必须是public
  3. java虚拟机在执行main方法时不需要创建对象,所以该方法必须是static
  4. 该方法接受String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数
  5. java执行的程序 参数1 参数2 参数3
  6. 在main()方法中,我们可以直接调用main方法所在类的静态方法和静态属性
  7. 但是不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象区访问该类中的非静态成员
public class leetcode {
    public static void printInfo() {
        System.out.println(".....");
    }

    static int n = 1;
    int m = 2;
    public void show(){
        System.out.println(",,,,,,,");
    }

    public static void main(String[] args) {
        leetcode.printInfo();       //静态方法,可以访问
        System.out.println(leetcode.n); //静态变量,可以访问
        
        leetcode.show();        //非静态方法,不能访问,报错
        System.out.println(leetcode.m); //非静态变量,不能访问,报错
        Leetcode leetcode = new Leetcode(); //new一个Leetcode 对象
        leetcode.show();        //可以访问非静态方法
        System.out.println(leetcode.m);     //可以访问非静态变量
    }
}

main动态传值

给main中的args传参数步骤:

  • 先跑一下程序
  • 绿色的三角形运行按钮,左边选择Edit Configurations
  • Application下选择所需的main方法,在Program arguments输入框输入即可

代码块

  • 基本介绍

    代码块又称为初始化块,属于类中的成员(即是类的一部分)类似于方法,将逻辑语句封装在方法体中,通过{}包围起来

    但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时或者创建对象时隐式调用

  • 基本语法

    修饰符{

    ​ 代码

    };

    说明注意:

    1. 修饰符可选,要写也只能写static
    2. 代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块/非静态代码块
    3. 逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)
    4. ;可以写上,也可以省略
  • 好处:

    1. 相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作

    2. 如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用性

      public class Movie {
          public String name;
          public String price;
          public String director;
      
          {
              System.out.println("请等候电影开始。。。");   //代码块的调用优先于构造器
              System.out.println("电影开始了。。。");     //不管使用哪个构造器,都会调用代码块的内容
          }
          public Movie(String name) {
              this.name = name;
          }
      
          public Movie(String name, String price) {
              this.name = name;
              this.price = price;
          }
      
          public Movie(String name, String price, String director) {
              this.name = name;
              this.price = price;
              this.director = director;
          }
      }
      
      
  • 注意事项和细节

    1. static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块每创建一个对象就执行

    2. 类什么时候被加载

      • 创建对象实例时(new)
      • 创建子类对象实例,父类也会被加载,而且父类先于子类
      • 使用类的静态成员时(静态方法,静态属性)
    3. 普通的代码块,在创建对象实例时,会被隐式的调用。被创建一次,就调用一次。如果只是使用类的静态成员时,普通代码块并不会被执行

    4. 调用类的静态变量→类被加载→静态代码块执行(只会执行一次)

    5. 创建一个对象时,在一个类调用顺序是:

      • 调用静态代码块和静态属性初始化(静态代码块和静态属性初始化调用的优先级相同,如果有多个静态代码块和多个静态变量初始化,则按定义的先后顺序调用)
      • 调用普通代码块和普通属性的初始化(普通代码块和普通属性的初始化调用的优先级相同,如果有多个普通代码块和多个普通属性初始化,则按定义的先后顺序调用
      • 调用构造方法

      总之,静态代码块/属性 > 普通代码块/属性 > 构造方法

    6. 构造方法的最前面其实隐含了super()和调用普通代码块

      public class Test {
          public static void main(String[] args) {
              new B();
              /*
              输出如下:
              A的普通代码块被调用。。。
              A的构造器被调用。。。
              B的普通代码块被调用。。。
              B的构造器被调用。。。
               */
          }
      }
      
      class A {
          {
              System.out.println("A的普通代码块被调用。。。");
          }
      
          public A() {
              //super()
              //普通代码块
              System.out.println("A的构造器被调用。。。");
          }
      
      }
      
      class B extends A {
          {
              System.out.println("B的普通代码块被调用。。。");
          }
      
          public B() {
              /*
              隐含两个语句:
              1、super()
              2、调用普通代码块
               */
              System.out.println("B的构造器被调用。。。");
          }
      }
      
    7. 创建一个子类对象时(继承关系),静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:

      1. 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
      2. 子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
      3. 父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
      4. 父类的构造方法
      5. 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
      6. 子类的构造方法

      总的来说,先是父,再是子,先静态,再普通

    8. 创建对象分两步:

      • 类加载(父→子)

        此时静态变量/方法被调用

      • 创建对象

        此时普通代码块、普通属性初始化、构造器被调用

    9. 静态代码块之恶能直接调用静态成员,普通方法块可以调用任意成员

    10. 代码块放在构造器前后并无要求,总是在super()后被调用

单例设计模式

  • 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格以及解决问题的思考方式。

  • 单例模式(单个实例)

    1. 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
    2. 单例模式有两种方式:饿汉式和懒汉式
  • 饿汉式步骤

    1. 构造器私有化(防止用户直接new)

    2. 类的内部创建对象(该对象是static)

    3. 向外暴露一个静态公共方法

    4. 代码实现

      public class Test {
          public static void main(String[] args) {
              GirlFriend girlFriend = GirlFriend.getInstance();
              System.out.println(girlFriend.getName());
          }
      }
      
      class GirlFriend {
          private GirlFriend(String name) {
              this.name = name;
          }
      
          public static int n = 100;
          
          private String name;
      
          private static GirlFriend girlFriend = new GirlFriend("小红");
      
          public static GirlFriend getInstance() {
              return girlFriend;
          }
      
          public String getName(){
              return this.name;
          }
      }
      /*
      为什么叫饿汉式?
      如果main方法中需要调用n,直接GirlFriend.n即可,但需要类加载,所以也会创建girlFriend实例,构造器也被调用,对象也就有了(所以饿汉式有时创建对象但是没有使用,出现资源浪费,所以出现了懒汉式)
      */
      
  • 懒汉式步骤:

    1. 构造器私有化

    2. 定义一个static静态属性对象

    3. 通过一个public的static方法,可以返回一个对象

    4. 懒汉式只有当用户使用getInstance时,才返回cat对象,再次调用时,还是会返回上次的对象(地址相同)

      class Cat{
          private String name;
          private static Cat cat;
      
          private Cat(String name) {
              this.name = name;
          }
      
          public static Cat getInstance(){
              if(cat == null){
                  //此时如果有多个线程同时访问,且cat对象还没建立,就会同时建立多个cat对象
                  //违背了单例模式,可以通过加锁解决
                  cat =new Cat("李白");
              }
              return cat;
          }
      
          public String getName() {
              return name;
          }
      }
      
  • 饿汉式和懒汉式对比

    1. 二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建
    2. 饿汉式不存在线程安全问题,懒汉式存在线程安全问题
    3. 饿汉式存在浪费资源的可能, 因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题
    4. 在javaSE标准类中,java.lang.Runtime就是经典的单例模式
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晚来舟Mango

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值