一. 什么是反射机制?
什么是反射?以镜子为例,一束光照射到镜子上,会有反射行为发生,所以反射是对已经存在事物的一种响应。在Java中就是在运行状态下,可以动态的获取某个类或对象的方法和属性。
二. 反射可以做什么?
- 动态的构造类
- 动态的调用对象的方法,包括判断对象的属性,例如是不是数组等
- 动态代理
三. 如何实例化Class对象?
有三种实例化Class对象的方式:
- Class<?> clazz = Class.forName("包路径+类名")。以下为Class类源码,它有两个构造函数,第一个是常用的。
@CallerSensitive
public static Class<?> forName(String paramString)
throws ClassNotFoundException
{
Class localClass = Reflection.getCallerClass();
return forName0(paramString, true, ClassLoader.getClassLoader(localClass), localClass);
}
@CallerSensitive
public static Class<?> forName(String paramString, boolean paramBoolean, ClassLoader paramClassLoader)
throws ClassNotFoundException
{
Class localClass = null;
SecurityManager localSecurityManager = System.getSecurityManager();
if (localSecurityManager != null)
{
localClass = Reflection.getCallerClass();
if (VM.isSystemDomainLoader(paramClassLoader))
{
ClassLoader localClassLoader = ClassLoader.getClassLoader(localClass);
if (!VM.isSystemDomainLoader(localClassLoader)) {
localSecurityManager.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
return forName0(paramString, paramBoolean, paramClassLoader, localClass);
}
- Class<?> clazz = 对象名.getClass();
- Class<?> clazz = 类名.class;
四. Class类主要包含哪些方法?
- getName():返回包名+类名
- getFields()/getDeclaredFields():返回public/全部属性
- getMethods()/getDeclaredMethods() :返回public/全部方法
- getConstructors()/getConstructor(Class<?>... paramVarArgs) :返回public/特种参数类型的构造方法
- getSuperclass():返回父类
- isArray():是否数组
- isInterface():是否接口
- isPrimitive():是否原始类型(boolean、char、byte、short、int、long、float、double)
- newInstance():返回一个对象,该对象由不带参数的构造方法创建。注意于Class.forName("")的区别,Class.forName("")返回的是类。
...
五. 怎么用?
- 通过反射修改属性
直接看例子:
public class TestReflectForField {
//私有属性
private String testField = null;
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.tddy.reflect.TestReflect");
Object object = clazz.newInstance();
//getDeclaredField获取指定属性,如果不清楚它有什么属性,可以用getDeclaredFields()获取所有属性
Field field = clazz.getDeclaredField("testField");
field.setAccessible(true);
field.set(object, "change field!");
System.out.println(field.get(object));
}
public String getTestField() {
return testField;
}
public void setTestField(String testField) {
this.testField = testField;
}
}
- 通过反射调用方法
直接看例子:
public class TestReflectMethod {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.tddy.reflect.TestReflectMethod");
Object object = clazz.newInstance();
//获取"method1()"方法,如果不知道有什么方法,可以通过getDeclaredMethods()获取所有方法
Method method = clazz.getMethod("method1");
//执行
method.invoke(object);
/*
* 跟上面相同,只需要注意参数
method = clazz.getMethod("method2", String.class);
method.invoke(clazz.newInstance(), "TestReflectMethod");
*/
}
public void method1() {
System.out.println("called method1");
}
public void method2(String str) {
System.out.println("called method2 and the str = " + str);
}
}
六. java.lang.reflect包轻解读
在JDK中,反射所用的类和接口主要有Field, Method, Constructor, Array, Modifier,Proxy, InvocationHandler等,除核心类Class位于java.lang包中,其他常用类或接口都位于java.lang.reflect包(jre/rt.jar),有兴趣可以去阅读一下源码,这里只是简单的解释一下这些类或接口分别能干什么。
- Field类:getFields()/getDeclaredFields()返回Field数组。
- Method类:getMethods()/getDeclaredMethods()返回Method数组
- Constructor类:getConstructors()/getConstructor(Class<?>... paramVarArgs)返回Constructor<?>[]数组
- Array类:数组的反射涉及到同维数组和不同维数组。同类型元素的同维数组,他们的Class相同,他们有共同的父类Object。原始类型数组(需要转换成对应的包装类)不能直接转换为Object类型数组。
- Modifier类:类、变量或方法的修饰符,修饰符集被表示为整数。以下为Modifier类源码:
public static final int PUBLIC = 1;
public static final int PRIVATE = 2;
public static final int PROTECTED = 4;
public static final int STATIC = 8;
public static final int FINAL = 16;
public static final int SYNCHRONIZED = 32;
public static final int VOLATILE = 64;
public static final int TRANSIENT = 128;
public static final int NATIVE = 256;
public static final int INTERFACE = 512;
public static final int ABSTRACT = 1024;
public static final int STRICT = 2048;
static final int BRIDGE = 64;
static final int VARARGS = 128;
static final int SYNTHETIC = 4096;
static final int ANNOTATION = 8192;
static final int ENUM = 16384;
static final int MANDATED = 32768;
private static final int CLASS_MODIFIERS = 3103;
private static final int INTERFACE_MODIFIERS = 3087;
private static final int CONSTRUCTOR_MODIFIERS = 7;
private static final int METHOD_MODIFIERS = 3391;
private static final int FIELD_MODIFIERS = 223;
private static final int PARAMETER_MODIFIERS = 16;
static final int ACCESS_MODIFIERS = 7;
以下为动态代理:
- Proxy类和InvocationHandler接口
关于动态代理,实际工作中可能用到的比较少,但是如果你使用框架,例如Spring, SpringMVC等,它的一个主要思想是AOP和IOC,其中AOP就是Java的动态代理机制。
分享2篇文章供大家参考:
七. Java类加载器
Java中默认的类加载器是AppClassLoader,它可以加载classpath下指定的类,在读取配置文件时经常使用。