Java 枚举
之前写过的文档:https://blog.csdn.net/Roobert_Chao/article/details/78637972
枚举对象的常用方法
Java 枚举的本质理解
Java 枚举的本质原理是通过普通类来实现的,经过编译器的加工处理(编译后生成的类是final class 类,且继承了 Enum 类
),枚举值加工成为类的静态常量属性,其属性在类加载的静态代码块中被初始化实例赋值。
查看字节码(.class)文件
- 命令行的方式:javap -c 文件所在目录。
- 使用插件工具 【IDEA】,添加插件 jclasslib bytecode viewer。
- 下载本地工具【JBE - Java Bytecode Editor】: http://set.ee/jbe/
上述枚举类型的编译后的代码如下:
public final class cn.chao.override.equals.ColorEnum extends java.lang.Enum<cn.chao.override.equals.ColorEnum> { // 类变成了 final class
// 三种静态常量
public static final cn.chao.override.equals.ColorEnum RED;
public static final cn.chao.override.equals.ColorEnum BLUE;
public static final cn.chao.override.equals.ColorEnum GREEN;
// 自定义字符串类型的属性
public java.lang.String color;
static {};
Code:
0: new #1 // class cn/chao/override/equals/ColorEnum
3: dup
4: ldc #16 // String RED
6: iconst_0
7: ldc #17 // String red
9: invokespecial #19 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
12: putstatic #23 // Field RED:Lcn/chao/override/equals/ColorEnum;
15: new #1 // class cn/chao/override/equals/ColorEnum
18: dup
19: ldc #25 // String BLUE
21: iconst_1
22: ldc #26 // String blue
24: invokespecial #19 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
27: putstatic #28 // Field BLUE:Lcn/chao/override/equals/ColorEnum;
30: new #1 // class cn/chao/override/equals/ColorEnum
33: dup
34: ldc #30 // String GREEN
36: iconst_2
37: ldc #31 // String green
39: invokespecial #19 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
42: putstatic #33 // Field GREEN:Lcn/chao/override/equals/ColorEnum;
45: iconst_3
46: anewarray #1 // class cn/chao/override/equals/ColorEnum
49: dup
50: iconst_0
51: getstatic #23 // Field RED:Lcn/chao/override/equals/ColorEnum;
54: aastore
55: dup
56: iconst_1
57: getstatic #28 // Field BLUE:Lcn/chao/override/equals/ColorEnum;
60: aastore
61: dup
62: iconst_2
63: getstatic #33 // Field GREEN:Lcn/chao/override/equals/ColorEnum;
66: aastore
67: putstatic #35 // Field ENUM$VALUES:[Lcn/chao/override/equals/ColorEnum;
70: return
public static cn.chao.override.equals.ColorEnum[] values();
Code:
0: getstatic #35 // Field ENUM$VALUES:[Lcn/chao/override/equals/ColorEnum;
3: dup
4: astore_0
5: iconst_0
6: aload_0
7: arraylength
8: dup
9: istore_1
10: anewarray #1 // class cn/chao/override/equals/ColorEnum
13: dup
14: astore_2
15: iconst_0
16: iload_1
17: invokestatic #47 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
20: aload_2
21: areturn
public static cn.chao.override.equals.ColorEnum valueOf(java.lang.String);
Code:
0: ldc #1 // class cn/chao/override/equals/ColorEnum
2: aload_0
3: invokestatic #55 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #1 // class cn/chao/override/equals/ColorEnum
9: areturn
}
枚举类与常量类
在使用枚举类的时候,发现枚举常量+枚举值,和常量类中常量赋值是一样的。那么为什么会出现枚举类呢 ???
- 枚举相对于常量类来说更加的简单,可以不定义枚举值。而常量类中的每个常量必须要手动添加值。
- 枚举类自动具备内置方法(如 values 方法可以获得所有值的集合类遍历,ordinal 方法可以获得排序值,compareTo 方法可以基于 ordinal 比较)。常量类不具备这些方法。
枚举类编译后生成了 final class 类,且继承了 Enum 类(Java 单继承机制),所以枚举类不能够继承,但是定义的枚举类可以通过 implement 实现其他接口。
Java 枚举与线程安全
1. Java 类加载和初始化是 Java 虚拟机(JVM )保证线程安全。
2. static 的常量属性和代码块都是在类加载时初始化完成的。
Java 枚举类编译后的代码,实质上是一个 final 类,枚举常量初始化都是在 static 代码块中进行的,自然就 JVM 保证线程安全。
Java 泛型(参数化类型)
之前写过的文档:https://blog.csdn.net/Roobert_Chao/article/details/78634340
1. 参数化类型,泛型类、泛型接口、泛型方法
。
2. 提高了代码的重用率,避免在运行时出现 ClassCastException。
Java 泛型是通过 擦除
来实现的
- Java 泛型是通过擦除来实现的,所以编译后的任何具体泛型类型都被擦除了。
(替换为非泛型上边界,没有上边界,则上边界就是 Object 类型。)
通过反射增加字符串
观察如下的代码:输出结果为
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.getClass().getMethod("add", Object.class).invoke(list, "abc");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
由于在程序中定义的 ArrayList 泛型类型实例化为 Integer 的对象,如果直接调用 add 方法则只能存储整型数据,不过当我们利用反射调用 add 方法时,就可以存储字符串。因为 Integer 泛型实例在编译之后被擦除了,只保留了原始类型 Object 。
- 擦除前的类型检查是
针对引用的
,用这个引用调用泛型方法就会对这个引用调用的方法进行类型检测而无关真正引用的对象。泛型中参数化类型不支持继承关系。且不能是基本类型。
- 泛型无法进行具体泛型参数类型的运行时检查。而且不能抛出,也不能捕获泛型类对象。
arrayList instanceof ArrayList<String> 是非法的。
arrayList instanceof ArrayList<?> 仅这种方式。
- Java 的泛型数组不能采用具体的泛型类型进行初始化。只能通过通配符的形式。
建议:
List<?>[] list = new ListArray<?>[10];