泛型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<User> userComparator=new UserComparator();
int compare = userComparator.compare(new User("zs", 18), new User("ls", 16));
System.out.println(compare);
}
}
明确类型的泛型继承,也可以用不明确类型的,(把UserComparator替换成泛型类)
类型通配符
- 无界(SuperArray<?> superArray)
- 上界((SuperArray<? extends Dog> superArray) dog类及其子类都能放入数组
- 下界 (SuperArray<? super Dog> superArray) dog类及其父类都能放入数组
类型擦除
-
不能用类型参数替换基本类型。就比如,没有
SuperArray<double>
,只有SuperArray<Double>
。因为当类型擦除后,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 这样的数字,我们肯定不知道它代表的是什么含义 - 对程序修改常量时,只需要对枚举修改,不用对所有常量进行修改