1. 枚举类
1.1 枚举类介绍
- JDK1.5之前需要自定义枚举类,1.5新增的enum关键字用于定义枚举类。
- 枚举类的对象只有有限个,且都是确定的。
- 当需要定义一组常量时,强烈使用枚举类。
- 如果枚举类中只有一个对象,则可作为一种单例模式的实现方式。
1.2 自定义枚举类
- 声明类的属性,以private final修饰
- 私有化类的构造器,并给属性赋值
- 提供当前枚举类的多个对象,以public static final修饰
- 完成其他述求:获取对象属性、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 可重复注解
- 在MyAnnotation上声明@Repeatable,成员值为MyAnnotations.class,其中MyAnnotations为MyAnnotation类型数组的注解。
- 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类为泛型类,其子类指定具体类型对应具体表。