一、static静态关键字
1.static修饰成员变量
属于类,内存中加载一次,可被共享访问。
同一个类中访问static变量,可以省略类名。
2.static修饰成员方法
实例方法:表示对象自己的行为,且方法中需要访问实例成员的,该方法必须声明成实例方法。
静态方法:该方法是通用功能,与单个对象无关。
内存原理:main方法和静态方法先加载到方法区,main方法进入栈内存开始执行代码。遇到静态方法,会直接到方法区里执行。遇到类对象,先加载到堆内存,通过对象调用方法区里的实例/静态方法。
静态方法不能直接访问实例成员,可以通过创建对象间接访问。
静态方法中不可以出现this关键字。(this只能代表当前对象)
二、static工具类
工具类是什么?
类中都是一些静态方法,每个方法都是以完成一个共用的功能为目的,这个类用来给系统开发人员共同使用的。
package com.jxust.d2_static_util;
/**
* 在企业管理系统中,需要一个系统很多业务处使用验证码进行防刷新等安全控制。
* 问题:同一个功能多处开发,代码重复度过高。
* 解决:使用工具类,一是调用方便,二是提高代码复用(一次编写,处处可用)
*/
import java.util.Random;
public class Login {
public static void main(String[] args) {
//开发一个验证码,调用工具类
System.out.println(JxustUtil.createVerifyCode(6));
}
}
package com.jxust.d2_static_util;
import java.util.Random;
/**
* 工具类
*/
public class JxustUtil {
//工具类无需创建对象,所以把其构造器私有化更专业。
private JxustUtil(){
}
//静态方法,方便别人调用
public static String createVerifyCode(int n) {
//开发一个验证码
String code = "";
//定义一个变量记住全部验证码字符
String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
//生成随机索引,得到字符
Random r = new Random();
for (int i = 0; i<n; i++){
//获取随机索引对应的字符,链接给code
int index = r.nextInt(data.length());
code += data.charAt(index);
}
return code;
}
}
【由于工具里面都是静态方法,直接用类名即可访问。因此,工具类无需创建对象,可将工具类的构造器进行私有化处理。】
工具类练习题:
需求:在实际开发中,经常会遇到一些数组使用的工具类。请按照如下要求编写一个数组的工具类:ArraysUtil
①:我们知道数组对象直接输出的时候是输出对象的地址的,而项目中很多地方都需要返回数组的内容,请在ArraysUtil中提供一个工具类方法toString,用于返回整数数组的内容,返回的字符串格式如:[10, 20, 50, 34,100](只考虑整数数组,且只考虑一维数组)
②:经常需要统计平均值,平均值为去掉最低分和最高分后的分值。请提供这样一个工具方法getAverage,用于返回平均分。(只考虑浮点型数组,且只考虑一维数组)
③:定义一个测试类TestDemo1,调用该工具类的工具方法,并返回结果。
测试类TestDemo1
package com.jxust.d2_static_util;
public class TestDemo1 {
public static void main(String[] args) {
int[] arr = null;
int[] arr1 = {};
int[] arr2 = {12,36,0,89,100,99,16,66};
double[] score = {90.5,10,100,85.5,80,90};
System.out.println("arr="+ArrayUtil.toString(arr));
System.out.println("arr1="+ArrayUtil.toString(arr1));
System.out.println("arr2="+ArrayUtil.toString(arr2));
System.out.println("score average ="+ArrayUtil.getAverage(score));
}
}
工具类ArraysUtil
package com.jxust.d2_static_util;
import java.util.Arrays;
/**
* 练习:完成数组工具类的设计
*/
public class ArrayUtil {
//私有构造器
private ArrayUtil() {
}
//工具方法:静态方法
public static String toString(int[] arr) {
if (arr == null) {
return null;
}
StringBuffer sb = new StringBuffer();
sb.append("[");
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i]);
if (i != arr.length - 1)
sb.append(",");
}
sb.append("]");
return sb.toString();
}
/**
* 统计平均值,平均值为去掉最低分和最高分后的分值。
* 请提供这样一个工具方法getAverage,用于返回平均分。
*/
public static double getAverage(double[] arr){
Arrays.sort(arr);
double totalScore = 0.0;
for(int i = 1;i < arr.length-1; i++){
totalScore += arr[i];
}
return totalScore/(arr.length-2);
}
}
输出结果:
arr=null
arr1=[]
arr2=[12,36,0,89,100,99,16,66]
score average =86.5
三、static代码块
代码块是类的5大成分之一(成员变量、构造器,方法,代码块,内部类),定义在类中方法外。
在Java类下,使用{}括起来的代码被称为代码块。
静态代码块:
格式:static{}
特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次。
使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用。
构造代码块:
格式:{}
特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行。
使用场景:初始化实例资源。
案例:斗地主游戏
需求:在启动房间时,应该提前准备好54张牌,后续才可以直接使用这些牌数据。
package com.jxust.d3_static_code;
import com.jxust.d2_static_util.ArrayUtil;
import java.util.ArrayList;
/**
* 分析如下:
* 1.该房间只需要一副牌。
* 2.静态ArrayList集合存储54张牌对象,静态的集合只会加载一份。
* 3.在启动游戏房间前,将54张牌初始化好。
*/
public class StaticTest {
public static ArrayList<String> cards = new ArrayList<>();
/**
* 在程序真正运行main方法前,把54张牌放进去,后续游戏可以直接使用。
* 这里需要静态代码块,进行优先加载。
*/
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("大🃏");
cards.add("小🃏");
}
public static void main(String[] args) {
System.out.println("新牌"+cards);
}
}
输出结果:
新牌[3♥, 3♠, 3♦, 3♣, 4♥, 4♠, 4♦, 4♣, 5♥, 5♠, 5♦, 5♣, 6♥, 6♠, 6♦, 6♣, 7♥, 7♠, 7♦, 7♣, 8♥, 8♠, 8♦, 8♣, 9♥, 9♠, 9♦, 9♣, 10♥, 10♠, 10♦, 10♣, J♥, J♠, J♦, J♣, Q♥, Q♠, Q♦, Q♣, K♥, K♠, K♦, K♣, A♥, A♠, A♦, A♣, 2♥, 2♠, 2♦, 2♣, 小🃏, 大🃏]
四、单例设计模式
单例模式:
可以保证系统中,应用该模式的这个类永远只有一个实例,即一个类只能创建一个对象
。
单例模式需要把构造器私有,否则不会只产生一个对象。
1.饿汉单例模式
在用类获取对象的时候,对象已经提前创建好了。
public class SingleInstance {
//1.饿汉单例的对象只能有一个,所以定义静态成员变量,只能随类加载一次。
public static SingleInstance instance = new SingleInstance();
//2.必须把构造器私有化
private SingleInstance(){
}
}
2.懒汉单例模式
在真正需要该对象时,才去创建一个对象(延迟加载对象)。
public class SingleInstance2 {
//instance变量的访问权限为private
private static SingleInstance2 instance;
private SingleInstance2(){}
//提供一个方法,对外返回单例对象。
public static SingleInstance2 getInstance(){
if(instance == null){
instance = new SingleInstance2();
}
return instance;
}
}