泛型和枚举的学习笔记
泛型Generic
泛型类
package demo;public class SuperArray<T> { private Object[] array; //根据下标查询数字 //当前最后一个数字的下边,要为-1 ,以为数组的第一个下标为0 private int currentIndex = -1; //构造是初始化 public SuperArray(){ array = new Object[8]; } //添加数据的方法 public void add(T data){ System.out.println("我是数组的实现!---add"); currentIndex++; //自动扩容 if(currentIndex > array.length-1){ array = dilatation(array); } array[currentIndex] = data; } public T get(int index){ System.out.println("我是数组的实现---get"); return (T)array[index]; } //数组扩容的方法 private Object[] dilatation(Object[] oldArray){ Object[] newArray = new Object[oldArray.length * 2]; for (int i = 0; i < oldArray.length; i++) { newArray[i] = oldArray[i]; } return newArray; } //验证下标是否合法 private boolean validateIndex(int index) { //只要有一个不满足就返回false return index <= currentIndex && index >= 0; } public static void main(String[] args) { SuperArray<String> superArray=new SuperArray<>(); superArray.add("123"); superArray.add("456"); System.out.println(superArray.get(1)); }}
在类后加入,使用时声明该泛型是哪个类
泛型方法
package demo;public class Demo1 { public <T> T show(T t){ System.out.println(t); return t; } public static <T> T show2(T t){ System.out.println(t); return t; } public static void main(String[] args) { Demo1 demo1 = new Demo1(); Integer show = demo1.show(123); String s = Demo1.show2("123"); }}
方法定义要加入, 最后尽量返回泛型,如果不返回的话,相当于用Object
泛型继承
public interface Comparator<T>{ int compare(T t1,T t2);}
package demo;public class User { private String name; private Integer age; public User() { } public User(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; }}
package demo;public class UserComparator implements Comparator<User>{ @Override public int compare(User t1, User t2) { return t1.getAge()- t2.getAge(); }}
package demo;public class Test1 { public static void main(String[] args) { UserComparator userComparator=new UserComparator();// Comparator userComparator=new UserComparator(); int compare = userComparator.compare(new User("zs", 18), new User("ls", 16)); System.out.println(compare); }}
明确类型的泛型继承,也可以用不明确类型的,(把UserComparator替换成泛型类)
类型通配符
- 无界(SuperArray superArray)
- 上界((SuperArray superArray) dog类及其子类都能放入数组
- 下界 (SuperArray superArray) dog类及其父类都能放入数组
类型擦除
-
不能用类型参数替换基本类型。就比如,没有
SuperArray
,只有SuperArray
。因为当类型擦除后,SuperArray
的原始类型变为Object
,但是Object
类型不能存储double
值,只能引用Double
的值 -
泛型被擦除后,其实这两个方法是一致的,并不能构成泛型。
-
类型擦除和多态冲突 虚拟机巧妙的使用了桥方法,来解决了类型擦除和多态的冲突(类型擦除后,JVM自动补充方法把Object方法补充,区分Date的方法,来区分方法调用)
静态方法和静态类中的问题
public class Test2<T> { public static T one; //编译错误 public static T show(T one){ //编译错误 return null; } }
因为泛型类中的泛型参数的实例化是在定义对象的时候指定的,而静态变量和静态方法不需要使用对象来调用。对象都没有创建,如何确定这个泛型参数是何种类型,所以当然是错误的。
public class Test2<T> { public static <T> T show(T one){ //这是正确的 return null; } }
因为这是泛型方法
枚举 enum
枚举基本特性
本质是静态常量
public class SeasonConstant { public static final int SPRING = 1; public static final int SUMMER = 2; public static final int AUTUMN = 3; public static final int WINTER = 4;}
public enum SeasonEnum { SPRING,SUMMER,AUTUMN,WINTER;}
values() 静态的自动生成的 | 可以遍历enum实例,其返回enum实例的数组 |
---|---|
ordinal() 父类的实例方法 | 返回每个实例在声明时的次序 |
name() 父类的实例方法 | 返回enum实例声明时的名称 |
getDeclaringClass() | 返回其所属的enum类 |
valueOf() 静态的自动生成的 | 根据给定的名称返回相应的enum实例 |
package demo;public class Test1 { public static void main(String[] args) { SeasonEnum[] values = SeasonEnum.values(); for (int i = 0; i < values.length; i++) { System.out.println(values[i].name()); System.out.println(values[i].ordinal()); System.out.println(values[i].getDeclaringClass()); System.out.println("----------------"); } }}
Enum中添加新方法
public enum SeasonEnum { SPRING("春天","春暖花开的季节"), SUMMER("夏天","热的要命,但是小姐姐都穿短裤"), AUTUMN("秋天","果实成熟的季节"), WINTER("冬天","冷啊,可以吃火锅"); private String name; private String detail; SeasonEnum() { } SeasonEnum(String name, String detail) { this.name = name; this.detail = detail; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; }}
Switch语句中的Enum
public static void main(String[] args) { SeasonEnum season = SeasonEnum.SPRING; switch (season){ case SPRING: System.out.println("春天来了,又到了万物交配的季节!"); case SUMMER: System.out.println("夏天来了,又可以穿大裤衩了!"); case AUTUMN: System.out.println("秋天来了,又到了收获的季节!"); case WINTER: System.out.println("冬天来了,又到了吃火锅的季节了!"); default: System.out.println("也没有别的季节了。"); }}
- 常规情况下必须使用 enum 类型来修饰 enum 实例,但在 case 语句中不必如此,
- 意思就是
case SPRING:
不需要写成case SeasonEnum.SPRING:
枚举的优势
阿里《Java开发手册》对枚举的相关规定如下:
【强制】所有的枚举类型字段必须要有注释,说明每个数据项的用途。
【参考】枚举类名带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。说明:枚举其实就是特殊的常量类,且构造方法被默认强制是私有。正例:枚举名字为 ProcessStatusEnum 的成员名称:SUCCESS / UNKNOWN_REASON。
int
类型本身并不具备安全性,假如某个程序员在定义int
时少些了一个final
关键字,那么就会存在被其他人修改的风险,而反观枚举类,它“天然”就是一个常量类,不存在被修改的风险- 使用
int
类型的语义不够明确,比如我们在控制台打印时如果只输出 1…2…3 这样的数字,我们肯定不知道它代表的是什么含义 - 对程序修改常量时,只需要对枚举修改,不用对所有常量进行修改