Java 枚举类型与泛型

Java 枚举类型与泛型

枚举类型可以取代以往的常量的定义方式,即将常量封装在类或者接口中,此外,它还提供了安全检查功能。枚举类型本质上还是以类的形式存在。

泛型的出现不仅仅可以让程序员少写某些代码,其主要作用还是解决泛型安全的问题,它提供编译时候的安全检查,不会因为将某个对象置于某个容器中而失去其类型。

枚举类型

以往的方式:

public class DayDemo {
public static final int MONDAY =1;
public static final int TUESDAY=2;
public static final int WEDNESDAY=3;
public static final int THURSDAY=4;
public static final int FRIDAY=5;
public static final int SATURDAY=6;
public static final int SUNDAY=7;
}

枚举出现后:

//枚举类型,使用关键字enum
enum Day {
MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

枚举类型Day中分别定义了从周一到周日的值,这里要注意,值一般是大写的字母,多个值之间以逗号分隔。

使用:

public class EnumDemo {
public static void main(String[] args){
//直接引用
Day day =Day.MONDAY;
}
}

//定义枚举类型
enum Day {
MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

就像上述代码那样,直接引用枚举的值即可,这便是枚举类型的最简单模型。

枚举类型的用法

用法1:常量

public enum Color { 
RED, GREEN, BLANK, YELLOW
}

用法2:switch

enum Signal {  
GREEN, YELLOW, RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch (color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}

用法3:向枚举中添加新方法

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;
}
// 普通方法
public static String getName(int index) {
for (Color c : Color.values()) {
if (c.getIndex() == index) {
return c.name;
}
}
return null;
}
// get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}

用法4:覆盖枚举的方法

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;
}
}

用法5:实现接口

所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。

用法6:使用接口组织枚举

用法7:关于集合的使用

泛型

泛型,即“参数化类型”。泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类泛型接口泛型方法

泛型类

public class Generic<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}

泛型接口

public interface Generator<T> {
public T next();
}

当实现泛型接口的类,未给泛型传入实参时:

class FruitGenerator<T> implements Generator<T>{
@Override
public T next() {
return null;
}
}

未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中。

如果不声明泛型,如:class FruitGenerator implements Generator,编译器会报错:”Unknown class”。

当实现泛型接口的类,给泛型传入了实参时

public class FruitGenerator implements Generator<String> {

private String[] fruits = new String[]{"Apple", "Banana", "Pear"};

@Override
public String next() {
Random rand = new Random();
return fruits[rand.nextInt(3)];
}
}

如果类已经将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型。即:Generator,public T next();中的的T都要替换成传入的String类型。

泛型方法

public class Util {
public static <K, V> boolean compare(Generic<K, V> g1, Generic<K, V> g2) {
return g1.getKey().equals(g2.getKey()) &&
g1.getValue().equals(g2.getValue());
}
}
public class Generic<K, V> {
private K key;
private V value;
public Generic(K key, V value) {
this.key = key;
this.value = value;
}
public void setKey(K key) { this.key = key; }
public void setValue(V value) { this.value = value; }
public K getKey() { return key; }
public V getValue() { return value; }
}

Util.compare()就是一个泛型方法,于是我们可以像下面这样调用泛型:

Generic<Integer, String> g1 = new Generic<>(1, "apple");
Generic<Integer, String> g2 = new Generic<>(2, "pear");
boolean same = Util.<Integer, String>compare(g1, g2);

可缩写成:

Generic<Integer, String> p1 = new Generic<>(1, "apple");
Generic<Integer, String> p2 = new Generic<>(2, "pear");
boolean same = Util.compare(p1, p2);

通配符

Generic不能被看作为Generic的子类。由此可以看出:同一种泛型可以对应多个版本(因为参数类型是不确定的),而不同版本的泛型类实例之间是不兼容的。

此时可以:

public void showKeyValue(Generic<?> obj){
System.out.println("泛型测试,value is " + obj.get());
}

此时,showKeyValue方法可以传入任意类型的Generic参数,这是一个无界的通配符。

泛型上下边界

在Java泛型定义时:
<T>等大写字母标识泛型类型,用于表示未知类型。
<T extends ClassA & InterfaceB …>等标识有界泛型,用于表示有边界的类型。
在Java泛型实例化时:
<?>标识通配符,用于表示实例化时的类型。
<? extends 父类型>标识上边界通配符,用于表示实例化时可以确定父类型的类型。
<? super 子类型>标识下边界通配符,用于表示实例化时可以确定子类型的类型。
对上面的Generic类增加一个新方法:

public void showKeyValue1(Generic<? extends Number> obj){
System.out.println("泛型测试,value is " + obj.get());
}
Generic<String> generic1 = new Generic<String>("11111");
Generic<Integer> generic2 = new Generic<Integer>(2222);
Generic<Float> generic3 = new Generic<Float>(2.4f);
Generic<Double> generic4 = new Generic<Double>(2.56);

//这一行代码编译器会提示错误,因为String类型并不是Number类型的子类
showKeyValue1(generic1);

showKeyValue1(generic2);
showKeyValue1(generic3);
showKeyValue1(generic4);

泛型的限制

1. Java泛型不能使用基本类型

2.Java泛型不允许进行直接实例化

3.Java泛型不允许进行静态化

4.Java泛型不允许直接进行类型转换(通配符可以)

5.Java泛型不允许直接使用instanceof运算符进行运行时类型检查(通配符可以)

6.Java泛型不允许创建确切类型的泛型数组(通配符可以)

7.Java泛型不允许作为参数进行重载

参考

https://www.jianshu.com/p/31b44188b973

https://www.cnblogs.com/alter888/p/9163612.html

https://www.cnblogs.com/jin-zhe/p/8259422.html

Author: pangzibo243
Link: https://litianbo243.github.io/2019/10/08/Java-枚举类型与泛型/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
支付宝打赏
微信打赏