百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

Java中Static关键字-Static定义代码块-单例设计模式

yuyutoo 2024-10-12 00:56 4 浏览 0 评论

文章目录

面向对象的进阶

面向对象进阶的第一篇, 主要讲解内容如下:

  • static关键字 : 开发中如何定义一个共享的信息,给所有对象共享访问,如在线人数信息等。
  • 单例设计模式 : 有些类只需要一个对象就可以了,如任务管理器对象,如何实现一个类只能对外产生同一个对象
  • 面向对象三大特征-继承 : 大量角色类的属性和行为存在重复代码,如果把一类的角色信息进行优化,提升代码复用,降低代码冗余

静态关键字:static

?static修饰成员变量

static是静态的意思,可以修饰成员变量和成员方法。

static修饰成员变量表示该成员变量只在内存中只存储一份,可以被共享访问、修改。

public class User {
 
		// 静态成员变量    
		public static int onlineNumber= 161;
  	// 实例成员变量
  	private String name;
		private int age;
    …
}

成员变量可以分为2类:

  1. 静态成员变量
  2. 实例成员变量

静态成员变量

静态成员变量 : 有static修饰,属于类,与类加载时一起加载一次

常表示如在线人数信息、等需要被共享的信息,可以被共享访问。

public class User {
 
    // 静态成员变量
		public static String onlineNumber= 161;
}

静态成员变量访问方式有两种:

通过类访问(推荐): 类名.静态成员变量

public static void main(String[] args) {
 
		// 类名.静态成员变量
		System.out.println(User.onLineNumber);
}

通过实例对象访问(能够访问但不推荐): 对象.静态成员变量

public static void main(String[] args) {
 
		// 对象.静态成员变量
		User u1 = new User();
		System.out.println(u1.onLineNumber);
}

实例成员变量

实例成员变量 : 无static修饰,存在于每个对象中, 属于每一个实例对象

常表示姓名name、年龄age、等属于每个对象的信息。

public class User {
 
		// 实例成员变量    
		private String name;
		private int age;
}

实例成员变量的访问方式只有一种, 访问格式: 对象.实例成员变量

public static void main(String[] args) {
 
		// 对象.实例成员变量
		User u1 = new User();
		u1.name = "chenyq";
		u1.age = 18;
		System.out.println(u1.name);
		System.out.println(u1.age);
}

?static修饰成员方法

刚刚我们学习了static修饰成员变量, 那修饰成员方法呢?

之前我们定义的方法有的有static修饰,有的是没有的,它们有什么不同

// 没有用static修饰
public void run(){
 
		System.out.println(name +"正在好好学习,天天向上~~");
}

// 有用static修饰
public static int getMax(int a , int b){
 
		return a > b ? a : b;
}

成员方法和成员变量相似, 也是分为两类:

  1. 静态成员方法
  2. 实例成员方法

实例成员方法 (有static修饰,属于类)

建议用类名访问(推荐),也可以用对象访问(同样不推荐)。

表示 对象自己的行为的 ,且方法中需要访问实例成员的,则该方法必须申明成实例方法。

public class Student {
 
    // 对象的成员变量
    private String name;
    private Number age;
  	// 定义有参构造器
    public Student (String name, Number age) {
 
        this.name = name;
        this.age = age;
    }

    // 定义实例成员方法
    public void study() {
 
        // 实例成员方法可以访问对象成员变量
        System.out.println(name + "正在学习");
    }

    public static void main(String[] args) {
 
        // 调用实例方法: 对象.实例方法
        Student stu = new Student("chenyq", 18);
        stu.study(); // chenyq正在学习
    }
}

静态成员方法 (无static修饰,属于对象)

只能用对象触发访问。

如果该方法是 以执行一个公用功能为目的 ,则可以申明成静态方法。

public class Student {
 
    // 对象的成员变量
    private String name;
    private Number age;

     // 定义静态成员方法
     public static int getMax(int a, int b) {
 
        if (a > b) return a;
        return b;
     }

    public static void main(String[] args) {
 
        // 调用静态方法: 类.静态方法
        // 同一个类中访问静态成员, 可以省略不写
        System.out.println(getMax(10, 20)); // 省略
        System.out.println(Student.getMax(10, 20));
    }
}

