首先了解一下 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(),这也满足单例的两个特性:按需加载和唯一实例。