一.单例模式
单例模式是一种常见的设计模式,用于确保一个类只有一个实例,并提供全局访问点来获取该实例。在单例模式中,通过限制类的实例化过程,可以防止多个实例的创建,从而保证所有代码都使用同一个实例。
注意
- 1、单例类只能有一个实例。
- 2、单例类必须自己创建自己的唯一实例。
- 3、单例类必须给所有其他对象提供这一实例。
单例模式的几种实现方式
1、懒汉式,线程不安全
这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
//懒汉式,线程不安全
public class Singleton_Demo01 {
private static Singleton_Demo01 instance;
// 私有化构造方法,防止外部创建实例
private Singleton_Demo01() {
}
// 私有化构造方法,防止外部创建实例
public static Singleton_Demo01 getInstance() {
if (instance == null) {
instance = new Singleton_Demo01();
}
return instance;
}
}
2、懒汉式,线程安全
这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
//懒汉式,线程安全
public class Singleton_Demo02 {
private static Singleton_Demo02 instance;
// 私有化构造方法,防止外部创建实例
private Singleton_Demo02() {}
// 只有在首次调用时才创建实例
public static synchronized Singleton_Demo02 getInstance() {
if (instance == null) {
instance = new Singleton_Demo02();
}
return instance;
}
}
3、饿汉式(Eager initialization)
这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
//饿汉式(Eager initialization)
public class Singleton_Demo03 {
// 在类加载时就创建实例
private static Singleton_Demo03 instance = new Singleton_Demo03();
// 私有化构造方法,防止外部创建实例
private Singleton_Demo03() {}
// 提供公共的访问方法
public static Singleton_Demo03 getInstance() {
return instance;
}
}
4、双重检查锁定(Double-checked locking)
这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
//双重检查锁定(Double-checked locking)
public class Singleton_Demo04 {
private volatile static Singleton_Demo04 instance;
// 私有化构造方法,防止外部创建实例
private Singleton_Demo04() {
}
public static Singleton_Demo04 getInstance() {
if (instance == null) {
synchronized (Singleton_Demo04.class) {
if (instance == null) {
instance = new Singleton_Demo04();
}
}
}
return instance;
}
}
5、静态内部类(Static inner class)
这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
//静态内部类(Static inner class)
public class Singleton_Demo05 {
private static class SingletonHolder {
private static final Singleton_Demo05 INSTANCE = new Singleton_Demo05();
}
// 私有化构造方法,防止外部创建实例
private Singleton_Demo05() {
}
public static Singleton_Demo05 getInstance() {
return SingletonHolder.INSTANCE;
}
}
以上是几种常见的单例模式的实现方式,每种方式都有其适用的场景和特点。在选择使用哪种实现方式时,需要根据具体需求和线程安全性要求进行选择
二.反射模式
反射模式是一种软件设计模式,它允许程序在运行时动态地调查、获取和使用类或对象的信息。它提供了一种机制来检查和操作代码中的类型、属性、方法等元素,而无需显式编写这些元素的名称。
反射模式实现方法
1.首先要有一个类(用来验证反射)
package com.cskt.pojo;
import lombok.Data;
@Data
public class User_SupCc {
//私有属性字段
private Integer id;
private String name;
//公有属性字段
public String password;
public String address;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
", address='" + address + '\'' +
'}';
}
//私有方法 无参
private void PrivatelyShowWu(){
System.out.println("私有方法-无参!");
}
//私有方法 有参
private void PrivatelyShowYou(String name){
System.out.println("私有方法-有参! "+name);
}
//公共方法 无参
public void commonalityShowWu(){
System.out.println("公共方法-无参!");
}
//公共方法 有参
public void commonalityShowYou(String name){
System.out.println("公共方法-有参! "+name);
}
}
2.我们使用反射得到类、通过得到类获取字段
@Test //测试注解
@SneakyThrows //抛出异常注解
public void TestPojoUser(){
//放射模式 全路径 获取类
Class c1 = Class.forName("com.cskt.pojo.User_SupCc");
Constructor<User_SupCc> constructor = c1.getConstructor();
User_SupCc user_supCc = constructor.newInstance();
//公有属性调用
user_supCc.address="赛博坦";
user_supCc.password="123456";
//私有属性调用
//id
Field id = c1.getDeclaredField("id");
id.setAccessible(true);//设置true 才能这设置值
id.set(user_supCc,1);
//name
Field name = c1.getDeclaredField("name");
name.setAccessible(true);//设置true 才能这设置值
name.set(user_supCc,"SupCc");
System.out.println(user_supCc.toString());
}
测试结果
3.我们使用反射得到类、通过得到类获取、公共方法、私有方法
@Test //测试注解
@SneakyThrows //抛出异常注解
public void TestUserMethod(){
//放射模式 全路径 获取类
Class c2 = Class.forName("com.cskt.pojo.User_SupCc");
//公共方法获取 获取所有的public的方法
Constructor<User_SupCc> constructor = c2.getConstructor();
User_SupCc user_supCc = constructor.newInstance();
//公共无参方法
user_supCc.commonalityShowWu();
//公共有参方法
user_supCc.commonalityShowYou("SupCc");
//私有方法获取 获取指定的的private的方法
Method privatelyShowWu = c2.getDeclaredMethod("PrivatelyShowWu");
privatelyShowWu.setAccessible(true);//私有需要强制才能执行
privatelyShowWu.invoke(user_supCc);//执行方法
//私有方法调用 调用私有方法无参
Method privatelyShowYou = c2.getDeclaredMethod("PrivatelyShowYou",String.class);
privatelyShowYou.setAccessible(true);//私有需要强制才能执行
privatelyShowYou.invoke(user_supCc,"SupCc");//执行方法
}
测试结果
反射模式在某些情况下非常有用,例如在框架开发、插件系统、动态代理等场景中。它使得程序可以在运行时根据需要动态地加载和使用类,从而增加了程序的灵活性和可扩展性。
需要注意的是,由于反射模式具有较高的复杂性和性能开销,所以在普通的业务逻辑中并不需要频繁地使用反射。只有在确实需要动态处理类和对象时才应考虑使用反射模式。