8. Java枚举类&注解&泛型

1. 枚举类

1.1 枚举类介绍

  • JDK1.5之前需要自定义枚举类,1.5新增的enum关键字用于定义枚举类。
  • 枚举类的对象只有有限个,且都是确定的。
  • 当需要定义一组常量时,强烈使用枚举类。
  • 如果枚举类中只有一个对象,则可作为一种单例模式的实现方式。

1.2 自定义枚举类

  1. 声明类的属性,以private final修饰
  2. 私有化类的构造器,并给属性赋值
  3. 提供当前枚举类的多个对象,以public static final修饰
  4. 完成其他述求:获取对象属性、toString()方法
class Season {
    
    
    private final String seasonName;
    private final String seasonDesc;

    private Season(String seasonName, String seasonDesc) {
    
    
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }

    public static final Season SPRING=new Season("春","春日暖阳");
    public static final Season SUMMER=new Season("夏","夏日清风");
    public static final Season AUTUMN=new Season("秋","秋日落叶");
    public static final Season WINTER=new Season("冬","冬日暮雪");

    public String getSeasonName() {
    
    
        return seasonName;
    }

    public String getSeasonDesc() {
    
    
        return seasonDesc;
    }

    @Override
    public String toString() {
    
    
        return "Season{" +
                "seasonName='" + seasonName + '\'' +
                ", seasonDesc='" + seasonDesc + '\'' +
                '}';
    }
}

1.3 使用关键字enum定义枚举类

  • 将当前枚举类的对象放在类的开头,并删除相同部分,多个对象间用逗号隔开,最后一个对象以分号结尾。
  • 定义的枚举类默认继承于java.lang.Enum类,其toString()方法打印当前对象的名字。
enum  Season1{
    
    
    SPRING("春","春日暖阳"),
    SUMMER("夏","夏日清风"),
    AUTUMN("秋","秋日落叶"),
    WINTER("冬","冬日暮雪");

    private final String seasonName;
    private final String seasonDesc;

    private Season1(String seasonName, String seasonDesc) {
    
    
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }

    public String getSeasonName() {
    
    
        return seasonName;
    }

    public String getSeasonDesc() {
    
    
        return seasonDesc;
    }
}

1.4 Enum类中的常用方法

  • values():返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值。
  • valueOf(String str):可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的名字。
  • toString():返回当前枚举类对象常量的名称。

1.5 实现接口的枚举类
可以直接在枚举类中重写接口的抽象方法,也可以让枚举类的每个对象分别重写接口的抽象方法。

interface info {
    
    
    void show();
}

enum Season2 implements info {
    
    
    SPRING("春", "春日暖阳") {
    
    
        @Override
        public void show() {
    
    
            System.out.println("春天");
        }
    },
    SUMMER("夏", "夏日清风") {
    
    
        @Override
        public void show() {
    
    
            System.out.println("夏天");
        }
    },
    AUTUMN("秋", "秋日落叶") {
    
    
        @Override
        public void show() {
    
    
            System.out.println("秋天");
        }
    },
    WINTER("冬", "冬日暮雪") {
    
    
        @Override
        public void show() {
    
    
            System.out.println("冬天");
        }
    };

    private final String seasonName;
    private final String seasonDesc;

    private Season2(String seasonName, String seasonDesc) {
    
    
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }
}

2. 注解(Annotation)

2.1 注解概述

  • 注解就是在代码里的特殊标记,这些标记可以再编译、类加载、运行时被读取,并执行相应的处理。
  • 通过使用注解,程序员可以在不改变原有逻辑的情况下,在原文件中嵌入一些补充信息。
  • 代码分析工具、开发工具、部署工具可以通过这些补充信息进行验证或进行部署。
  • 注解可以像修饰符一样被使用,可用于修饰:包、类、构造器、方法、成员变量、参数、局部变量的声明,这些信息被保存在注解中的“name = value”对中。

