本文主要讲解反射机制的实现和反射机制在优秀框架中的使用
1.反射机制的实现:
在聊java反射之前,先看一段代码:
public class Student {
private String name;
public void println(){
System.out.println(name);
}
}
这是一个Student类,定义了一个私有name属性,一个打印方法,没有get和set方法,现在如果我想掉用Student的println方法,能否给name赋值?
为了解决这个问题,java设计了反射机制。
何为反射机制?
先看一段代码:
public static void main(String[] args) {
// TODO Auto-generated method stub
Student stu = new Student();
try {
Field f = stu.getClass().getDeclaredField("name");//获取Student的name属性
f.setAccessible(true);//允许反射使用该字段
f.set(stu, "张三");//设置值
stu.println();
} catch (NoSuchFieldException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
上面就是一段简单的java反射实现,通过field获取Student的name属性,然后过反射访问该字段,实现给该字段赋值。
执行步骤:
1.获取field对象
2.修改field对象属性为private时可修改
3.给对象的属性赋值
通过运行main方法,能够打印张三
在了解何为反射之后,我们将这段代码进行改造:
public class Reflex {
public static void setter(Object obj,String field,Object value){
try {
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, value);
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
Student stu=new Student();
Reflex.setter(stu, "name", "张三");
stu.println();
}
}
改造之后的代码,实现了面向对象的设计,解释一下传入的三个参数:
Object obj:需要反射的具体的对象(就是告诉我给哪个学生赋值)
String field:需要实现反射的属性(就是告诉我需要给学生的赋值的是哪个属性)
Object value:需要实现反射的属性值(就是告诉我需要给学生的赋什么值)
2.ORM主要实现(基于Mybatis)
谈完反射,来谈谈ORM:
所谓ORM(对象关系映射):就是把数据库的字段变成java实体类的属性
我们看一个配置:
<resultMap id="userAndJobs1" extends="BaseResultMap" type="TUser">
<collection property="jobs"
ofType="com.enjoylearning.mybatis.entity.TJobHistory">
<result column="comp_name" property="compName" jdbcType="VARCHAR" />
<result column="years" property="years" jdbcType="INTEGER" />
<result column="title" property="title" jdbcType="VARCHAR" />
</collection>
</resultMap>
这个配置就是将从数据库获取的字段与实体类的字段一一对应。
具体解释一下,这段配置,有哪些信息
- 类名
- 类中属性名
- 对应的数据库中数据的字段名
有了这三个信息,我就可以模拟实现了,来看Mybatis的实现
public static void copyBeanProperties(Class<?> type, Object sourceBean, Object destinationBean) {
Class<?> parent = type;
while (parent != null) {
final Field[] fields = parent.getDeclaredFields();
for(Field field : fields) {
try {
field.setAccessible(true);
field.set(destinationBean, field.get(sourceBean));
} catch (Exception e) {
// Nothing useful to do, will only fail on final fields, which will be ignored.
}
}
parent = parent.getSuperclass();
}
}
来看看怎么调用的
public static Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
final Class<?> type = target.getClass();
EnhancedResultObjectProxyImpl callback = new EnhancedResultObjectProxyImpl(type, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
Object enhanced = crateProxy(type, callback, constructorArgTypes, constructorArgs);
PropertyCopier.copyBeanProperties(type, target, enhanced);
return enhanced;
}
通过注入的方式实现从List<Object>到List<具体的class>,就是说,将Object通过复制,转换成我们需要的具体的实现类。
3.依赖注入的实现
何谓依赖注入?
创建被调用者 实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。
简单来说,就是实例化对象不由开发者new去实例化,而是交给Spring 容器去实例化(详细的依赖注入的优点和缺点这里不做详细解释)。
我们来看看Spring的依赖注入怎么利用反射的。
这个是Autowired的具体实现,主要就是通过反射的方式实现。
当然,在实现注入之前,实现了判断缓存、判空等。
总结:
java的反射机制是众多优秀框架的核心实现之一,优点是,在不需要实现get和set方法的的前提下,赋值或实例化对象,降低代码之间的耦合。