目录
视频教程传送门 -> https://www.bilibili.com/video/BV1Cv411372m?p=97
static修饰成员变量
static修饰成员变量表示该成员变量只在内存中只存储一份,可以被共享访问、修改。
例如在线人数、观看人数这类变量适合定义为静态成员变量
静态成员变量和实例成员变量
成员变量类别 | 特点 | 访问方式 | 使用场景 |
静态成员变量 | 有static修饰,属于类、加载一次,可以被共享访问 | 类名.静态成员变量 (推荐) 对象.静态成员变量 |
表示在线人数等需要被共享的信息 |
实例成员变量 | 无static修饰,属于对象 | 对象.实例成员变量 | 属于每个对象,且每个对象信息不同时(name,age,…等) |
static修饰成员变量的内存原理
static修饰成员方法
静态成员方法和实例成员方法
成员方法类别 | 特点 | 访问方式 | 使用场景 |
静态成员方法 | 有static修饰,属于类和对象共享 | 类名.静态成员方法(推荐) 对象.静态成员方法 |
以执行一个通用功能为目的,或者需要方便访问的方法 |
实例成员方法 | 无static修饰,属于对象 | 对象.实例成员方法 | 表示对象自己的行为,且方法中需要访问实例成员 |
static修饰成员方法的内存原理
注意:
静态方法只能访问静态的成员,不可以直接访问实例成员(间接访问-> 静态方法中创建对象)。
实例方法可以访问静态的成员,也可以访问实例成员。
静态方法中是不可以出现this关键字的。
工具类
内部是一些静态方法,每个方法完成一个功能
一次编写,处处可用,提高代码的重用性
建议工具类的构造器私有化处理 => 不让创建对象,节约内存
【例】验证码工具类,登录、注册等功能均可使用
定义一个工具类 VerifyTool,私有构造器,类中有一个静态方法 createCode
无需创建实例对象,通过类名引用静态方法创建验证码即可
package com.test.d3_static_test;
import java.util.Random;
public class VerifyTool {
/**
私有构造器
*/
private VerifyTool(){
}
/**
静态方法
*/
public static String createCode(int n){
// 1、使用String开发一个验证码
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
// 2、定义一个变量用于存储n位随机的字符作为验证码
String code = "";
// 3、循环
Random r = new Random();
for (int i = 0; i < n; i++) {
int index = r.nextInt(chars.length());
// 4、对应索引提取字符
code += chars.charAt(index);
}
return code;
}
}
一个登录的测试类可以通过工具类类名调用验证码静态方法
package com.test.d3_static_test;
public class Login {
public static void main(String[] args) {
// 验证码:
System.out.println("验证码:" + VerifyTool.createCode(10));
}
}
代码块
代码块定义在类中方法外。
在Java类下,使用 { } 括起来的代码被称为代码块 。
代码块分类
静态代码块:
格式:static{}
特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用。
构造代码块(了解,用的少):
格式:{}
特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行
使用场景:初始化实例资源。
静态代码块作用
在启动系统时对数据进行初始化
单例设计模式
可以保证系统中,一个类永远只能创建一个对象。
例如任务管理器对象只需要一个就可以(重复点击也只有一个),这样可以节省内存空间。
饿汉单例设计模式
在用类获取对象的时候,对象已经提前为你创建好了。
设计步骤:
定义一个类,把构造器私有。
定义一个静态变量存储一个对象。
【例】SingleInstanceHungry.java内容如下(私有化构造器 + 公开的静态变量)
package com.test.d6_singleinstance;
/**
饿汉单例模式
*/
/**
1、定义一个单例类
*/
public class SingleInstanceHungry {
/**
3.定义一个静态变量存储一个对象,加载一次,只有一份
*/
// public static int onLineNumber = 21; 类比:与这个静态变量赋值是一样的格式
public static SingleInstanceHungry instance = new SingleInstanceHungry();
/**
2、必须私有构造器:私有构造器对外不能被访问。
*/
private SingleInstanceHungry(){
System.out.println("创建了一个饿汉对象");
}
}
执行测试类 Test.java
package com.test.d6_singleinstance;
public class Test {
public static void main(String[] args) {
// SingleInstanceHungry s1 = new SingleInstanceHungry(); 执行会报错,因为构造器是private
//使用类的静态成员变量instance,“创建3个”对象,看看其地址是否一样(1个对象)
SingleInstanceHungry s1 = SingleInstanceHungry.instance;
SingleInstanceHungry s2 = SingleInstanceHungry.instance;
SingleInstanceHungry s3 = SingleInstanceHungry.instance;
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s1 == s2);
}
}
观察输出可以发现,无论引用几次静态变量,创建几次对象,地址都是同一个
懒汉单例设计模式
在真正需要该对象的时候,才去创建一个对象(延迟加载对象)。
设计步骤:
定义一个类,把构造器私有。
定义一个静态变量存储一个对象。
提供一个返回单例对象的方法。
【例】SingleInstanceLazy.java内容如下(私有化构造器 + 私有的静态变量 + 公开的静态方法)
package com.test.d6_singleinstance;
/**
懒汉单例模式
*/
/**
1、定义一个单例类
*/
public class SingleInstanceLazy {
/**
3、定义一个静态的成员变量存储一个对象,一开始不要初始化对象,因为人家是懒汉
*/
private static SingleInstanceLazy instance;
/**
2、私有化构造器
*/
private SingleInstanceLazy(){
}
/**
4、提供一个方法暴露,真正调用这个方法的时候才创建一个单例对象
*/
public static SingleInstanceLazy getInstance(){
if(instance == null){
// 第一次来拿对象,新建一个对象
instance = new SingleInstanceLazy();
}
return instance;
}
}
执行测试类 Test.java
package com.test.d6_singleinstance;
public class Test2 {
public static void main(String[] args) {
SingleInstanceLazy s1 = SingleInstanceLazy.getInstance();
SingleInstanceLazy s2 = SingleInstanceLazy.getInstance();
System.out.println(s1 == s2);
}
}
输出为true,即地址是相同的
饿汉单例和懒汉单例比较
优缺点:饿汉单例取对象快,懒汉单例节约内存
共同点:都要把构造器私有 -> 不让外部创建对象(合理隐藏)
都定义了一个单例类型的静态成员变量 -> 随着类只加载一次,保证最多一个实例对象
不同点:饿汉单例定义单例类型的静态变量时就初始化(外部需要访问,public),类一加载即创建对象; 懒汉单例定义单例类型的静态变量不初始化(外部无需访问,可私有化),后续通过公开的静态方法判断单例是否存在,首次访问则创建对象、否则返回静态变量指向的对象