1. 自定义注解添加属性:
package com.itcast.d34;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// RetentionPolicy.RUNTIME对应内存中的字节码,RetentionPolicy.CLASS对应class文件,
// RetentionPolicy.SOURCE对应源文件
@Retention(RetentionPolicy.RUNTIME)
// 指定注解的位置
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyAnnotation {
String value();// 特殊的属性名,可省略的变量名
int[] arrayAttr() default {1,2,3}; // 可设置默认值
/* 可以是一个注解类型 */
/* 可以是枚举类型 */
}
使用:
package com.itcast.d34;
@MyAnnotation("cc")
public class AnnotationTest {
public static void main(String[] args) {
if (AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation myAnnotation = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(myAnnotation.value());
};
}
}
2. 泛型
泛型的深入理解和高级应用:泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一致。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,使用反射得到集合,再调用其add方法即可:
ArrayList<Integer> al = new ArrayList<Integer>();
al.getClass().getMethod("add", Object.class).invoke(al, "asd");
System.out.println(al.get(0));
泛型通配符?的使用:
// 打印任意类型的泛型集合
public static void printCollection(Collection<?> collection){
System.out.println(collection.size());
for(Object obj : collection){
System.out.println(obj);
}
}
通配符?的扩展:
限定通配符的上边界:
正确:Vector<? extends Number> x = new Vector<Integer>();
错误:Vector<? extends Number> x = new Vector<String>();
限定通配符的下边界:
正确:Vector<? super Integer> x = new Vector<Number>();
错误:Vector<? super Integer > x = new Vector<Byter>();
限定通配符包括自己。
遍历一个泛型集合:
HashMap<String,Integer> maps = new HashMap<String, Integer>();
maps.put("zxx", 28);
maps.put("lhm", 35);
maps.put("flx", 33);
Set<Map.Entry<String,Integer>> entrySet = maps.entrySet();
for(Map.Entry<String, Integer> entry : entrySet){
System.out.println(entry.getKey() + ":" + entry.getValue());
}
自定义泛型方法及其应用:
private static <T> T[] swap(T[] a,int i,int j){
T tmp = a[i];
a[i] = a[j];
a[j] = tmp;
return a;
}
只用引用类型才能作为自定义泛型方法的实际参数。swap(new int[]{1,3,5,4,5},3,4)是不对的
如果类的实例对象中的多处都要使用同一个泛型参数,即这些地方引用的泛型类型要保持同一个实际类型时,这时候就要采用泛型类型飞方式进行定义,也就是类级别的泛型,语法格式:
public class BaseDao<T>{
private T filed;
public void save(T obj){}
public T findById(int id);
}
通过反射获得泛型的实际类型参数:
Method applyMethod = GenericTest.class.getMethod("applyVector", Vector.class);
Type[] types = applyMethod.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType)types[0];
System.out.println(pType.getRawType());
// 获得实际参数类型
System.out.println(pType.getActualTypeArguments()[0]);
public static void applyVector(Vector<Date> v1){}
编译器编译带类型说明的集合时会去掉“类型”信息,所以只能使用方式的反射。