2.2 常见的注解
2.2.1 生成文档相关的注解
如@author、@version、@see、@since、@param、@return、@exception

2.2.2 在编译时进行格式检查
JDK中有3个内置的基本注解:

  • @Override:重写父类方法(该注解只能用于方法)
  • @Deprecated:所修饰的元素已过时
  • @SuppressWarnings:抑制编译器警告

2.2.3 跟踪代码依赖性,实现替代配置文件功能

  • Servlet3.0中提供了注解,使得不再需要在web.xml文件中进行Servlet的部署
  • Spring框架中使用注解对事务进行管理

2.3 自定义注解

  • 注解的类型声明为@interface,自定义注解自动继承了java.lang.annotation.Annotation接口。
  • 注解的成员变量以无参数方法的形式来声明,其方法名和返回值定义了该成员的名字和类型,称为配置参数。如果只有一个参数成员,建议使用参数名为“value”。
  • 可以在定义注解的成员变量时为其制定初始值,指定成员变量的初始值使用default关键字。
  • 若果定义的注解含有配置参数,那么使用时必须指定参数值,除非有默认值。格式为“参数名 = 参数值”,如果只有一个参数成员,且名为“value”,可省略“value = ”。
  • 没有成员定义的注解称为标记,包含成员变量的注解称为元数据注解
//定义
public @interface MyAnnotation{
    
    
	String value() default "hello";
}
//使用(自定义注解使用反射才有意义)
@MyAnnotation(value = "wwww")

2.4 元注解
JDK提供了4种元注解,元注解用于修饰其他注解。

  • @Retention:指定被修饰注解的生命周期(能保留多长时间),值包括:SOURCE、CLASS、RUNTIME。只有声明为RUNTIME生命周期的注解,才能通过反射获取。
  • @Target:指定被修饰的注解能用于修饰哪些程序元素。
  • @Documented:被修饰的注解类会被javadoc工具提取称文档。
  • @Inherited:被修饰的注解类具有继承性,其子类自动有该注解。

2.5 利用反射获取注解信息
2.6 JDK 8中注解的新特性
2.6.1 可重复注解

  1. 在MyAnnotation上声明@Repeatable,成员值为MyAnnotations.class,其中MyAnnotations为MyAnnotation类型数组的注解。
  2. MyAnnotation的Target和Retention等元注解信息和MyAnnotations相同。

2.6.2 类型注解

  • ElementType.TYPE_PARAMETER表示该注解能写在类型变量的声明语句中(如:泛型声明)。
  • ElementType.TYPE_USE表示该注解能写在使用类型的任何语句中。

3. 泛型

3.1 为什么要有泛型
泛型类似于生活中的标签。集合容器类在声明阶段不能确定这个容器存的什么类型的对象,在JDK5之前只能把元素类型设计为Object,JDK5之后使用泛型来解决,此时把元素的类型设计成一个参数,这个类型参数叫做泛型。

Collection< E >,List< E >,ArrayList< E >中的< E >就是类型参数,即泛型。

使用泛型前存在的问题(使用泛型后解决的问题):

  • 元素存储时,类型不安全。使用泛型后,在编译时就会进行类型检查。
  • 读取元素时,类型强转可能报错。使用泛型后,避免了强转操作。

3.2 在集合中使用泛型

  • 集合接口或集合类在JDK5时都修改为带泛型的结构
  • 在实例化集合类时,可以指明具体的泛型类型
  • 指明泛型类型后,集合类的内部结构所有使用泛型的位置,都变为指定的泛型类型
  • 泛型的类型必须是类,不能是基本数据类型(用包装类替换)
  • 若实例化时没有指明泛型的类型,默认类型为Object
  • JDK7开始,new后接的泛型可以省略(类型推断)
