1. 泛型
1.1 泛型实现机制?
从Java5开始引入,泛型作用域: 泛型方法,泛型类,泛型参数;
编译期有效,运行期无效,仅仅是编码时期的约束, JVM无法识别.
1.1 Java泛型使用类型擦除实现,优点:
- 运行时内存开销小,节约方法区内存开销;
- 例如: List
,List , 都会编译成List; 考虑兼容性,从Java5开始加入泛型,兼容4之前代码(通过强转实现).
1.2 类型擦除的缺点:
Java泛型基本类型无法作为泛型实参;由于泛型会擦除类型,只能使用包装类型,需要拆箱装箱,但安卓中避免了拆箱装箱的开耗,设计了SparseArray(内存优化);
泛型类型作为方法时候无法方法重载,因为编译完成都是一样的类型,参数被擦除了,方法签名相同
private void test(List<String> ls){}
private void test(List<Integer> li){}
泛型类型无法当做真实类型使用,由于不知道真实类型,所以无法通过new关键字实例化,不能创建类型参数的实例,但是反射可以.无法使用在数组,无法获取类型,无法使用instanceof
// new 无法编译
private <T> void test(List<T> lt) {
T t = new T(); // 无法new
T[] ts = new T[0];// 无法创建数组
Class c = T.class;// 无法获取类型
if (lt instanceof List<String>){} // 无法类型判断
if (lt instanceof List){} // √
List<T> tt = new ArrayList<T>();// 泛型传递,作用在其他泛型处
}
// 反射 通过编译
private <T> void test(List<T> lt, Class<T> ct) throws NoSuchMethodException, InvocationTargetException
, InstantiationException, IllegalAccessException {
// T t = ct.newInstance();// @Deprecated(since="9")
T t = ct.getDeclaredConstructor().newInstance();
lt.add(t);
}
静态方法无法引用类泛型参数;因为类泛型参数只有实例化时候知道,静态方法不需要类的实例,通过静态方法声明泛型参数即可解决;
public class Test<T> { private T t;// √ private static T tt;// × 无法使用在静态字段 private static T test(T t) {return t;}// × 静态方法无法引用类泛型参数 private static <T> T test(T t, T b) {return t;}// √ 静态方法可以声明泛型参数 }
1.3 泛型类型签名信息可以通过反射获取.
1.4 泛型通配符
无边界通配符
泛型操作符用于解决当泛型实参的类型不确定的情况,用?来替代类型实参,可以将其看成所有类型的父类。
// 泛型参数 无边界通配符 ?
private void test(List<?> list) {
list.add(1);
list.add(null);
list.get(0).hashCode();
}
上下边界通配符
上边界 extends
List 中的元素必定是 Integer 或它的子类
// 固定上边界 ? extends
private void test(List<? extends String> list) {
list.add("");
list.add(null);
list.get(0).toString();
}
下边界 super
List 中的元素必定是 Integer 或它的父类
// 固定下边界 ? super
private void test(List<? super Integer> list) {
list.add(1);
list.add(null);
}
2. 注解
2.1 元注解
元注解是描述注解的注解, JDK中提供的原始注解, 方便自定义注解, 注解标志: @interface
列举使用最频繁的两个注解:
@Target(ElementType.METHOD)
参数表示注解作用域: ElementType枚举类型常用的包括:
TYPE: 类,接口,注解,枚举
METHOD: 方法
FIELD: 属性
@Retention(RetentionPolicy.RUNTIME)
注解保留的阶段, RetentionPolicy枚举类型, 3个固定枚举:
SOURCE: 编译阶段, 这个注解会被移除, 不会包含在编译后的class文件中
CLASS: 注解会被保留在class文件中, 运行时会被移除
RUNTIME: 注解会被保留到运行时, 可以在运行时通过反射解析这个注解