java反射
在一些组件或者框架开发中声明,他们本身不知道要处理哪些类,
例如Jackson组件,
在web.xml中配置了哪些servlet类,Tomcat就要创建哪些类对象
在mybatis中,给了什么类型,mybatis就可以将结果封装映射对给定的类的对象中
以前已知类名的使用方式,可以看作是正向使用类
框架只需要写一套程序,就可以处理我们给他的任意类
只需要知道类的名字,通过名字动态获取类中的信息,被称为反向使用
反射
在运行状态中,对于任意一个类,都能够知道这个类,都能知道这个类的所有属性和方法
对于任意一个对象,都能调用它的任意一个方法
如何实现反射机制
java.lang.Class
Claas类的对象,表示当前正在运行中的类和接口
一旦class文件被加载到内存堆,就会为其创建一个class对象
Class类是Java反射机制的基础,通过Class类,可以得到一个类的基本信息
获得Class的方法
要使用Class类的方法,必须先哦的该类的Class类的实例,获得Class类实例的常用方法有如下三种
1.Object类中存在getClass方法,可以通过对象获得Class实例
2.使用类名.class的方式,适用于通过类名获得Class实例的情况
3.Class类的静态方法 forName(Strin name)
//使用反射机制时,只知道类的名称(包名+类名)
String classname ="com.ffyc.javareflect.User";
//如何类的信息?可以通过Class类来获得类中的信息
//如何获得类的Class对象?
//方式1:
Class clazz1=Class.forName(classname);
System.out.println(clazz1);
//方式2:
Class clazz2 =User.class;
System.out.println(clazz1==clazz2);
//方式3
User user = new User();
Class clazz3 = user.getClass();
System.out.println(clazz1==clazz3);
获得Constructor类实例
Constructor实例通过Class实例获得,Class类中定义了如下方法
constructor getConstructor(Class …parameterTypes);
通过指定参数类型,返回构造方法实例
constructor类可以通过getXXX方法获得构造方法的基本信息
getName:返回构造方法的名字
除了可以获得构造方法的基本信息,还可创造实例
使用newInstance(Object… initargs)可以创造实例
String classname="com.ffyc.javareflect.User";
//1.通过类名 获得到类的Class对象
Class aClass=Class.forName(classname);
//2.通过类的class对象,创建对象
0bject object =aClass.newInstance();
System.out.println(object);
//获得类中的构造方法,通过构造方法api中的方法创建对象
Constructor constructor1 = aClass.getconstructor();//获得指定的公共构造方法
0bject objectl=constructor1.newInstance();
Constructor constructor2 =aClass.getConstructor(String.class,String.class);
Object object2 = constructor2.newInstance( "zhangsan","1111");
System.out.println(object1);
System.out.println(object2)
获得Field实例
通过Class中的方法可以获得Field实例
public Field getField(String name)通过指定Field名字,返回Field实例
注意Field的访问权限(类中的属性是否私有)
Field类将类的属性进行封装,可以获得属性的基本信息,属性的值,也可以对属性进行赋值
getName:返回属性名字
set:设置属性值
//1.通过类名 获得到类的Class对象
Class aClass=Class.forName(classname);
//2.通过类的Class对象,创建对象
0bject object =aClass.newInstance();
/获得类中成员变量//
Field accountField = aclass.getField("account");//获得指定名称的公共的成员变量
/*Field accountField = aclass.getDeclaredField("account");//获得指定名称的成员变量,包含私有的
accountField.setAccessible(true);
accountField.set(object,"admin");
System.out.println(object);*/
//模拟从数据库中查询到的数
HashMap<String,String> map = new HashMap<>();
map.put("account","admin");
map.put("password","1111");
Field[] declaredFields = aClass.getDeclaredFields(); //获得类中所有的成员变量
for(Field field :declaredFields){
field.setccessible(true);//允许访问操作私有属性,不建议
field.set(object,map.get(field.getName()));
}
System.out.println(object);
获得Method实例
Method实例都是通过Class类的方法获得
Method get Method(String name,Class…parameterTypes);
通过指定方法名,参数类型,返回一个Method实例
Method类将类中的方法进行封装,可以动态获得方法的信息,例如:
getName:获得方法名字
getParameterTypes:获得方法的参数类型
除了动态获得方法之外,Method还能动态调用某一个对象的具体方法
invoke(Object obj,Object… args);
使用obj调用该方法,参数为args
String classname ="com.ffyc.javareflect.User"
//String classname ="com.ffyc.javareflect.Car";
//1.通过类名 获得到类的class对象
Class aClass =Class.forName(classname);
//2.通过类的class对象,创建对象
Object object =aClass.newInstance();
//演示通过属性的get和set方法,对类中私有属性进行赋值取值操作
//模拟从数据库中查询到的数据
HashMap<String,String> map = new HashMap<>():
map.put("account","admin");
map.put("password","1111");
//先拿到类中所有的私有属性
Field[] declaredFields = aclass.getDeclaredFields();
for(Field field :declaredFields){
//根据属性名 生成set方法名称
String setmethod = "set"+field.getName().substring(0,1).touppercase(+ field,getName(),substring(1);
//通过class对象,获得对应的set方法对象
Method setmethodobj= aClass.getMethod(setmethod,field.getType());
//调用set方法
setmethodObj.invoke(object,map.get(field.getName()));
反射案例
自定义java对象转换Json工具类
public class JsonUtil {
public static String objectToJson(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = object.getClass();
String json = "{";
Field[] declaredFields = clazz.getDeclaredFields();
for(Field field : declaredFields){
//生成get方法名字
String getmethod = "get"+field.getName().substring(0,1).toUpperCase()+field.getName().substring(1);
//获得方法对象
Method method = clazz.getMethod(getmethod);
//调用方法
String value =(String) method.invoke(object);
//把属性和名字拼接成键值
json += field.getName()+":"+value+",";
}
//去掉多余的逗号
json = json.substring(0,json.length()-1);
json+="}";
return json;
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
User user = new User();
user.setAccount("admin");
user.setPassword("111");
Car car = new Car();
car.setColor("红色");
car.setName("宝马");
System.out.println(JsonUtil.objectToJson(user));
}
}
反射优缺点
优点
1.增加程序的灵活性,可以在运行过程中动态对类进行修改和操作
2,提高代码效率,比如动态代理
3.可以在运行时轻松获取任意一个类的方法,属性,并且还能通过反射进行动态调用
缺点
1.反射会涉及到动态类型的解析.导致性能要比非反射调用更低
2,使用反射技术通常要在一个没有安全限制的程序运行
3,反射可以绕过一些限制访问的属性或者方法,可能会导致破坏代码本身的抽象性