javese 5 中的枚举类及单例模式

首先了解一下 javap 的用法,之后用到:javap -p (private)显示所有类和成员,javap -c  对代码进行反汇编。

java.lang.Eumn<E>,在java代码中使用关键字 enum 声明一个枚举类。你不能显示地创建一个 Eumn 对象,因为这个类的构造器只允许编译器调用。

通常实现一个枚举,需要手动创建很多 static final 变量,就像下面这样:

public static final int COLOR_RED = 0;
public static final int COLOR_GREEN = 1;
public static final int COLOR_YELLOW = 2;

public void setColor(int color) {
    //some code here
}
//调用
setColor(COLOR_RED)

如果使用枚举:

public enum Season {
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER
}

比上面那段代码要简洁很多,我们可以反编译看看它的源码:

E:\lemos\项目笔记\java基础\javase\code\01>javap -p Season
Compiled from "Season.java"
public final class Season extends java.lang.Enum<Season> {
  public static final Season SPRING;
  public static final Season SUMMER;
  public static final Season AUTUMN;
  public static final Season WINTER;
  private static final Season[] $VALUES;
  public static Season[] values();
  public static Season valueOf(java.lang.String);
  private Season();
  static {};
}

可以看到这个类继承自Enum,并设置为 final,也就是说这个类无法继承其他类也不能被继承。

具体编译下,查看它的汇编码,主要查看 static 代码块中包含哪些内容:

E:\lemos\项目笔记\java基础\javase\code\01>javap -c Season
Compiled from "Season.java"
public final class Season extends java.lang.Enum<Season> {
  public static final Season SPRING;

  public static final Season SUMMER;

  public static final Season AUTUMN;

  public static final Season WINTER;

  public static Season[] values();
    Code:
       0: getstatic     #1                  // Field $VALUES:[LSeason;
       3: invokevirtual #2                  // Method "[LSeason;".clone:()Ljava/lang/Object;
       6: checkcast     #3                  // class "[LSeason;"
       9: areturn

  public static Season valueOf(java.lang.String);
    Code:
       0: ldc           #4                  // class Season
       2: aload_0
       3: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
       6: checkcast     #4                  // class Season
       9: areturn

  static {};
    Code:
       0: new           #4                  // class Season
       3: dup
       4: ldc           #7                  // String SPRING
       6: iconst_0
       7: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      10: putstatic     #9                  // Field SPRING:LSeason;
      13: new           #4                  // class Season
      16: dup
      17: ldc           #10                 // String SUMMER
      19: iconst_1
      20: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      23: putstatic     #11                 // Field SUMMER:LSeason;
      26: new           #4                  // class Season
      29: dup
      30: ldc           #12                 // String AUTUMN
      32: iconst_2
      33: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      36: putstatic     #13                 // Field AUTUMN:LSeason;
      39: new           #4                  // class Season
      42: dup
      43: ldc           #14                 // String WINTER
      45: iconst_3
      46: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      49: putstatic     #15                 // Field WINTER:LSeason;
      52: iconst_4
      53: anewarray     #4                  // class Season
      56: dup
      57: iconst_0
      58: getstatic     #9                  // Field SPRING:LSeason;
      61: aastore
      62: dup
      63: iconst_1
      64: getstatic     #11                 // Field SUMMER:LSeason;
      67: aastore
      68: dup
      69: iconst_2
      70: getstatic     #13                 // Field AUTUMN:LSeason;
      73: aastore
      74: dup
      75: iconst_3
      76: getstatic     #15                 // Field WINTER:LSeason;
      79: aastore
      80: putstatic     #1                  // Field $VALUES:[LSeason;
      83: return
}

其中,

0~52为实例化SPRING, SUMMER, AUTUMN, WINTER
53~83为创建Season[]数组$VALUES,并将上面的四个对象放入数组的操作.

单例模式

  • 饿汉式加载
  • 懒汉式synchronize和双重检查
  • 利用java的静态加载机制
  • 使用枚举

饿汉式

public class Singleton{
    //类加载时就初始化
    private static final Singleton instance = new Singleton();
    
    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
}

双重校验锁( 使用双重 if判断,可以减少 synchronized 性能开销)

这里使用 volatile 的目的是:避免重排序。直接原因也就是 初始化一个对象并使另一个引用指向他 这个过程可分为多个步骤:

  • 分配内存空间,
  • 初始化默认值(区别于构造器方法的初始化),
  • 初始化对象,
  • 将内存空间的地址赋值给对应的引用。

如果最后 2步替换顺序,则导致了可能会出现引用指向了对象并未初始化好的那块堆内存。

此外,注意 volatile 没有解决操作的原子性,仅仅避免了重排序。即有可能出现一个线程执行了前2步,而另一线程重新执行的情况,所以需要加 synchronized 关键字保证此过程是单线程同步的。

public class Singleton {

    //volatile 防止延迟初始化
    private volatile static Singleton instance;

    public static Singleton getInstance() {
        if (instance == null) { //判断是否已有单例生成
            synchronized (Singleton.class) {
                if (instance == null)  //判断是否已经赋值
                    instance = new Singleton();//instance为volatile,现在没问题了
            }
        }
        return instance;
    }
}

由于类的静态初始化会在类被加载时触发,并且线程安全的。所以可以使用静态内部类,同时实现懒加载。(静态内部类是独立的,不因基类加载而加载,只在被访问时才加载,因此可以实现懒加载。并且因为静态关系,内部类的任何静态成员(包括要单例的对象)都会在其加载时被初始化)

public class SingleInstance {
  private SingleInstance() {
  }
  
  public static SingleInstance getInstance() {
      return SingleInstanceHolder.sInstance;
  }
  
  private static class SingleInstanceHolder {
      private static SingleInstance sInstance = new SingleInstance();
  }
}

使用枚举 

public enum AppManager {
    INSTANCE;

    private String tagName;
    public void setTag(String tagName) {
        this.tagName = tagName;
    }

    public String getTag() {
        return tagName;
    }
}

当你调用时,只能通过 AppManager.INSTANCE 进行调用。比如:AppManager.INSTANCE.getTag(),这也满足单例的两个特性:按需加载和唯一实例。

转载于:https://my.oschina.net/lemos/blog/842349

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值