天天看点

Java的一些高级特性

静态导入

    用于导入类中的静态成员和静态方法,格式如下:

import static java.lang.math.*;     // 在当前命名空间导入所有静态字段
import static java.lang.math.PI;    // 在当前命名空间导入某一静态字段
           

    静态导入的好处是可以简化书写,弊端是缺少类名作为前缀,不能让人一眼就看出静态方法或静态成员属于哪个类。

可变参数

格式:

    1、int getSum(int a, int...arr) {}

    2、只能出现在参数列表最后;

    3、 ...位于类型 与 变量名之间;

使用:

    在调用可变参数方法时,编译器隐含一个创建数组的动作,数组名为最后一个参数名,在方法体中以数组的形式访问参数:

int getSum(int a, int...arr) {
    int sum = a;
    for (int i : arr) {
        sum += i;
    }
    return sum;
}
           

泛型 generic

使用泛型的好处:

    1、通过提供额外的类型信息,加强了编译时期的类型检查,将可能在运行时发生的错误提前在编译时期检查出来;

    2、避免了类型强转的麻烦。

注意:

    1、泛型应用于集合、反射中。

    2、数组不能加上泛型信息:List<String>[] 是错误的写法。

    3、泛型检查只在编译阶段,编译过后会去除泛型信息,ArrayList<String>和ArrayList<Integer>是同一个类型。所以,可以利用反射机制绕过编译时期对泛型的检查:

// 定义一个实际类型参数为Integer的集合
List<Integer> intList = new ArrayList<>();

// 通过反射机制向集合加入String对象
intList.getClass().getMethod("add", Object.class).invoke(al, "abcd");
           

通配符 ?

    使用了通配符?的集合表示该集合存放的元素未知,?表示未知类型的类。

边界通配符

    上限<? extends T>:表示可以接收T类型或者T的子类型对象。

    上限<? extends T&E>:表示可以接收实现了T接口和E接口的类的子类对象。

    下限<? super T>:表示可以接收T类型或者T的父类型对象。

通配符表示不确定的类型,所以在创建集合时应该明确指定实际的类型参数而不要使用通配符:

List<?> intList =       // 使用了通配符
    new ArrayList<Integer>();  

intList.add(123);      // 报错,其实除了null外,不能往intList加入任何元素  
           

泛型类

class Person<T> {
    private T obj;
    
    public void set(T obj) {
        this.obj = obj;
    }
}
           

    当类中的操作的引用数据类型不确定的时候,以前用的Object来进行扩展的,现在可以用泛型来表示。这样可以避免强转的麻烦,而且将运行问题转移到的编译时期。

泛型方法

    当方法操作的引用数据类型不确定的时候,可以将泛型定义在方法上。注意,泛型方法标识必需连着返回类型: <T> void。

// 将数组元素添加到集合中
public <T> void copy(Collection<T> col, T[] arr) {
    for (T ele : arr) {
        col.add(ele);
    }
}
           

    另外,静态方法无法访问类上定义的泛型,所以,如果静态方法想使用泛型,必须要将泛型定义在该方法上。

泛型接口

    格式与泛型类差不多:interface Comparable<T>{}

枚举类 java.lang.Enum

  •     枚举类由关键字enum定义,枚举类与其他类很相似。由于所有的枚举类都继承了Enum,所以枚举类不能再继承其他类了。
  •     构造方法隐式地被指定为私有的。
  •     枚举常量必须在第一行初始化,常量之间用逗号分隔,如果还有其他成员或者方法,用分号表示枚举常量定义结束。
  •     已经实现了Serializable和Comparable<E>接口。

常用方法:

String name()       // 获得此枚举常量的名称
int ordinal()       // 获得枚举常量的序数,默认第一个枚举常量的序数为 0
Class<E> getDeclaringClass()    // 获取枚举类的字节码对象
static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) 
                                // 根据名字获得指定类型的枚举常量
           

一个复杂的枚举类:

enum TrafficLamp {
    RED(30) {
        public TrafficLamp nextLamp() {
            return GREEN;
        }
    },
    GREEN(30) {
        public TrafficLamp nextLamp() {
            return YELLOW;
        }
    },
    YELLOW(5) {
        public TrafficLamp nextLamp() {
            return RED;
        }
    };
    int time;
    TrafficLamp(int time) {this.time = time;}
    public abstract TrafficLamp nextLamp();
}
           

注解 Annotation

    注解是附加在程序上的元信息,这些信息在编译时期或者运行时期可以被使用和解析,通常用于对程序进行说明和配置。

3个内置注解:

    @Override:可注解方法,表示被注解的方法打算覆盖父类方法,如果该方法没有覆盖父类方法,编译器会报错。  ——SOURCE周期

    @Deprecated:可注解程序中的所有元素,不鼓励程序使用这样的元素。   ——SOURCE周期

    @SuppressWarnings:可注解所有元素,通知编译器忽略指定的、掉针对此元素的警告。 ——RUNTIME周期

4个元注解:——可对注解进行注解

    @Documented 指示某一类型的注释将通过 javadoc 和类似的默认工具进行文档化。

    @Inherited  指示注释类型被自动继承。

    @Retention  指示注释类型的保留策略;

        注解的3个保留策略:

        RetentionPolicy.SOURCE  标明注解只存在于源文件;

        RetentionPolicy.CLASS   标明注解会被保留在class文件中,但是运行时无法被获取;

        RetentionPolicy.RUNTIME 标明注解会被保留在class文件中,运行时可通过反射机制获取。

    @Target:指示注释类型所适用的程序元素的种类。

        程序元素的分类:

        ElementType.ANNOTATION_TYPE 注释类型声明 

        ElementType.CONSTRUCTOR 构造方法声明 

        ElementType.FIELD 字段声明(包括枚举常量) 

        ElementType.LOCAL_VARIABLE 局部变量声明 

        ElementType.METHOD 方法声明 

        ElementType.PACKAGE 包声明 

        ElementType.PARAMETER 参数声明 

        ElementType.TYPE 类、接口(包括注释类型)或枚举声明 

自定义注解:

@Retention(RetentionPolicy.RUNTIME) // 指示自定义注解的保留策略
@Target(ElementType.METHOD)         // 指示自定义注解所适用的元素种类
public @interface MyAnnotation {    // 使用关键字 @interface 自定义注解

    int[] intMethod();              // 方法名就是参数名,返回类型就是参数的类型
    String name() default "hello";  // 使用关键字 default 指定参数的初始值
}