一.关于反射
(1)使用场景介绍
平常我们写代码时,都是已知类名,类的属性,构造方法,其他方法等信息,然后根据类名new对象,这个过程称为正向操作(例如:有一个管理员类,有账号和密码属性,还有一个set,get,eat方法,直接通过类名new对象,再通过对象名调用类的变量和方法。但在其他的一些场景如框架,servlet,xml文件中,可能并不知道该类有什么属性和方法等,可能只知道类的名字等,无法直接new对象为解决这个问题就引入了反射机制。
(1)如:servlet中的json格式转换将对象转为{属性名,值}的字符串
new ObjectMapper().writeValueAsString(result) result就是传入的对象,json处理时并不知道这个传入的对象是什么,所以就要反过来根据对象名拿到该对象类的变量和属性,才能获得该对象的属性名和值。
(2) 如:在mybatis框架中要在mybatis的xml文件中配置类的名称从而找到类,将查询的结果自动通过类的名称映射到类的对象中,这就是使用了反射机制。
<insert id="insertAdminById" parameterType="Admin"> insert into admin(account,password,gender) values (#{account},#{password}, #{gender}) </insert>
(2)什么是java反射
(3)在java中为什么要使用反射
就在上述场景中介绍一样,在java中平常不可避免的要用到反射,平常写业务代码(就是自己创建类new 对象,自己清楚类的属性和方法)用不到,但是一些其他场景不可避免地可能只知道类名,对象名等,要对该类(对象)的属性,方法操作就需要•动态获取类(对象)的信息,使其只要知道任意类名或者对象名就能获得该类或者该对象的属性和方法并对其进行操作。
(4)反射机制图解
(5)java反射相关api
Java反射相关的类主要包括• Class 类型 : 可以动态将任意类转化为Class对象,然后根据Class对象获得类的对象)。• Constructor 构造方法 :可以通过该构造方法获得类的对象(前提获得Class对象)。• Method 方法 : 获得类的方法(前提获得Class对象)。• Field 属性: 获得类的属性(前提获得Class对象)。• 除了Class外,其他类都位于java.lang.reflect包中● 可见,反射API将类的类型、方法、属性都封装成了类,其中最重要的类是 Class,可以说,反射的使用都是从Class开始。
以user(管理员类为例)
package com.ffyc.javareflection.model;
public class user {
String account;
String password;
public user() {
System.out.println("无参构造方法");
}
public void eat()
{
System.out.println("人吃饭");
}
public user(String account, String password) {
System.out.println("有参构造方法");
this.account = account;
this.password = password;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "user{" +
"account='" + account + '\'' +
", password='" + password + '\'' +
'}';
}
}
1.获得Class对象
已知类如何获得类中的属性和方法,通过CLass获得
//方法一:已知类名获得Class对象
Class aClass=Class.forName("com.ffyc.javareflection.model.user");
System.out.println(aClass);
//方法二:已知类获得Class对象
Class bclass=user.class;
System.out.println(bclass);
//方法三:已知对象名获得Class对象
user user=new user();
Class cclass=user.getClass();
System.out.println(cclass);
结果如图Class对象一样
获得类的对象有四种方法: 1.new 对象 2.对象序列化 3.反射机制 4.对象克隆
2.通过Class对象获得类的对象
//第一种:通过Class对象中的new获得类的对象
Class aaclass=Class.forName("com.ffyc.javareflection.model.user");
Object object=aaclass.newInstance();
System.out.println(object);
3.通过构造方法获得类的对象
//第二种:通过类中的构造方法来获得类的对象(公共的构造方法)
//无参构造
Constructor constructor=aaclass.getConstructor();
Object object1= constructor.newInstance();
System.out.println(object1);
//有参构造
Constructor constructor1=aaclass.getConstructor(String.class,String.class);
Object object2=constructor1.newInstance("张三","111");
System.out.println(object2);
//获得所有公共的构造方法
Constructor []constructors=aaclass.getConstructors();
System.out.println(constructors.length);
//获得任意的构造方法,包含私有的构造方法,一般不建议操作,因为打破了封装性
Constructor [] constructor3= aaclass.getDeclaredConstructors();
System.out.println(constructor3.length);
4. 通过Method 方法获得类的方法(Method getMethod(String name, Class... parameterTypes) : 通过指定方法名,参数类型,返回一个Method实例)
Method 作用:
● Method类将类中的方法进行封装,可以动态获得方法的信息,例如● getName:获得方法名字● getParameterTypes:获得方法参数类型● 除了动态获得方法信息外,Method还能动态调用某一个对象的具体方法● invoke(Object obj, Object... args) :使用obj调用该方法,参数为args
Class cclass=Class.forName("com.ffyc.javareflection.model.user");
Object object=cclass.newInstance();
Method method=cclass.getMethod("eat");
String value= (String) method.invoke(object);
System.out.println(value);
5.Field 属性获得类的属性
Field类将类的属性进行封装,可以获得属性的基本信息、属性的值,也可以对属性进行赋值.● getName:返回属性的名字● set:设置属性值
//通过私有属性get和set放法对类中私有属性进行赋值取值操作
HashMap<String,String> hashMap=new HashMap<>();
hashMap.put("account","admin");
hashMap.put("password","111");
Field [] fields=cclass.getDeclaredFields();//获得类中所有的成员变量包括私有的
for (Field field:fields) {
//根据属性名获得set放法名称
String setmethod="set"+field.getName().substring(0,1).toUpperCase()+field.getName().substring(1);
//通过class对象获得set方法对象
Method method= cclass.getMethod(setmethod,field.getType());
//调用set方法
method.invoke(object,hashMap.get(field.getName()));
}
System.out.println(object); //通过私有属性get和set放法对类中私有属性进行赋值取值操作
HashMap<String,String> hashMap=new HashMap<>();
hashMap.put("account","admin");
hashMap.put("password","111");
Field [] fields=cclass.getDeclaredFields();//获得类中所有的成员变量包括私有的
for (Field field:fields) {
//根据属性名获得set放法名称
String setmethod="set"+field.getName().substring(0,1).toUpperCase()+field.getName().substring(1);
//通过class对象获得set方法对象
Method method= cclass.getMethod(setmethod,field.getType());
//调用set方法
method.invoke(object,hashMap.get(field.getName()));
}
System.out.println(object);
二.反射的实例转json格式
package com.ffyc.javareflection.model;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Json {
public static String json(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
String json="{";
Class aclass=object.getClass();//先将传过来的对象转为class对象
Field[] fields=aclass.getDeclaredFields();//然后获得该对象的所有属性
for (Field field:fields) {
String getfield="get"+field.getName().substring(0,1).toUpperCase()+field.getName().substring(1);//拿到get方法名
//获得方法对象,getMethod(方法名,返回值类型)
Method method= aclass.getMethod(getfield);
//调用方法
String value=(String)method.invoke(object);
//把属性名和值拼接成键值
json+=json+field.getName()+":"+value+",";
json=json.substring(0,json.length()-1);//去掉多余逗号
json+="}";
}
return json;
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
car car = new car();
car.setName("红旗");
car.setColor("红色");
user user = new user();
user.setAccount("admin");
user.setPassword("111");
System.out.println(Json.json(car));
System.out.println(Json.json(user));
}
}
三.反射的好处和坏处
优点:● 1. 增加程序的灵活性,可以在运行的过程中动态对类进行修改和操作● 2. 提高代码的复用率,比如动态代理● 3. 可以在运行时轻松获取任意一个类的方法、属性,并且还能通过反射进行动态调用
缺点:
● 1. 反射会涉及到动态类型的解析,导致性能要比非反射调用更低● 2. 使用反射技术通常要在一个没有安全限制的程序运行 .● 3. 反射可以绕过一些限制访问的属性或者方法,可能会导致破坏代码本身的抽象 性