?静态方法定义工具类

工具类:

工具类中定义的都是一些静态方法,每个方法都是以完成一个共用的功能为目的。

现状问题分析:

在企业的管理系统中,通常需要在一个系统的很多业务处使用验证码进行防刷新等安全控制。

如果登录和注册等多处地方都存在验证码逻辑,就会导致同一个功能多处开发,会出现代码重复度过高。

工具类的好处:

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

我们在工具类使用静态成员方法, 方便调用节约内存

实例方法需要创建对象调用,此时用对象只是为了调用方法,这样只会浪费内存。

工具类的定义注意:

建议将工具类的构造器进行私有,不允许创建对象。

里面都是静态方法,直接用类名访问即可, 工具类无需创建对象, 。

public class ArraysUtils {
 
    // 工具类构造器私有化处理
    private ArraysUtils() {
 
        
    }
}

我们来试着定义一个数组工具类, 需求如下:

需求:在实际开发中,经常会遇到一些数组使用的工具类。请按照如下要求编写一个数组的工具类:ArraysUtils

思路分析:

我们知道数组对象直接输出的时候是输出对象的地址的,而项目中很多地方都需要返回数组的内容,请在ArraysUtils中提供一个工具类方法toString,用于返回整数数组的内容,返回的字符串格式如:[10, 20, 50, 34, 100]( 只考虑整数数组,且只考虑一维数组

public class ArraysUtils {
 
    // 将构造器设为私有
    private ArraysUtils() {
 

    }

    public static String toString(int[] arr) {
 
        String showArr = "[";
        for (int i = 0; i < arr.length; i++) {
 
            showArr += arr[i];
            showArr += (i == arr.length -1 ? "]" : ", ");
        }
        return showArr;
    }
}

经常需要统计平均值,平均值为去掉最低分和最高分后的分值,请提供这样一个工具方法getAerage,用于返回平均分。( 只考虑浮点型数组,且只考虑一维数组

public class ArraysUtils {
 
    // 将构造器设为私有
    private ArraysUtils() {
 

    }

    public static String toString(int[] arr) {
 
        String showArr = "[";
        for (int i = 0; i < arr.length; i++) {
 
            showArr += arr[i];
            showArr += (i == arr.length -1 ? "]" : ", ");
        }
        return showArr;
    }

    public static double getAerage(double[] arr) {
 
        double max = arr[0];
        double min = arr[0];
        double sum = 0;
        for (int i = 0; i < arr.length; i++) {
 
            if (max < arr[i]) max = arr[i];
            if (min > arr[i]) min = arr[i];
            sum += arr[i];
        }
        return  (sum - max - min) / (arr.length - 2);
    }
}

定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果。

定义好一个工具类, 在其他地方

public class TestDemo {
 
    public static void main(String[] args) {
 
        int[] nums = {
 10, 20, 30, 40};
        // 调用toString方法, 并对返回结果打印
        System.out.println(ArraysUtils.toString(nums)); // [10, 20, 30, 40]

        double[] score = {
 2.0, 1.8, 1.7, 1.9, 1.6};
        // 调用getAerage方法, 并对返回结果打印
        System.out.println(ArraysUtils.getAerage(score)); // 1.8
    }
}

static访问注意事项:

静态方法只能访问静态的成员,不可以直接访问实例成员。

实例方法可以访问静态的成员,也可以访问实例成员。

静态方法中是不可以出现this关键字的。

Static定义代码块

?静态代码块和构造代码块

代码块概述

代码块是类的5大成分之一(成员变量、构造器,方法,代码块,内部类),定义在类中方法外。

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

代码块分为 :

  1. 静态代码块
  2. 动态代码块

静态代码块:

格式: static{}

特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次

使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用。

public class TestDemo01 {
 
  	// 当类加载的时候, static中的代码块会自动执行一次
    static {
 
        System.out.println("静态代码块与类一起加载的代码块, 自动触发一次");
    }

    public static void main(String[] args) {
 

    }
}

构造代码块(了解,用的少):

格式: {}

特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行

使用场景:初始化实例资源。

public class TestDemo01 {
 
    {
 
        System.out.println("构造代码块与对象一起加载的代码块, 自动触发执行");
    }

    // 定义构造器
    public TestDemo01() {
 
        System.out.println("构造器执行了");
    }

    public static void main(String[] args) {
 
      	// 创建第一个对象
        new TestDemo01();
      	// 创建第二个对象
        new TestDemo01();
    }
}

打印结果如下:

我们发现, 构造代码块会比构造器先执行

由于构造代码块与对象一起加载, 索引每创建一个对象, 构造代码块中的内容都会执行一次

?静态代码块的小案例练习

相信大家都玩过斗地主游戏, 现在我们有如下一个需求

需求:

斗地主游戏在启动游戏房间的时候,应该提前准备好54张牌,后续才可以直接使用这些牌数据。

我们来完成这个提前准备好54张牌的功能

分析:

该房间只需要一副牌。

定义一个静态的ArrayList集合存储54张牌对象,静态的集合只会加载一份。

在启动游戏房间前,应该将54张牌初始化好

当系统启动的同时需要准备好54张牌数据,此时可以用静态代码块完成。

public class StaticCodeDemo {
 
    // 定义静态成员变量
    public static ArrayList<String> cards = new ArrayList<>();

    // 使用静态代码块对静态资源cards进行初始化
    static {
 
        String[] colors = {
 "?", "?", "?", "?"};
        String[] nums = {
 
        		"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"
        };

        for (int i = 0; i < nums.length; i++) {
 
            for (int j = 0; j < colors.length; j++) {
 
                cards.add(colors[j] + nums[i]);
            }
        }

        // 添加大小王
        cards.add("大王");
        cards.add("小王");
    }

    public static void main(String[] args) {
 
      	// 打印静态代码块查看效果
        System.out.println(cards);
    }
}

Static单例设计模式

參单例模式介绍

介绍单例模式之前, 我们先说一说什么是设计模式

设计模式(Design pattern):

开发中经常遇到一些问题,一个问题通常有n种解法的,但其中肯定有一种解法是最优的

这个最优的解法被人总结出来了,称之为设计模式。

设计模式有20多种,对应20多种软件开发中会遇到的问题,学设计模式主要是学2点:

  • 第一:这种模式用来解决什么问题。
  • 第二:遇到这种问题了,该模式是怎么写的,他是如何解决这个问题的。

单例模式:

可以保证系统中,应用该模式的这个类永远只有一个实例,即 一个类永远只能创建一个对象

例如任务管理器对象我们只需要一个就可以解决问题了,这样可以节省内存空间。

单例的实现方式有很多, 这篇我主要讲解以下两种单例模式:

饿汉单例模式。

懒汉单例模式。

?饿汉单例模式

饿汉单例设计模式 : 在用类获取对象的时候,对象已经提前为你创建好了。

设计步骤:

1.定义一个类,把构造器私有, 让外界无法创建对象。
2.定义一个静态变量, 用于存储创建出来的对象
// 1.定义一个单例类
public class SingleInstance1 {
 
    // 3.定义一个静态成员变量, 用于储存一个对象
    public static SingleInstance1 instance1 = new SingleInstance1();
    // 2.将类的构造器设置为私有构造器
    private SingleInstance1() {
 
      
    }
}

我们在通过另一个类中, 多次通过 SingleInstance1.instance1 获取对象也只会获取一次对象

这是因为类和静态成员变量一起加载, 且只加载一次, 所以只会获取到一个对象

public class Test {
 
    public static void main(String[] args) {
 
        SingleInstance1 sin1 = SingleInstance1.instance1;
        SingleInstance1 sin2 = SingleInstance1.instance1;
      	// 获取两次得到的是同一个对象
        System.out.println(sin1 == sin2); // true
    }
}

讀懒汉单例模式

懒汉单例设计模式 : 在真正需要该对象的时候,才去创建一个对象(延迟加载对象)。

设计步骤:

1.定义一个类,把构造器私有。
2.定义一个静态变量存储一个对象。
3.提供一个返回单例对象的方法
public class SingleInstance2 {
 
    // 2.定义一个静态变量, 用于存储一个对象, 但是不初始化对象
    public static SingleInstance2 instance2;

    // 1.定义一个类, 把构造器私有
    public SingleInstance2() {
 

    }

    // 3.提供一个返回单例对象的方法
    public static SingleInstance2 getObject() {
 
        if (instance2 == null) return instance2 = new SingleInstance2();
        return instance2;
    }
}

我们测试一下, 在另一个类中, 多次通过 SingleInstance1.getObject 获取对象, 是否只会获取一次对象

public class Test {
 
    private static void main(String[] args) {
 
          SingleInstance2 sin1 =  SingleInstance2.getObject();
          SingleInstance2 sin2 =  SingleInstance2.getObject();
          System.out.println(sin1 == sin2); // true
    }
}

饿汉单例模式和懒汉单例模式区别对比:

饿汉单例模式和懒汉单例模式各有优缺点

  • 从第一次获取对象速度里来看: 饿汉单例模式的速度比懒汉单例模式快
  • 从内存资源来看: 饿汉单例模式有可能会浪费资源, 而懒汉单例模式不会。

原文链接:https://www.tuicool.com/articles/Qn2IBz3

相关推荐

网站建设:从新手到高手

现代化网站应用领域非常广泛,从个人形象网站展示、企业商业网站运作、到政府公益等服务网站,各行各业都需要网站建设。大体上可以归结四类:宣传型网站设计、产品型网站制作、电子商务型网站建设、定制型功能网站开...

JetBrains 推出全新 AI 编程工具 Junie,助力高效开发

JetBrains宣布推出名为Junie的全新AI编程工具。这款工具不仅能执行简单的代码生成与检查任务,还能应对编写测试、验证结果等复杂项目,为开发者提供全方位支持。根据SWEBench...

AI也能写代码!代码生成、代码补全、注释生成、代码翻译轻松搞定

清华GLM技术团队打造的多语言代码生成模型CodeGeeX近期更新了新的开源版本「CodeGeeX2-6B」。CodeGeeX2是多语言代码生成模型CodeGeeX的第二代模型,不同于一代CodeG...

一键生成前后端代码,一个36k星的企业级低代码平台

「企业级低代码平台」前后端分离架构SpringBoot2.x,SpringCloud,AntDesign&Vue,Mybatis,Shiro,JWT。强大的代码生成器让前后端代码一键生成,无需写任...

Gitee 代码托管实战指南:5 步完成本地项目云端同步(附避坑要点)

核心流程拆解:远程仓库的搭建登录Gitee官网(注册账号比较简单,大家自行操作),点击“新建仓库”,建议勾选“初始化仓库”和“设置模板文件”(如.gitignore),避免上传临时文件。...

jeecg-boot 源码项目-强烈推荐使用

JEECGBOOT低代码开发平台...

JetBrains推出全新AI编程工具Junie,强调以开发者为中心

IT之家2月1日消息,JetBrains发文,宣布推出一款名为Junie的全新AI编程工具,官方声称这款AI工具既能执行简单的代码生成与检查等基础任务,也能应对“编写测试、验证结...

JetBrains旗下WebStorm和Rider现已加入“非商用免费”阵营

IT之家10月25日消息,软件开发商JetBrains今日宣布,旗下WebStorm(JavaScript开发工具)和Rider(.NET开发工具)现已加入“非商用免费”阵营。如果...

谈谈websocket跨域

了解websocketwebsocket是HTML5的新特性,在客户端和服务端提供了一个基于TCP连接的双向通道。...

websocket调试工具

...

利用webSocket实现消息的实时推送

1.什么是webSocketwebSocket实现实现推送消息WebSocket是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议。以前的推送技术使用Ajax轮询,浏览器需...

Flutter UI自动化测试技术方案选型与探索

...

为 Go 开发的 WebSocket 库

#记录我的2024#...

「Java基础」Springboot+Websocket的实现后端数据实时推送

这篇文章主要就是实现这个功能,只演示一个基本的案例。使用的是websocket技术。...

【Spring Boot】WebSocket 的 6 种集成方式

介绍...

取消回复欢迎 发表评论: