Java反射机制
目录
反射
1. 反射的定义
- 反射即反向探知,有点类似考古学家根据发掘的物品来探知以前的事情
- 在Java程序运行状态中:
- 对于给定的一个类(Class)对象,可以获得这个类(Class)对象的所有属性和方法;
- 对于给定的一个对象( new ClassName < ? extends Object> ),都能够调用它的任意一个属性和方法
这种动态获取类的内容以及动态调用对象的方法和获取属性的机制,就叫做JAVA的反射机制。
2. 反射的优缺点
优点:
- 增加程序的灵活性,避免固有逻辑写死到程序中
- 代码相对简洁,可以提高程序的复用性
public interface Ball {
public void playBall();
}
class BasketBall implements Ball {
@Override
public void playBall() {
System.out.println("一起打篮球。。。。");
}
}
class FootBall implements Ball {
@Override
public void playBall() {
System.out.println("一起踢足球。。。。");
}
}
class BallMain {
public static void main(String[] args) throws Exception {
System.out.println(getNewInstanceByKey("BasketBall"));
System.out.println(getNewInstanceByKey("FootBall"));
}
public static Ball getInstanceByKey (String key) {
if ("BasketBall".equals(key)) {
return new BasketBall();
} else if ("FootBall".equals(key)) {
return new FootBall();
}
// 如果要增加排球、羽毛球、、、很多球,下面还要继续判断,创建实例吗?
return null;
}
public static Ball getNewInstanceByKey (String key) throws Exception {
String basePackage = "com.elian.reflex";
Ball ball = null;
Class<?> clazz = Class.forName(basePackage + "." + key);
ball = (Ball) clazz.newInstance();
return ball;
}
}
缺点:
- 相比于直接调用,反射有比较大的性能消耗
- 内部暴露和安全隐患
反射到底慢在哪里?
- 调用了native方法
- 每次new Instance都会做安全检查 比较耗时
3. 深入class内部

3.1 基本操作
1) 获取类对象的4种方式
public class ReflexTest {
public static void main(String[] args) throws Exception {
Class<Person> p1 = Person.class;
Class<?> p2 = Class.forName("com.elian.reflex.Person");
Class<? extends Person> p3 = new Person().getClass();
Class<?> p4 = ReflexTest.class.getClassLoader().loadClass("com.elian.reflex.Person");
}
}
2) 基本操作
// 获取类的相关结构
int modifiers = p1.getModifiers(); // 获取类修饰符
p1.getPackage() // 获取包名
p1.getName() // 获取全路径名
p1.getSuperclass() // 获取父类
p1.getClassLoader() // 获取类加载器
p1.getSimpleName() // 获取类名
p1.getInterfaces() // 获取类型所有实现的接口
p1.getAnnotations() // 获取所有注解
3) 字段的操作
public static void main(String[] args) throws Exception {
// 获取Person对象
Class<Person> clazz = Person.class;
Person person = clazz.newInstance();
Field[] clazzFields = clazz.getFields(); // 只能获取当前类及父类public的字段
Field[] declaredFields = clazz.getDeclaredFields(); // 可以获取当前类中所有的字段
for (Field field :
clazzFields) {
System.out.println(field.getModifiers() + " " + field.getName());
}
System.out.println( "========" );
for (Field field :
declaredFields) {
System.out.println(field.getModifiers() + " " + field.getName());
}
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true); // 设置权限,private的字段可以设置值
nameField.set(person, "Elian");
// 对静态字段进行操作
Field addressField = clazz.getDeclaredField("address");
addressField.set(null, "北京通州");
}
4) 对方法的操作
public static void main(String[] args) throws Exception {
Person person = new Person();
Class<Person> clazz = Person.class;
Method[] methods = clazz.getMethods(); // 获取当前类及父类中所有的public修饰的方法
Method[] declaredMethods = clazz.getDeclaredMethods(); // 获取本类中所有方法
for (Method method :
methods) {
System.out.println( method.getModifiers() + " " + method.getName() );
}
System.out.println( "================" );
for (Method method :
declaredMethods) {
System.out.println( method.getModifiers() + " " + method.getName() );
}
Method jump = clazz.getDeclaredMethod("jump");
jump.invoke(person);
Field address = clazz.getDeclaredField("address");
address.setAccessible(true);
address.set(null, "北京通州");
Method getAddress = clazz.getDeclaredMethod("getAddress");
getAddress.setAccessible(true);
System.out.println(getAddress.invoke(null));
}
5) 对构造器的 操作
public static void main(String[] args) throws Exception {
Class<Person> clazz = Person.class;
Constructor<?>[] constructors = clazz.getConstructors();
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor constructor :
constructors) {
System.out.println(constructor.getModifiers() + " " + constructor.getName());
}
System.out.println("===============");
for (Constructor constructor :
declaredConstructors) {
System.out.println(constructor.getModifiers() + " " + constructor.getName());
}
// 创建实例两种方式
// 1. 直接通过newInstance创建对象
Person person1 = clazz.newInstance();
// 2. 获取对应的Constructor对象获取实例
Constructor<Person> declaredConstructor = clazz.getDeclaredConstructor(String.class);
declaredConstructor.setAccessible(true);
Person person2 = declaredConstructor.newInstance("Elian");
System.out.println(person2.getName());
}
漏洞:对于单例的对象来说,能够调用私有的构造器创建新的对象,比较危险,所以应在代码中控制对象的创建。
public class SinglePerson {
private static final SinglePerson instance = new SinglePerson();
public static SinglePerson getInstance() {
return instance;
}
private SinglePerson() {
if (instance != null)
throw new RuntimeException( "The instance of SinglePerson has been created and cannot be created it again" );
}
public static void main(String[] args) {
SinglePerson s1 = SinglePerson.getInstance();
SinglePerson s2 = SinglePerson.getInstance();
System.out.println(s1);
System.out.println(s2);
}
}
3.2 反射的使用场景
- jdbc的封装
- Spring中的IoC
- jdbcTemplate
- MyBatis
4. SpringIoC中反射的应用
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
// 创建Ioc容器对象 BeanFactory 同时解析配置文件
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
// 单例对象的实例化
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
}
}
}
'==========================='
public abstract class BeanUtils {
//....
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
return ctor.newInstance(args);
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}
// ....
}

浙公网安备 33010602011771号