欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

阿里巴巴Java成神之路-笔记(7)枚举类型和泛型

程序员文章站 2024-03-23 12:45:28
...

Java语言基础(7)

1. 枚举

从Java1.5开始,枚举类型( enum type) 是指由一组固定的常量组成合法的类型。 Java 中由关键字enum (小写!)来定义一个枚举类型。 下面就是 java 枚举类型的定义。
枚举可以在编译期间实现自动的类型检查。

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

enum既然是类,就可以定义属性和方法,如下:
RED,GREEN,BALNK,YELLOW 都是enum类型的 实例对象

下面的 name, index,Color(),toString() 是它们4个都有的属性或者方法。
所以类似RED("红色", 1) 就是调用下面的Color()构造函数 初始化Color对象RED.

public enum Color {
	RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
	
	// 成员变量
	private String name;
	private int index;
	// 构造方法
	private Color(String name, int index) {
		this.name = name;
		this.index = index;
	}
	//覆盖方法
	@Override
	public String toString() {
	return this.index+"_"+this.name;
	}
}

1.1 枚举的实现

那么枚举类型到底是什么类呢? 是 enum 吗?
答案很明显不是, enum 就和 class 一样, 只是一个关键字, 他并不是一个类, 那么枚举是由什么类维护的呢, 我们简单的写一个枚举:

public enum t {
	SPRING,SUMMER;
}

然后我们使用反编译, 看看这段代码到底是怎么实现的, 反编译后代码内容如下:

public final class T extends Enum
{
	private T(String s, int i)
	{
		super(s, i);
	}
	public static T[] values()
	{
		T at[];
		int i;
		T at1[];
		System.arraycopy(at = ENUM$VALUES, 0, at1 = new T[i = at.length], 0,
i);
	return at1;
	}
	public static T valueOf(String s)
	{
		return (T)Enum.valueOf(demo/T, s);
	}
	public static final T SPRING;
	public static final T SUMMER;
	private static final T ENUM$VALUES[];
	static
	{
		SPRING = new T("SPRING", 0);
		SUMMER = new T("SUMMER", 1);
		ENUM$VALUES = (new T[] {
			SPRING, SUMMER
		});
	}
}

通过反编译后代码我们可以看到, public final class T extends Enum, 说明, 该类是继承了 Enum 类的, 同时 final 关键字告诉我们, 这个类也是不能被继承的。

当我们使用 enmu 来定义一个枚举类型的时候, 编译器会自动帮我们创建一个 final类型的类继承 Enum 类, 所以枚举类型不能被继承。

java 枚举值比较用 ==equals 方法没啥区别, 两个随便用都是一样的效果。

因为枚举 Enum 类的 equals 方法默认实现就是通过 == 来比较的; 类似的Enum 的 compareTo 方法比较的是 Enum 的 ordinal 顺序大小; 类似的还有 Enum的 name 方法和 toString 方法一样都返回的是 Enum 的 name 值。

1.2 枚举与单例模式

阿里巴巴Java成神之路-笔记(7)枚举类型和泛型

双重锁校验实现的单例模式的代码之所以很臃肿, 是因为大部分代码都是在保证线程安全。 为了在保证线程安全和锁粒度之间做权衡, 代码难免会写的复杂些。 但是, 这段代码还是有问题的, 因为他无法解决反序列化会破坏单例的问题。

枚举可解决线程安全问题

阿里巴巴Java成神之路-笔记(7)枚举类型和泛型
阿里巴巴Java成神之路-笔记(7)枚举类型和泛型

下面是enum实现单例模式 返回 User 对象

public class User {
    //私有化构造函数
    private User(){ }
 
    //定义一个静态枚举类
    static enum SingletonEnum{
        INSTANCE;//创建一个枚举对象INSTANCE,该对象天生为单例
        private User user;
        //私有化枚举的构造函数
        private SingletonEnum(){
            user=new User();
        }
        public User getInstnce(){
            return user;
        }
    }
 
    //对外暴露一个获取User对象的静态方法
    public static User getInstance(){
        return SingletonEnum.INSTANCE.getInstnce();
    }
}

public class Test {
    public static void main(String [] args){
        System.out.println(User.getInstance());
        System.out.println(User.getInstance());
        System.out.println(User.getInstance()==User.getInstance());
    }
}
结果为true

2. 泛型

Java 泛型( generics) 是 JDK 5 中引⼊的⼀个新特性, 允许在定义类和接口时候使⽤类型参数。泛型最⼤的好处是可以提高代码的复用性

2.1 类型擦除

类型擦除指的是通过类型参数合并, 将泛型类型实例关联到同一份字节码上。 编译器只为泛型类型生成一份字节码, 并将其实例关联到这份字节码上。 类型擦除的关键在于从泛型类型中清除类型参数的相关信息, 并且再必要的时候添加类型检查和类型转换的方法。 类型擦除可以简单的理解为将泛型 java 代码转换为普通 java 代码, 只不过编译器更直接点,将泛型 java 代码直接转换成普通 java 字节码。 类型擦除的主要过程如下: 1.将所有的泛型参数用其最左边界( 最*的父类型) 类型替换。 ( 这部分内容可以看: Java 泛型中 extends 和 super 的理解) 2.移除所有的类型参数。

阿里巴巴Java成神之路-笔记(7)枚举类型和泛型

2.2 泛型带来的问题

  1. 泛型遇到重载
public class GenericTypes {
	public static void method(List<String> list) {
		System.out.println("invoke method(List<String> list)");
	} 
	public static void method(List<Integer> list) {
		System.out.println("invoke method(List<Integer> list)");
	}
}

上面这段代码, 有两个重载的函数, 因为他们的参数类型不同, 一个是 List<String>另一个是 List<Integer> , 但是, 这段代码是编译通不过的。 因为我们前面讲过, 参数List<Integer>List<String>编译之后都被擦除了, 变成了一样的原生类型 List, 擦除动作导致这两个方法的特征签名变得一模一样。

  1. 泛型内包含静态变量
public class StaticTest {
	public static void main(String[] args){
		GT<Integer> gti = new GT<Integer>();
		gti.var=1;
		GT<String> gts = new GT<String>();
		gts.var=2;
		System.out.println(gti.var);
	}
}

class GT<T>{
	public static int var=0;
	public void nothing(T x){}
}

答案是: 2! 由于经过类型擦除, 所有的泛型类实例都关联到同一份字节码上, 泛型类的所有静态变量是共享的。

总结:

阿里巴巴Java成神之路-笔记(7)枚举类型和泛型

2.3 List<Object>和原始类型 List 之间的区别

阿里巴巴Java成神之路-笔记(7)枚举类型和泛型