写点什么

Java 之 static 关键字的应用【工具类、代码块和单例】

作者:Fire_Shield
  • 2022 年 9 月 20 日
    浙江
  • 本文字数:6029 字

    阅读完需:约 20 分钟

Java之static关键字的应用【工具类、代码块和单例】

在上一篇文章讲完了 static 关键字的一些基础知识后,我们就来说一说这个关键字在应用开发中具体可以怎么使用吧,希望看完这篇文章可以对您有帮助:book:


@TOC

一、工具类

1、什么是工具类?

类中都是一些静态方法,每个方法都是以完成一个公用的功能为目的,这个类用来给系统开发人员共同使用的

2、使用工具类有什么好处?

一是调用方便,二是提高了代码复用【一次编写,处处可用】

3、具体案例介绍

(1)随机生成验证码

我们平常在生活中都会遇到很多的验证码需要输入,比如登录注册、修改密码、查询访问,所以验证码处处可在,但是在开发过程中,难道我们开发人员每次遇到一个需要验证码的场合就重新写一次代码,那这样的开发效率就太低了,因此就产生了==工具类==


  • 具体 Java 代码如下


//Util工具类public static String CreateVerifiableCode(int n){    String Code = "";    String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random r = new Random(); for (int i = 0; i < n; i++) { int index = r.nextInt(data.length()); //0 - data.length - 1 Code += data.charAt(index); //连接所产生的随机字符 } return Code;}
复制代码


//登录注册类public static void main(String[] args) {    System.out.println(ItheimaUtl.CreateVerifiableCode(3));}
复制代码


//异常检查类public static void main(String[] args) {    System.out.println(ItheimaUtl.CreateVerifiableCode(6));    //ItheimaUtl i = new ItheimaUtl();      工具类构造器被私有化,无法创建对象}
复制代码


  • 可以看到,登录注册类和异常检查类中,都是直接通过类名去访问了验证码方法,因为这个验证码是写在静态方法中的,如果你对 Java 中的静态方法还不太了解,那就看看这篇原来实例成员变量和类成员变量可以这么区分!,因为是静态方法,所以我们可以直接使用类去调用,==但这不是在同一类中,所以不可以省略类名==,这一小细节也是比较关键:wind_chime:

  • 在异常检查类中我们可以看到无法用工具类构造器去构造一个对象,这个我们在注意事项中讲哈

(2)数组工具类

对于数组这个数据结构,大家应该在刚刚接触 C 语言的时候有已经使用过了,经常会让我们去遍历输出一个数组中的所有内容,这个时候的正常操作就是通过一个 for 循环去遍历,但是如果每次我们输出一个数组都这样去操作,那也会降低开发效率,因此这个也可以定义成工具类


  • 具体 Java 代码如下


public static String ToString(int[] arr){    if(arr == null)        return null;    String result = "[";    for (int i = 0; i < arr.length; i++) {        result += (i == arr.length - 1 ? arr[i] : arr[i] + ", ");    }    result += "]";    return result;}
复制代码


有关代码的内容我就不解释了,都是基本的操作,就是多了一个三元运算符,这就是一个简略代码段的操作,相当于 if 分支,不知道的小伙伴们可以去单独学习一下:mag_right:


//主函数实现类public static void main(String[] args) {    int[] arr1 = null;    int[] arr2 = {};    int[] arr3 = {12,66,33,48};
System.out.println(ArrayUtil.ToString(arr1)); System.out.println(ArrayUtil.ToString(arr2)); System.out.println(ArrayUtil.ToString(arr3));}
复制代码


运行结果


4、注意事项

  • 对于工具类中的方法,我们最好使用静态方法去做,不要用实例方法做,因为我们知道,实例方法需要创建对象调用,所以必须要构建一个新的对象,这样就会浪费内存,会降低开发的成本

  • 而且在工具类定义的时候,建议把其构造器私有化,这样就可以防止外部人员去通过这个工具类创建对象,因为一个类在创建的时候会有系统提供的默认构造器,对于我们上面提到的两个工具类,在其开头都应该加上以下代码,不仅是为了开发的安全着想,==而且这样可以显得你很专业==:mortar_board:


