反射与泛型
反射
Class类
class本身是一种数据类型(Type),class/interface的数据类型是Class,JVM为每个加载的class创建唯一的Class实例。
Class实例包含该class的所有信息,通过Class实例获取class信息的方法称为反射(Reflection)
获取一个class的Class实例:
1)Class cls = String.class;
2)Class cls = "str".getClass();
3)Class cls = Class.forName("java.lang.String");
注意 Class的==比较和instanceof的区别
Integer n = new Integer(123);
boolean b3 = n instanceof Integer; // true
boolean b4 = n instanceof Number; // true
// 精确判断时
boolean b1 = n.getClass() == Integer.class; // true
boolean b2 = n.getClass() == Number.class; // false
从Class实例获取class信息:
1)getName():获取完整类名
2)getSimpleName():获取简单的类名
3)getPackage():获取包名
从Class实例判断class类型:
1)isInterface():判断是否是接口类型
2)isEnum():判断是否是枚举类型
3)isArray():判断是否是数组类型
4)isPrimitive():判断是否是基本类型
创建class实例:
cls.newInstance()
JVM总是动态加载class,可以在运行期根据条件控制加载class
// commons logging优先使用Log4j
LogFactory factory;
if(isClassPresent("org.apache.logging.log4j.Logger")){
factory = createLog4j();
}else{
factory = createJdkLog();
}
boolean isClassPresent(String name){
try{
Class.forName(name);
return true;
}catch(Exception e){
return false;
}
}
访问字段
通过Class实例获取字段field信息:
1)getField(name)——获取某个public的field(包括父类)
2)getDeclaredField(name)——获取当前类的某个field(不包括父类)
3)getFields()——获取所有public的field(包括父类)
4)getDeclaredFields()——获取当前类的所有field(不包括父类)
Field对象包含一个field的所有信息
1)getName():字段名称
2)getType():字段定义的数据类型
3)getModifiers():字段修饰符
获取和设置field的值
1)get(Object obj)
2)set(Object, Object)
通过反射访问Field需要通过SecurityManager设置的规则
通过设置setAccessible(true)来访问非public字段
调用方法
通过Class实例方法获取Method信息:
1)getMethod(name, Class ...):获取某个public的method(包括父类)
2)getDeclaredMethod(name, Class ...):获取当前类的某个method(不包括父类)
3)getMethods():获取所有public的method(包括父类)
4)getDeclaredMethods():获取当前类的所有method(不包括父类)
Method对象包含一个method的所有信息
1)getName():获取方法名
2)getReturnType():获取返回值类型
3)getParameterTypes():获取方法参数类型
4)getModifiers():获取方法修饰符
调用Method:
Object invoke(Object obj, Object ...args)
通过设置setAccessible(true)来访问非public方法
反射调用Method也遵守多态的规则
调用构造方法
Class.newInstance()只能调用public无参数构造方法
String s = (String) String.class.newInstance(); // ^_^
Integer n = (Integer) Integer.class.newInstance(); // ERROR
通过Class实例获取Constructor信息:
1)getConstructor(Class...):获取某个public 的 Constructor
2)getDeclaredConstructor(Class...):获取某个Constructor
3)getConstructors():获取所有public的Constructor
4)getDeclareConstructors():获取所有的Constructor
通过Constructor实例可以创建一个实例对象
newInstance(Object ... parameters)
通过设置setAccessible(true)来访问非public构造方法
获取继承关系
获取父类的Class:
1)Class getSuperclass()
2)Object的父类是null
3)interface的父类是null
获取当前类直接实现的interface:
1)Class[] getInterfaces()
2)getInterfaces()获取的不包括间接实现的interface;如果想获取所有的,可以递归调用获取
3)没有interface的class返回空数组
4)interface返回继承的interface
判断一个向上转型是否成立:
boolean isAssignableFrom(Class)
注解 Annotation
使用注解
注解是放在Java源码的类、方法、字段、参数前的一种标签
注解本身对代码逻辑没有任何影响,如何使用注解由工具决定
编译器可以使用的注解
@Override:让编译器检查该方法是否正确实现了覆写
@Deprecated:告诉编译器该方法已经标记为“作废”
@SuppressWarnings:让编译器忽略警告
注解可以定义配置参数和默认值
配置参数由注解类型定义
配置参数可以包括:
所有基本类型
String
枚举类型
数组
配置参数必须是常量
定义注解
使用@interface定义注解,例如
@Target(ElementType.METHOD)
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}
使用元注解(meta annotation)定义注解
1)@Target
2)@Retention
3)@Repeatable
4)@Inherited
@Target
使用@Target定义Annotation可以被应用于源码的哪些位置:
类或接口:ElementType.TYPE
字段:ElementType.FIELD
方法:ElementType.METHOD
构造方法:ElementType.CONSTRUCTOR
方法参数:ElementType.PARAMETER
@Retention
使用@Retention定义Annotation的生命周期
仅编译器:RetentionRolicy.SOURCE
仅class文件:RetentionRolicy.CLASS
运行期:RetentionRolicy.RUNTIME
如果@Retention不存在,则该Annotation默认为CLASS
通常自定义的Annotation都是RUNTIME
@Repeatable