最近在学习java反射机制,读到了一篇很棒的博客,我的这篇文章是对原文的概括性笔记,总结了这部分知识的学习体系。
1. java.lang.Class
获取Class对象
- 知道类名时,编译期加载:
Class myObjectClass = MyObject.class
- 通过读取字符串,运行时加载:
Class class = Class.forName("com.jenkov.myapp.MyObject");
获取类名
String getname()
:完全包名String getSimpleName()
:仅类名
获取修饰符
int getModifiers()
:获取修饰符的int标记
然后使用is方法判断:
Modifier.isAbstract(int modifiers)
Modifier.isFinal(int modifiers)
Modifier.isInterface(int modifiers)
Modifier.isNative(int modifiers)
Modifier.isPrivate(int modifiers)
Modifier.isProtected(int modifiers)
Modifier.isPublic(int modifiers)
Modifier.isStatic(int modifiers)
Modifier.isStrict(int modifiers)
Modifier.isSynchronized(int modifiers)
Modifier.isTransient(int modifiers)
Modifier.isVolatile(int modifiers)
包信息
Package getPackage()
:获取包对象java.lang.Package
父类信息
Class getSuperclass()
:得到父类的对象Class
实现的接口
Class[] getInterfaces()
:只返回此类显式实现的接口,不包括父类的
构造器
Constructor[] getConstructors()
getConstructor(Class[])
:根据参数类,获得指定的构造器,NoSuchMethodException
方法
Method[] getMethods()
Method getMethod(String, Class[])
:根据方法名和参数类(无参时传null),获得指定方法对象,NoSuchMethodException
字段
获取public字段(包括父类的):
Field[] getFields()
Filed getField(String)
:根据字段名,获取指定字段,NoSuchFieldException
还可以获取private/protected/package字段(不包括父类的):
Field[] getDeclaredFields()
Field getDeclaredField(String name)
类注解Annotation
Annotation[] getAnnotations()
A getAnnotation(Class<A> annotationClass)
:根据注解类,获取指定注解
2. java.lang.reflect.Constructor
得到构造参数
Class[] getParameterTypes()
用构造器对象实例化对象
MyObject myObject = (MyObject) constructor.newInstance("constructor-arg1");
3. java.lang.reflect.Field
字段名
String getName()
字段类型
Class getType()
Getting 和 Setting字段的值
Object get(Object obj)
:获取类实例的字段的值set(Object obj, Object value)
:设置类实例的字段的值
静态字段可以传入null实例。
访问private/protected/package字段
访问私有字段的值前需要取消访问检查:
setAccessible(true)
4. java.lang.reflect.Method
方法参数和返回类型
Class[] getParameterTypes()
Class getReturnType()
调用类实例的方法
Object invoke(Object obj, Object... args)
:静态方法时,obj可为null
判断方法是否是getter或setter方法
public static boolean isGetter(Method method){
if(!method.getName().startsWith("get")) return false;
if(method.getParameterTypes().length != 0) return false;
if(void.class.equals(method.getReturnType()) return false;
return true;
}
public static boolean isSetter(Method method){
if(!method.getName().startsWith("set")) return false;
if(method.getParameterTypes().length != 1) return false;
return true;
}
5. 反射中的Annotation
类的注解
- Annotation[] getAnnotations()
- A getAnnotation(Class<A> annotationClass)
:根据注解类,获取指定注解
获取方法的注解
T Method.getAnnotation(Class<T>)
Annotation[] Method.getDeclaredAnnotations()
参数的注解
Annotation[][] Method.getParameterAnnotations()
字段注解
Annotation[] Field.getDeclaredAnnotations()
T Field.getAnnotation(Class<T>)
6. 反射中的泛型
方法的泛型返回值
Type method.getGenericReturnType()
Type[] typeArguments = type.getActualTypeArguments();
:获取泛型中的每个类型
public class MyClass {
protected List<String> stringList = ...;
public List<String> getStringList(){
return this.stringList;
}
}
Method method = MyClass.class.getMethod("getStringList", null);
Type returnType = method.getGenericReturnType();
if(returnType instanceof ParameterizedType){
ParameterizedType type = (ParameterizedType) returnType;
Type[] typeArguments = type.getActualTypeArguments();
for(Type typeArgument : typeArguments){
Class typeArgClass = (Class) typeArgument;
System.out.println("typeArgClass = " + typeArgClass);
}
}
方法的泛型参数
Type[] method.getGenericParameterTypes()
泛型字段
Type field.getGenericType()
7. java.lang.reflect.Array
反射获取数组
int[] intArray = (int[]) Array.newInstance(int.class, 3);
获取数组类
非反射方式:
Class stringArrayClass = String[].class;
反射:
Class intArray = Class.forName("[I");
Class stringArrayClass = Class.forName("[Ljava.lang.String;");
"[I"
:表示基本数据类型数组,I,S,C,F,D,J(long),B(byte),Z(boolean)"[L类名;"
:表示对象数组
数组类的组件类型
Class arrayClass.getComponentType()
基本数据类型的数组,组件类型为基本数据类型的类,如int
- 对象数组,组件类型为对象的类,如java.lang.String
8. 动态代理
java.lang.reflect.Proxy
用于运行时动态实现接口。
创建
Object newProxyInstance(ClassLoader, Class<?>[],InvocationHandler)
InvocationHandler handler = new MyInvocationHandler();
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class[] { MyInterface.class },
handler);
InvocationHandler
public class MyInvocationHandler implements InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//do something "dynamic"
}
}
proxy
:用此Handler创建的代理,通常都用不到。method
:代理调用的接口的方法。args
:代理调用的接口的方法的参数,基本数据类型会变成包装类。
类加载器
创建一个新的标准Java类加载器是,必须提供它的双亲类加载器。这和类加载的顺序有关:
- 检查这个类是否已经加载过了。
- 如果没有加载过,就让加载器的双亲加载器来加载这个类。
- 如果双亲加载器不能加载这个类,就由自己来加载。
而且一个加载器只会加载一个类一次。
应用场景
- 数据库连接,事务处理
- 单元测试的动态模拟对象
- Adaptation of DI Container to Custom Factory Interfaces
- AOP-like Method Interception
示例
public class Test {
public static void main(String[] args) {
HelloImpl hello = new HelloImpl();
MyInvocationHandler handler = new MyInvocationHandler(hello);
// 构建代码实例
Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(),
HelloImpl.class.getInterfaces(), handler);
// 调用代理方法
proxyHello.sayHello();
}
}
interface Hello {
void sayHello();
}
class HelloImpl implements Hello {
@Override
public void sayHello() {
System.out.println("Hello World");
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Invoking sayHello");
return method.invoke(target, args);
}
}
上一篇:RadioGroup中显示radiobutton之外的其他组件
下一篇:Java中类的实例化过程变量的初始化顺序,以及常见笔试程序阅读题分析