private ItheimaUtl(){    //验证码}
private ArrayUtil(){ //数组}
复制代码

二、代码块

1、什么是代码块?

对于代码块,它是类的五大成分之一(成员变量、构造器、方法、代码块、内部类)


在 Java 中,使用{}括起来的代码被称为代码块

2、代码块的分类

静态代码块(重点了解)

  • 格式:static{}

  • 特点:属于类,与类一起优先加载,自动触发执行一次

  • 作用:可以用在程序启动时,进行静态资源的初始化操作

  • 代码实例


public static String name;public static ArrayList<String> card = new ArrayList<>();/* *静态代码块:有static修饰,属于类,与类一起优先加载,自动触发执行 * 作用:可以用于初始化静态资源 */static{    name = "Fire";    System.out.println("Let's go");    card.add("#");}public static void main(String[] args) {    System.out.println("name = " + name);    System.out.println("Ok");}
复制代码


  • 运行结果


从上述代码可以看到,我定义了一个静态成员变量 name,一个静态集合容器 ArrayList,在 static 代码块中,我分别都对它们进行了初始化,一些需要在程序一启动就初始化好的变量可以放在此处加载


从运行结果中可以看出,==Let's go 这句代码在最前面执行==,因为其放在静态代码块中,是优先于所有代码先行加载的,当然最先执行的是 name = "Fire"这句代码,只是后面打印而已

构造代码块(很少使用)

  • 格式:{}

  • 特点:属于对象,每次调用构造器构建对象前都会执行一次,再执行构造器

  • 作用:可以用于初始化实例资源

  • 代码实例


String name;StaticDemo2(){    System.out.println("===无参构造被触发执行===");}/** *实例代码块:无static修饰,属于对象,每次构建对象时,都会触发一次执行 * */{    System.out.println("===实例代码块被触发执行===");    name = "gg";}public static void main(String[] args) {    StaticDemo2 st1 = new StaticDemo2();    System.out.println("name = " + st1.name);    StaticDemo2 st2 = new StaticDemo2();    System.out.println("name = " + st2.name);}
复制代码


  • 运行结果


从上述代码我们可以看出构造代码块会在每次构建对象之前调用,也就是会在构造方法之前,从运行结果我们就可以看出来。我这里是构建了两个对象,它就会调用两次构造代码块


不仅如此,构造代码块还可以用于==初始化实例资源==,这里我定义了一个姓名 name,在代码块中进行一个初始化,然后在分别打印这两个对象的姓名时,发现他们的姓名都是一样的,就是因为实例代码块都是在构建对象前就已经跑过了,所以无论你去构建多少对象,它们都是相同的


但我们知道在程序中每个对象的成员变量都要不一样,这样才能体现类与对象的特性,所以这个代码块在开发中很少用到,大家了解即可,重点在于【静态代码块】:bell:

3、应用案例展示

不墨迹,先上代码:point_down:


//1.定义一个静态的集合,存放所有扑克,一个房间只需要一副牌public static ArrayList<String> cards = new ArrayList<>();
//2.在程序运行前,初始化静态数据,将这些牌放进去static{ //静态代码块 - 只加载一次 //a.定义一个数组存储所有点数 - 个数确定,类型确定 String[] size = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"}; //b.定义一个数组存储所有花色 - 个数确定,类型确定 String[] colors = {"♥","♠","♦","♣"};
for (int i = 0; i < size.length; i++) { for (int j = 0; j < colors.length; j++) { String card = size[i] + colors[j]; cards.add(card); } cards.add("\n"); } //c.单独加入大小王 cards.add("小王"); cards.add("大王");}public static void main(String[] args) { //3.显示牌 System.out.println("54张牌为"); System.out.println(" " + cards);}
复制代码


运行结果



  • OK,我们来讲解一下,这个案例是关于初始化一幅扑克牌的案例,扑克相信大家从小到大都玩过,当我们去买一副牌摊开后往往四种花色的相同点数都是放在一起的,从运行结果就可以看出

  • 这个案例就很好地展现了静态代码块的在开发中的实用性。首先是定义了一个公开的静态扑克集合,这样就可以在静态代码块中对其进行初始化

  • 然后我们需要一个【点数的集合】和一个【花色的集合】,要先去遍历每个点数,然后遍历四种花色,这样就是四张四张打印出来,最大再加上大小王即可

三、单例

1、设计模式介绍

设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性,在开发中遇到很多问题,一个问题会有多种解法,而最优的那一个称为设计模式


具体大家想深入了解的可以看看这篇博客Java常见设计模式总结

2、单例模式的概念

单例模式可以确保在系统中,应用该模式的时候永远只会有一个实例,即一个类只能创建一个对象。因为我们在开发中,有些东西往往只需要一个对象就够了,对象多了:dog:就会占内存

3、单例模式的优缺点

  • 优点


单例模式可以帮助我们在实现一个类时只创建一个对象,从而节省空间,提高系统性能:runner:


  • 缺点


当想实例化一个单例类的时候,==必须要记住使用相应的获取对象的方法==,而不是使用 new,可能会给其他开发人员造成困扰,特别是看不到源码的时候

4、饿汉单例

单例模式有七八种,这里我们讲解一下常用的两种:balloon:

①实现步骤

1.定义一个类,然后把构造器私有化,为的是不然外界轻易访问 2.定义一个静态变量去存储一个对象,为的是实现单例的功能


//饿汉单例 - 已提前构建好一个对象public class SingleInstance {    //1.构造器私有化    private SingleInstance(){}
//2.饿汉单例在获取对象前,对象已经提前准备好了, // 这个对象只能是一个,所以定义静态成员变量记住 public static SingleInstance instance = new SingleInstance();}
复制代码


public static void main(String[] args) {    SingleInstance s1 = SingleInstance.instance;    SingleInstance s2 = SingleInstance.instance;    System.out.println(s1 == s2);    //该对象只会生成一个,两个对象的地址相同}
复制代码


以上这个测试结果为 true,就不显示了

②细究原理(仔细琢磨)


  • 有小伙伴可能看到这句代码比较疑惑,但是我这样比较一下,应该就可以很清晰的看出来了,public 表示它们都是共有的,而且带有 static 关键字表明它们是静态成员变量,SingleInstance 表示的就是这个对象的类型,也就是这个类,后面的 new SingleInstance()就类似于初始化的一串数据

  • 所以饿汉单例在获取对象前,对象已经提前准备好了,当我们在主函数中用类名访问这个静态成员变量时,对象就会给到 s1,这里就体现了单例的缺陷,必须要记住使用相应的获取对象的方法,不过有代码自动补全还好。可当我们在创建第二个对象时,可以看出它和第一个对象所指向的内存地址是同一块,所以显示出来的是 true,原因就是单例的特性——只能对外创建一个对象


public static SingleInstance instance = new SingleInstance();public static int age = 18;
复制代码

5、懒汉单例

看完了饿汉单例,接下来我们来了解一下另一种单例模式——懒汉单例

①实现步骤

1.定义一个类,然后将构造器私有化,不让外界访问 2.声明一个静态变量,但是不为其初始化构建对象 3.提供一个返回单例对象的方法,在真正需要用时返回对象


//懒汉单例 - 访问时才产生对象public class SingleInstance2 {    //1.构造器私有化    private SingleInstance2(){}
//2.定义一个静态变量存储对象,只调用一次 private static SingleInstance2 instance2; //private私有化,使得外界无法访问到此静态变量
//3.提供一个方法,对象返回单例对象 public static SingleInstance2 getInstance2() { if(instance2 == null){ //若instance2为空,表示第一次来拿对象 instance2 = new SingleInstance2(); } //若不为空,则表示是第二次及以上来获取对象,直接返回上一个创建的对象即可 return instance2; }}
复制代码


public static void main(String[] args) {    SingleInstance2 s1 = SingleInstance2.getInstance2();    SingleInstance2 s2 = SingleInstance2.getInstance2();    //两个对象相同,第二次创建对象时还是第一个的地址    System.out.println(s1);    System.out.println(s2);}
复制代码


运行结果


②细究原理(大力推荐)

饿汉单例的原理就是,在你真正需要用到对象的时候才去调用方法接口创建,而不是像懒汉单例一样在事先给你创建好


  • 对于构造器,和饿汉单例一样,都是要将其私有化,不让外界轻易访问,第二步,就是定义一个静态变量去存储要构建的对象,但在这里先不对其进行初始化

  • 而且尤其要注意的一点是,这个静态变量我定义成了 private 私有化,那有些小伙伴就惊呆了,静态变量本身就是公开的,怎么能私有化呢?这里举一个案例


SingleInstance s3 = SingleInstance.instance;SingleInstance s4 = SingleInstance.instance;
System.out.println(s3);System.out.println(s4);
复制代码



  • 可以看出,如果不将这个静态变量私有化,那外界就可以访问它了,但此时这个类还没有准备好对象提供给你,那返回的便是 null 空值了,这个要在开发中就是一个事故了(不是故事)。所以为了更加严谨化,我们要将这个静态变量私有化,即==外界只能通过相应的获取对象方法才可以去构建一个对象==

  • 最后一步,就是提供一个返回单例对象的方法,具体的写法就是当外界调用这个方法的时候,判断 instance 是有又被初始化过了,如果有,则表示外界已经调用此方法构建了一次对象,则会直接返回上一次对象的地址,若判断 instance2 == null,则表示还没申请创建过对象,则为其 new 一个对象出来,存入 instance 这个私有静态变量中

  • 可能有些小伙伴看完后还有点迷惑,举个例子,简单来说就是你去酒店住房:bed:,你的伙伴已经登记拿了房卡,假设你要和他住一起,那就只能也是这个房间,但是房卡前台已经给过你们了,所以它会告诉你这个房间的地址,因此你们二人住的地址是相同的,这样讲大家应该明白了吧

6、小结

  • 对于==懒汉单例==呢,它在我们访问类的之后就会构建出一个对象给我们,速度会比==饿汉单例==来得快。但是懒汉单例有一个缺陷就是无论你做什么操作,都会给你 new 出来一个对象,这样即使你想调用这个到单例类中的其他方法但是又不想创建对象时,就会比较麻烦,所以二者各有优劣,要看不同的使用场景

四、总结与回顾

本文主要讲述了 static 关键字在实例应用中的表现形式,可以作为【工具类】来减少代码的复用、可以通过【静态代码块】来初始化静态成员变量、也可以将其运用在【单例】中,节省系统资源,提高系统性能


OK,对于 static 关键字在 Java 中的应用就讲到这里,相信大家在看完上一篇文章和本文后对 static 关键字有了一个更加深入的了解了,这个关键字在 Java 中还是起到比较重要的一个作用,大家在学习的时候一定要好好掌握,如果有什么疑问,可以于评论区或私信留言,感谢您的观看🌹


发布于: 刚刚阅读数: 5
用户头像

Fire_Shield

关注

语言观决定世界观 2022.09.02 加入

高校学生,热爱编程,喜欢写作

评论

发布
暂无评论
Java之static关键字的应用【工具类、代码块和单例】_static_Fire_Shield_InfoQ写作社区