@Test
public void test(){
    
    
    ArrayList<Integer> list = new ArrayList<Integer>();
    list.add(123);
    list.add(1234);
    list.add(12345);
    Iterator<Integer> iterator = list.iterator();
    while (iterator.hasNext()){
    
    
        System.out.println(iterator.next());
    }
}
//定义Map时,会用到泛型的嵌套
@Test
public void test1(){
    
    
    HashMap<String, Integer> map = new HashMap<>();
    map.put("Tom",88);
    map.put("Jack",76);
    map.put("Mary",68);
    Set<Map.Entry<String, Integer>> entries = map.entrySet();
    Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
    while (iterator.hasNext()) {
    
    
        System.out.println(iterator.next());
    }
}

3.3 自定义泛型结构
3.3.1 自定义泛型类、泛型接口

  • 泛型类可能由多个参数,此时应将多个参数一起放在尖括号内。如:<E1,E2,E3>
  • 泛型类的构造器中不带泛型
  • 泛型不同的引用不能相互赋值(ArrayList< String >不能赋值给ArrayList< Integer >)
  • 静态方法中不能使用类的泛型
  • 异常类不能是泛型的
  • 不能使用new E[],但可以用:E[] e = (E[])new Object[capacity];
public class Order<T> {
    
    
    String orderName;
    int orderId;
    T orderT;

    public Order() {
    
    
    }

    public Order(String orderName, int orderId, T orderT) {
    
    
        this.orderName = orderName;
        this.orderId = orderId;
        this.orderT = orderT;
    }

    public T getOrderT() {
    
    
        return orderT;
    }

    public void setOrderT(T orderT) {
    
    
        this.orderT = orderT;
    }
}
  • 子类继承泛型类或泛型接口时,可以指明泛型的类型。在实例化子类对象时,不再需要指明泛型。若未指明泛型的类型,则仍然是泛型类。
  • 子类除了指定或保留父类的泛型,还可以增加自己的泛型。
public class subOrder extends Order<Integer> {
    
    
}

public class subOrder1<T> extends Order<T>{
    
    
}

public class subOrder2 extends Order{
    
     //等价于Order<Object>
}

 @Test
 public void test2(){
    
    
     Order<String> order = new Order<>("AA",12,"kk");
     order.setOrderT("www");
     System.out.println(order);

     subOrder subOrder = new subOrder();
     subOrder1<String> subOrder1 = new subOrder1<>();
 }

3.3.2 自定义泛型方法
泛型方法中的泛型参数与类的泛型参数没有任何关系,泛型方法不一定要处于泛型类,泛型方法可以是static。

public <E> E getE(E e){
    
     
//<E>表示该方法未泛型方法,且声明了一个泛型E。该方法的返回类型为泛型E。
    return e;
}

Integer i = order.getE(2);

3.4 泛型在继承上的体现

  • List< String >不能赋值给List< Object >,这两者没有子父类关系,是并列关系。
  • String< T >可以赋值给Object< T >,是子父类关系

3.5 通配符的使用
3.5.1 所有泛型的通配符

  • 通配符:?
  • 可用通配符表示并列的泛型(所有泛型的父类),可以避免方法的重载
  • List<?>中不能添加数据,除了null;可以读取Object类型的数据
List<Object> list1 = null;
List<String> list2 = null;
List<?> list = null;
list = list1;
list = list2;

3.5.2 有限制的通配符

  • 上限entends:使用时指定的类型必须时继承某个类,或实现某个接口,即<=
  • 下限super:使用时指定的类型不能小于操作的类,即>=
  • <? super Number>:只允许泛型为Number或Number父类的引用调用
  • <? extends Comparable>:只允许泛型为实现Comparable接口的实现类的引用调用

3.6 泛型应用举例
在使用Java对数据库进行操作时,由于不确定操作的是哪一张表,创建的DAO类为泛型类,其子类指定具体类型对应具体表。

猜你喜欢

转载自blog.csdn.net/qq_43221336/article/details/108368426
今日推荐