反射介绍
反射,一种计算机处理方式。是程序可以访问、检测和修改它本身状态或行为的一种能力。
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
Java反射常用API
在java.lang.reflect包下有三个类
优点:
1、反射提高了程序的灵活性和扩展性。
2、降低耦合性,提高自适应能力。
3、它允许程序创建和控制任何类的对象,无需提前硬编码目标类。
缺点:
1、性能问题:使用反射基本上是一种解析操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
2、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。
Class介绍
Java中的Class它可以代表任意的类或接口类型.
如何获取一个Class?
有三种方式:
- 如果持有一个对象,可以直接通过从Object类中继承的getClass方法获取
// 1.如果你得到一个类的对象
@Test
public void test1() {
User user = new User();
Class class1 = user.getClass(); // getClass方法是从Object类中继承
System.out.println(class1);
}
- 可以直接通过类包(接口)直接调用其属性.class获取
// 2.可以直接通过类名获取
@Test
public void test2() {
Class clazz = User.class;
System.out.println(clazz);
}
- 可以通过Class类中提供的forName方法获取
// 3.推荐使用的方案
@Test
public void test3() throws ClassNotFoundException {
Class clazz=Class.forName(“com.it.reflect.User”);
System.out.println(clazz);
}
为什么要获取Class对象?
对于我们学习反射,我们在操作中一般会获取类的成员 Constructor Field Method,但是要想获取这些对象,必须首先得到其Class,通过Class来获得其它对象
Constructor介绍
Constructor它描述的单个构造器,我们得到它就可以实例化对象.
问题:如何获取Constructor?
getConstructor它获取的是类的public构造
getConstructors它获取的是类的所有的public构造
以上两个方法不仅可以获取public,也可以获取其它权限的。
我们得到构造器,就可以实例化对象
如果不是public,那么我们需要通过AccessibleObject中的
来取消检查
Field介绍
Java.lang.reflect.Field它描述的属性对象。
关于Filed我们了解以下两个方面
- 如何获取一个Field
-
Field的操作
a. 对Field进行赋值
b. 对Field进行取值
Method介绍(重点)
Java.lang.reflect.Method它描述的是类或接口中的方法。
如何获取一个Method对象
Method如何使用?
Method的invoke使用时注意事项?
- 如果方法是static,我们怎样调用?
如果方法是静态的,在通过invoke调用时不需要传递对象
// 调用static方法
@Test
public void test4() throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Class clazz = User.class;
// 得到sum方法
Method method = clazz.getMethod("sum"); // 注意sum是一个静态方法
method.invoke(null);
}
- 如果方法的参数是一个数组类型,怎样处理?
// 调用参数是数组类型的方法
@Test
public void test5() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class clazz = User.class;
// 得到sum方法
Method method = clazz.getMethod("sum",Integer[].class);
//执行sum方法
Integer[] args={1,2,3,4};
//解决方案一:将args直接强制转换成Object在传递
//method.invoke(null, ((Object)args));
//解决方案二:在args这个数组外层在包装一层数组
Object[] objs={args};
method.invoke(null, objs);
}
反射案例
并提供get/set方法
public class Person {
private String username;
private String sex;
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [username=" + username + ", sex=" + sex + ", age=" + age + "]";
}
使用java中的反射技术将类中的属性与map中的key相同名称的,使用反射技术将key对应的value值赋值给属性.
采用两种方式完成操作
直接操作属性 Field来完成操作
// 通过属性来完成操作
@Test
public void test1() throws Exception {
Map<String, Object> map = new HashMap<String, Object>();
map.put("username", "tom");
map.put("age", 20);
map.put("sex", "男");
map.put("address", "北京");
// 1.得到Person类的Class
Class clazz = Class.forName("com.it.reflect.Person");
Object obj = clazz.newInstance();
// 2.得到Person类的所有属性
Field[] fds = clazz.getDeclaredFields();
// 3.得到map中所有的key
Set<String> keys = map.keySet();
for (Field f : fds) {
String field_name = (f.getName()); // 得到属性名称
if (keys.contains(field_name)) { // map的key中包含了Person类的属性
// 4.将key对应的value赋值给属性
f.setAccessible(true);
f.set(obj, map.get(field_name));
}
}
System.out.println(obj);
}
通过属性对应的setXxx方法来完成操作
// 通过属性对应setXxx方法来完成操作
@Test
public void test2() throws Exception{
Map<String, Object> map = new HashMap<String, Object>();
map.put("username", "tom");
map.put("age", 20);
map.put("sex", "男");
map.put("address", "北京");
// 1.得到Person类的Class
Class clazz = Class.forName("com.it.reflect.Person");
Object obj = clazz.newInstance();
//2.得到Person类中的方法
Method[] methods = clazz.getDeclaredMethods();
//3.遍历map
for(String key:map.keySet()){
//将所有的key前面添加上set,与方法的名称不区分大小写来对比。
String methodName="set"+key; //操作的方法
for(Method method:methods){
String mname=method.getName();
if(methodName.equalsIgnoreCase(mname)){
method.invoke(obj, map.get(key));
}
}
}
System.out.println(obj);
}