静态关键字:static
目录
静态关键字:static
static关键字的作用:
- static是静态的意思,可以修饰成员变量,表示该成员变量只在内存中存储一份,可以被共享访问、修改。
static 修饰成员变量的方法:
成员变量可以分为两类
-
静态成员变量(有static修饰,属于类,内存中加载一次):常表示如在线人数、等需要被共享的信息,可以被共享访问。
-
public class User{ //静态成员变量 public static String onlineNumber = 161; }
- 类名.静态成员变量。(推荐)
- 对象.静态成员变量。(不推荐)
-
-
实例成员变量(无static修饰,存在于每个对象中):常表示姓名name、年龄age、等属于每个对象的信息。
-
public class User{ public static String onlineNumber = 161; //实例成员变量 private String name; private int age; }
- 对象.实例成员变量
-
package com.csl.d1_static_filed;
public class User {
//在线人数信息:静态成员变量
public static int onlineNumber = 161;
//实例成员变量
private String name;
private int age;
public static void main(String[] args) {
//1.类名.静态成员变量
User.onlineNumber++;
//注意:同一个类中访问静态成员变量,类名可以省略不写
System.out.println(onlineNumber);
System.out.println(User.onlineNumber);
//2.对象.静态成员变量
User u1 = new User();
u1.name = "孙悟空";
u1.age = 13;
System.out.println(u1.name);
System.out.println(u1.age);
// 对象.静态成员变量 (不推荐)
u1.onlineNumber++;
User u2 = new User();
u2.name = "猪八戒";
u2.age = 23;
System.out.println(u2.name);
System.out.println(u2.age);
// 对象.静态成员变量 (不推荐)
u2.onlineNumber++;
System.out.println(onlineNumber);
}
}
output:
162
162
孙悟空
13
猪八戒
23
164
static修饰成员变量的内存原理
static修饰成员方法的基本用法
成员方法的分类
- 静态成员方法(有static修饰,属于类),可以用类名访问,也可以用对象名访问。
- 实例成员方法(无static修饰,属于对象),只能用对象触发访问。
使用场景
- 表示对象自己行为的,且方法中需要访问实例变量的,则该方法必须申明成实例方法。
- 如果该方法是以执行一个通用功能为目的,或者需要方便访问,则可以申明成静态成员方法。
public class Student {
private String name;
private int age;
/*
实例方法:无static修饰,属于对象的,通常表示自己的行为,可以访问对象的成员变量
*/
public void study(){
System.out.println(name+"正在学习!");
}
/**
* 静态方法:有static修饰的,隶属于类,可以被类和对象共同访问
*/
public static void getMax(int a,int b){
System.out.println(a > b ? a : b);
}
public static void main(String[] args) {
//1.类名.静态方法
Student.getMax(100,200);
//注意:同一个类中访问静态成员,可以省略类名不写
getMax(22,33);
//2.对象.实例方法
// study();//报错的
Student s = new Student();
s.name = "全蛋儿,";
s.age = 3;
s.study();
//3.对象.静态方法(不推荐)
s.getMax(111,333);
}
}
output:
200
33
全蛋儿,正在学习!
333
static 修饰成员方法的内存原理
static实例应用案例:使用静态方法定义工具类
工具类:
- 对于一些应用程序中多次需要用到的功能,可以将这些功能封装成静态方法,放在一个类中,这个类就是工具类
- 工具类的作用:一是方便调用,二是提高了代码复用。
import java.util.Random;
public class Login {
public static void main(String[] args) {
//验证码
//1.使用String开发一个验证码
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
//2.定义一个变量用作存储随机产生的5位字符
String code = "";
//3.循环
Random r = new Random();
for (int i = 0; i < 5; i++) {
int index = r.nextInt(chars.length());
//4.对应索引提取字符
code += chars.charAt(index);
}
System.out.println("验证码为:"+code);
}
}
单独写成工具类
import java.util.Random;
public class VerifyTool {
public static String creatCode(int n){
//使用String开发验证码
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
//定义一个变量用于储存验证码
String code = "";
Random r = new Random();
for (int i = 0; i < n; i++) {
int index = r.nextInt(chars.length());
code += chars.charAt(index);
}
return code;
}
}
----------------------------
public class Register {
public static void main(String[] args) {
System.out.println(VerifyTool.creatCode(5));
}
}
工具类原理和延伸
- 一次编写,处处可用
- 建议将工具类的构造器私有,不让工具类对外产生对象。
import java.util.Random;
public class VerifyTool {
private VerifyTool(){
}
public static String creatCode(int n){
//使用String开发验证码
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
//定义一个变量用于储存验证码
String code = "";
Random r = new Random();
for (int i = 0; i < n; i++) {
int index = r.nextInt(chars.length());
code += chars.charAt(index);
}
return code;
}
}
为什么工具类中的方法不用实例方法来写呢?
- 因为实例方法需要创建对象来调用,此时用对象只是为了调用方法,这样只会浪费内存。
工具类是什么,有什么好处?
- 内部是一些静态方法,每个方法完成一个功能
- 一次编写,处处可用,提高代码的复用性
工具类有什么要求?
- 建议工具类的构造器私有化处理。
- 工具类不需要创建对象
static实际应用案例:定义数组工具类
需求:在实际开发中,经常会遇到一些数组使用的工具类。请按照要求编写一个数组的工具类:ArrayUtils
-
:我们知道数组对象直接输出的时候是输出对象的地址的,而项目中很多地方都需要返回数组的内容,请在ArrayUtils中提供一个工具类方法toString(),用于返回整数数组的内容,返回的字符串格式如:[ 10,20,40,100 ] (只考虑整数数组,且只考虑一维数组)
-
:经常需要统计平均值,平均值为去掉最低分和最高分后的分值,请提供这样一个工具方法getAevrage,用于返回平均分。(只考虑浮点型数组,且只考虑一维数组)。
-
定义一个测试类,调用该工具类的工具方法,并返回结果
package com.csl.d3_static_test;
public class Test {
public static void main(String[] args) {
int[] arr = {10,20,30,40,50};
System.out.println(arr);
System.out.println(ArrayUtils.toString(arr));
System.out.println(ArrayUtils.getAverage(arr));
}
}
package com.csl.d3_static_test;
public class ArrayUtils {
//构造器私有化处理
private ArrayUtils(){
}
public static String toString(int[] arr){
if (arr != null){
String result = "[";
for (int i = 0; i < arr.length; i++) {
result += (i == arr.length-1 ? arr[i] : arr[i] + ",");
}
result +="]";
return result;
}else {
return null;
}
}
public static double getAverage(int[] arr){
int max = arr[0];
int min = arr[0];
int sum = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i]>max){
max = arr[i];
}
if (arr[i]<min){
min = arr[i];
}
sum += arr[i];
}
return (sum - max - min)*1.0/(arr.length-2);
}
}
output:
[I@1b6d3586
[10,20,30,40,50]
30.0
static注意事项
- 静态方法只能访问静态的成员,不可以直接访问实例成员。(可以在静态方法中创建对象访问)
- 实例方法可以访问静态的成员,也可以访问实例成员。
- 静态方法中是不可以出现this关键字的。
package com.csl.d4_static_attention;
public class Test {
//静态成员变量
public static int age;
//实例成员变量
public String name;
//静态成员方法
public static void getMax(){
//1.静态方法可以直接访问静态成员变量
System.out.println(age);
System.out.println(Test.age);
//3.静态方法中不能出现this关键字
}
//2.实例方法可以直接访问静态成员,也可以访问实例成员
public void run(){
System.out.println(age);
System.out.println(Test.age);
study();
Test.study();
System.out.println(name);
sin();
}
public void sin(){
System.out.println("我在唱歌");
}
public static void study(){
System.out.println("我正在学习!");
}
}
static应用知识:代码块
代码块的分类、作用
代码块概述
- 代码块是类的5大成分之一(成员变量、构造器、方法、代码块、内部类),定义在类中方法外
- 在Java类中,使用 { }括起来的的代码称为代码块。
代码块分为
- 静态代码块
- 格式:static{}
- 特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
- 使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用。
package com.csl.d5_static_codeblock;
public class TestDemo1 {
private static String stuName;
public static void main(String[] args) {
System.out.println("========main方法被执行输出=========");
System.out.println(stuName);
}
/*
特点:与类一起加载,自动触发执行一次,优先执行
作用:可以在程序加载时对一些静态数据进行初始化操作(准备内容)
*/
static {
System.out.println("========静态代码块被触发执行=========");
stuName = "陈太帅";
}
}
output:
========静态代码块被触发执行=========
========main方法被执行输出=========
陈太帅
- 构造代码块(了解,用的少)
- 格式:{}
- 特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行器执行。
- 使用场景:初始化实例资源。
- 格式:{}
package com.csl.d5_static_codeblock;
public class TestDemo2 {
private String name;
/*
构造代码块,属于对象的,与对象一起加载,自动触发执行,优先于构造器
*/
{
System.out.println("=========构造代码块被执行了==========");
name = "二蛋";
}
public TestDemo2(){
System.out.println("========构造器被触发执行=========");
}
public static void main(String[] args) {
TestDemo2 t = new TestDemo2();
System.out.println(t.name);
TestDemo2 t1 = new TestDemo2();
System.out.println(t1.name);
}
}
output
=========构造代码块被执行了==========
========构造器被触发执行=========
二蛋
=========构造代码块被执行了==========
========构造器被触发执行=========
二蛋
静态代码块的应用案例
斗地主游戏
需求:
在启动游戏房间的时候,应该提前准备好54张牌,后续才可以直接使用这些牌数据。
分析:
- 该房间只需要一副牌
- 定义一个静态的ArrayList集合存储54张牌对象,静态的集合只会加载一份。
- 在启动游戏前,应该将54张牌初始化好
- 当系统启动的同事需要准备好54张牌数据,此时可以用静态代码块完成。
package com.csl.d5_static_codeblock;
import java.util.ArrayList;
public class StaticCodeTest {
/*
模拟初始化操作
点数:"3","4","5","6","7","8","9","10","J","Q","K","A","2";
花色:"♠","♥","♣","♦";
*/
//1.准备一个容器,存储54张牌对象,这个容器建议使用静态的集合,静态的集合只加载一次
static ArrayList<String> cards = new ArrayList<>();
/**
* 2.在游戏启动之前需要准备好54张牌放进去,使用静态代码块进行初始化
*/
static {
//3.加载54张牌放进去
//4.准备4种花色,类型确定,个数确定
String[] colors = {"♠", "♥", "♣", "♦"};
//5.定义点数
String[] sizes = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
//6.先遍历点数,再组合花色
for (int i = 0; i < sizes.length; i++) {
for (int j = 0; j < colors.length; j++) {
cards.add(sizes[i] + colors[j]);
}
}
//7.添加大小王
cards.add("小王");
cards.add("大王");
}
public static void main(String[] args) {
System.out.println("新牌为:" + cards);
}
}
output:
新牌为:[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♦, 小王, 大王]
static应用知识:单例设计模式
设计模式
什么是设计模式
- 设计模式是一套被前人反复使用、多数人知晓、经过分类编目的代码设计经验的总结,后来者可以直接拿来解决问题。
- 设计模式是软设计中的常见解决方案,好的设计模式可以进一步提高代码的重用性。
单例模式介绍
单例模式:
- 可以保证系统中,应用该模式的这个类永远只有一个实例,即一个类永远只能创建一个对象。
单例的场景和作用
- 例如任务管理器对象我们只需要一个就可以解决问题了,这样可以节省内存空间。
饿汉单例模式
- 在用类获取对象的时候,对象已经提前为你创建好了。
设计步骤:
- 定义一个类,把构造器私有。
- 定义一个静态变量存储一个对象。
package com.csl.d6_static_singleinstance;
public class SingleInstance {
/*
2.定义一个公开的静态的成员变量存储一个类的对象
饿汉:在这里加载静态变量 的时候就会创建对象了
public static int onlineNumber = 161;
*/
public static SingleInstance instance = new SingleInstance();
/*
1.构造器私有
*/
private SingleInstance(){
}
}
测试是不是单例
package com.csl.d6_static_singleinstance;
public class Test {
public static void main(String[] args) {
SingleInstance s1 = SingleInstance.instance;
SingleInstance s2 = SingleInstance.instance;
SingleInstance s3 = SingleInstance.instance;
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s1==s3);
}
}
output:
com.csl.d6_static_singleinstance.SingleInstance@1b6d3586
com.csl.d6_static_singleinstance.SingleInstance@1b6d3586
com.csl.d6_static_singleinstance.SingleInstance@1b6d3586
true
懒汉单例模式
- 在真正需要该对象的时候,才去创建一个对象(延迟加载对象)
设计步骤:
- 定义一个类,把构造器私有
- 定义一个静态变量存储一个对象
- 提供一个返回单例对象的方法
package com.csl.d6_static_singleinstance;
public class SingleInstance2 {
/*
1.构造器私有化
*/
private SingleInstance2() {
}
/*
2.创建一个静态的成员变量来存储本类的对象,注意此时不能初始化对象
*/
private static SingleInstance2 instance;//null
/*
3.定义一个方法,让其他地方可以来调用获取一个对象
*/
public static SingleInstance2 getInstance() {
if (instance == null) {
instance = new SingleInstance2();
}
return instance;
}
}
测试
package com.csl.d6_static_singleinstance;
public class Test2 {
public static void main(String[] args) {
SingleInstance2 s1 = SingleInstance2.getInstance();
SingleInstance2 s2 = SingleInstance2.getInstance();
SingleInstance2 s3 = SingleInstance2.getInstance();
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s1 == s3);
}
}
output:
com.csl.d6_static_singleinstance.SingleInstance2@1b6d3586
com.csl.d6_static_singleinstance.SingleInstance2@1b6d3586
com.csl.d6_static_singleinstance.SingleInstance2@1b6d3586
true