反射
文章的结构分布(自己的知识体系总结)
一.了解java的反射机制
百度百科:
Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。
java中关于反射 的类都在java.lang.reflect包
1.java中的一个类有若干个对象组成,field属性对象,method方法对象,constructor构造器对象,Modifier修饰符对象,Void对象
2.反射是类的自省,通过反射可以动态获取类中的方法 构造方法,属性等类的内容
3.我们以前编写的代码,是编译期代码,是硬编码,反射在运行期执行的代码,使用反射编写的代码并没有具体定义那个对象,它会根据需要在运行期自动创建类的对象并调用相关的方法
4.我们可以通过反射来开发通用功能的方法或者类;目前所使用的所有企业级开发框架都离不开反射
总结:
反射就是一个技术,通过获得字节码对象,在运行期执行相关的操作,如获得自身的属性,方法,构造器,也可以根据需要(根据编写的代码)创建自身的对象!
问题1:
反射为什么可以写出通用的功能?
因为可以通过Class cla ,也就是通过泛型和字节码,可以使得出传入任何对象的字节码,然后通过反射创建其对象,并进行了一系列操作
问题2:
Java中同一个类创建的俩个对象字节码一样吗?
不一样
二.java反射的基本使用:
1.Class类:
Class类在java,lang>Class类,该类就是用于表示类或者接口的字节码对象
获取一个类的Class对象有以下3中方式
(1)完整路径名: Class.forName
Class aClass = Class.forName("com.fan.model.User");
System.out.println(aClass);
(2)通过类名.Class直接获得
Class<User> userClass = User.class;
System.out.println(userClass);
(3)通过对象名,getClass()获得
代码如下:
User user = new User();
Class<? extends User> Class = user.getClass();
System.out.println(Class);
2.使用反射操作类中的属性
方法介绍:
getField(String fieldName) 通过属性名获得一个属性对象
getFields() 获得本类以及父类的public属性,返回一个数组
getDeclaredField(String name)通过属性名指定的一个属性对象
getDeclaredFields() 获取本类中所有的属性,返回一个数组
getName() 获取属性的属性名,返回String
getType() 获取属性的类型名,返回Class
getModifiers() 获取属性的修饰符,返回数字
field.set(obj,“fjg”) 给属性赋值,第一个参数是属性所属的对象,第二个参数是属性的值,调用set给属性赋值,属性不能是private,protected,默认,只有public才可以
field.get(obj)获得属性,返回Object
package com.fan.reflect;
import com.fan.model.User;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class 通过反射操作类中的属性 {
public static void main(String[] args) {
Class<User> userClass = User.class;
//获得类中所有的属性
Field[] declaredFields = userClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
//属性名
String name = declaredField.getName();
//类型名
Class type = declaredField.getType();
//修饰符
int modifiers = declaredField.getModifiers();
String s = Modifier.toString(modifiers);
System.out.println("属性名:"+name);
System.out.println("类型名:"+type);
System.out.println("修饰符:"+s);
System.out.println(s+"" +type+" "+name);
}
}
}
package com.fan.reflect;
import com.fan.model.User;
import java.lang.reflect.Field;
public class 根据属性名获得属性对象并调用该属性 {
public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException {
Class<User> userClass = User.class;
//根据属性名获得一个属性对象
Field field = userClass.getDeclaredField("user_name");
/*
* 调用属性
*编译期调用属性的方法:
* User user=new User();
* user.user_name="樊军刚";
* 反射调用属性
*1.设置属性的值
* field.set(obj,"樊军刚")
* 参数1:对象,属性所属的对象
* 参数2:属性的值
* 2.获得属性的值
* Object val=field.get(obj);
* //获取属性的值
*/
//通过Class创建类的对象,该方法调用类的无参数的构造方法创建类的实例
User user = userClass.newInstance();
field.set(user,"樊军刚");//设置属性的值
String val= (String) field.get(user);
System.out.println(val);
}
}
3.操作类中的方法
方法:
getMethod(String fieldName,Class<?> …parametertypes) 通过方法名和参数类型获得一个方法对象
getMethods() 获得本类以及父类的public方法,返回一个数组
getDeclaredMethod(String name,Class<?> …parametertypes)通过方法名指定的一个方法对象
getDeclaredMethods() 获取本类中所有的方法对象,返回一个数组
getName() 获取方法的方法名,返回String
getModifiers() 获取方法的修饰符,返回数字
getReturnType()获取方法的返回类型
getParameterTypes()获取方法中参数的类型,返回数组
getExpectionTypes()获取方法抛出的异常,返回数组
方法体无权获得
invoke(obj,“值”) 调用方法,第一个是方法的所属对象,后面的是要传入的值
package com.fan.reflect;
import com.fan.model.User;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class 通过反射操作类中的方法 {
public static void main(String[] args) {
Class<User> userClass = User.class;
//获得类中所有的方法,获得当前类的所有方法对象,每个方法都是一个Method对象
Method[] declaredMethods = userClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
//方法名
String name = declaredMethod.getName();
//方法的返回类型
Class returnType = declaredMethod.getReturnType();
//方法的修饰符
int modifiers = declaredMethod.getModifiers();
String s = Modifier.toString(modifiers);
//方法的参数列表,返回方法中参数类型的数组
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
//方法抛出异常
Class<?>[] exceptionTypes = declaredMethod.getExceptionTypes();
//方法体无权获得
System.out.println("方法名"+name);
System.out.println("方法的返回类型:"+returnType);
System.out.println("方法的参数列表");
for (Class<?> parameterType : parameterTypes) {
System.out.println(parameterType);
}
System.out.println("异常:");
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
System.out.println("----------------------------------");
}
}
}
package com.fan.reflect;
import com.fan.model.User;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class 获得某个方法并调用某个方法 {
public static void main(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class<User> userClass = User.class;
//获得一个方法对象,根据方法名和参数列表(参数类型)来确定一个唯一额的方法
Method method = userClass.getDeclaredMethod("setUser_name", String.class);
/**
* 调用方法
* 编译期调用方法:
* User user=new User();
* user.setUser_id=12;
* 反射中调用方法:
* 参数1:对象,值那个对象的方法
* 参数2:方法参数的值
*返回值为方法的返回值
* Object returnValue=method.invoke(obj,12);
* System.out.println(returnValue);
* 调用getUser_id()方法获得属性的值
* Method method1=cla.getDeclareMethod("getUser_id")
* 调用方法
*Object val=method1.invoke(obj)
*/
//创建类的实例
User user = userClass.newInstance();
Object returnValue= method.invoke(user, "fjg");
//调用getUser_id()方法获得属性的值
Method method1 = userClass.getDeclaredMethod("getUser_name");
Object value = method1.invoke(user);
System.out.println(value);
}
}
4.操作类中的构造器
方法:
getConstructor(Class<?> …parametertypes) 通过参数类型获得一个构造器对象
getConstructors() 获得本类的public构造器方法,返回一个数组
getDeclaredConstructor(Class<?> …parametertypes)通过参数类型获得指定的一个构造器对象
getDeclaredConstructors() 获取本类中所有的构造器对象,返回一个数组
getName() 获取构造器的构造名,返回String
getModifiers() 获取构造器的修饰符,返回数字
getParameterTypes()获取构造器中参数的类型,返回数组
getExpectionTypes()获取构造器中抛出的异常,返回数组
newInstance() 创建对象,如果其有值,那么就相当于给对象赋值
代码:
package com.fan.reflect;
import com.fan.model.User;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
public class 通过反射操作类中的构造方法 {
public static void main(String[] args) throws NoSuchMethodException {
Class<User> userClass = User.class;
//获得类中所有的构造方法
Constructor<User> constructor1 = userClass.getConstructor();
Constructor[] constructors = userClass.getDeclaredConstructors();
//遍历构造方法
for (Constructor constructor : constructors) {
//方法名
String name = constructor.getName();
//方法的修饰符
String modifierStr = Modifier.toString(constructor.getModifiers());
//方法的参数列表
Class[] parameterTypes = constructor.getParameterTypes();
//方法抛出的异常
Class[] exceptionTypes = constructor.getExceptionTypes();
System.out.println("方法名:"+name);
System.out.println("方法的修饰符:"+modifierStr);
System.out.println("参数列表:");
for (Class parameterType : parameterTypes) {
System.out.println(parameterType);
}
System.out.println("异常:");
for (Class exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
System.out.println("--------------------------");
}
}
}
package com.fan.reflect;
import com.fan.model.User;
import java.lang.reflect.Constructor;
public class 获得一个构造方法并创建对象 {
public static void main(String[] args) throws Exception{
Class<User> userClass = User.class;
//使用默认的构造方法创建对象,但JDK11以后就过期了,
// User user = userClass.newInstance();
//获得无参数的构造方法对象
// Constructor<User> declaredConstructor = userClass.getDeclaredConstructor();
// //使用构造方法创建类的对象,调用无参数的构造方法
// User user = declaredConstructor.newInstance();
//
//获得有参数的构造方法对象
Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(int.class, String.class, String.class);
//使用构造方法创建类的对象,调用有参数的构造方法
User user = declaredConstructor.newInstance(11, "樊军刚", "123456");
System.out.println(user);
}
}
5.创建对象的俩种方式
(1) 通过字节码对象调用newInstance方法直接调用对象,但JDK11以后就过期了
Class<User> userClass = User.class;
//使用默认的构造方法创建对象,但JDK11以后就过期了,
User user = userClass.newInstance();
(2)通过字节码生成构造器对象,再通过构造器对象调用newInstance()方法来生成对象
Class<User> userClass = User.class;
Constructor<User> declaredConstructor =userClass.getDeclaredConstructor(int.class, String.class, String.class);
//使用构造方法创建类的对象,调用有参数的构造方法
User user = declaredConstructor.newInstance(11, "樊军刚", "123456");
System.out.println(user);
三.java反应的应用
1**.封装DButils的查询方法,可以用于查询所有的查询,相当于Mybatis的超级讲话版本**
代码:
public <T>List<T> executeQuery(Class<T> cla,String sql,Object...params){
try {
this.getConn();
ps=conn.prepareStatement(sql);
if (params!=null&¶ms.length!=0){
for (int i=0;i< params.length;i++){
ps.setObject(i+1,params[i]);
}
}
rs=ps.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
List<T> list = new ArrayList<>();
while(rs.next()){
T t = cla.getDeclaredConstructor().newInstance();
for (int i=0;i<columnCount;i++){
Object value = rs.getObject(i + 1);
String catalogName = metaData.getCatalogName(i + 1);
Field declaredField = cla.getDeclaredField(catalogName);
String methodName = "set" + catalogName.substring(0, 1).toUpperCase() + catalogName.substring(1);
Method declaredMethod = cla.getDeclaredMethod(methodName, declaredField.getType());
declaredMethod.invoke(t, ConvertUtils.convert(value,declaredField.getType()));
list.add(t);
}
return list;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return null;
}
2.封装Servlet,相当于超级简化版本的SpringMVC,当然了,我们考虑的情况非常少,框架要考虑的情况非常多,非常复杂
package com.fan.reflect.强化反射训练;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Map;
public class Tools {
public static <T> T encapsulationByRequest(Class<T> cla, HttpServletRequest request) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, ParseException {
//获得客户端提交的参数信息,获得一个Map集合key是参数名,值是参数值(字符串数组)
Map<String, String[]> parameterMap = request.getParameterMap();
//创建实体对象
T t = cla.getDeclaredConstructor().newInstance();
//遍历Map集合
for (Map.Entry<String,String[]> entry:parameterMap.entrySet()){
//规定:参数名和实体的属性名必须一致
//根据参数名获得属性名
String fieldName = entry.getKey();
//判断是否存在参数值,如果不存在则继续下一次循环
if (entry.getValue()==null||entry.getValue().length==0){
continue;
}
//获得参数值
String[] value = entry.getValue();
//根据属性名获得属性对象
Field declaredField = cla.getDeclaredField(fieldName);
//根据属性名获得方法名
String methodName="Set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
//获得属性的类型
Class<?> type = declaredField.getType();
//根据方法名和参数列表获得方法对象
Method method = cla.getDeclaredMethod(methodName, type);
//根据属性的类型对值进行处理
if (type==String.class){
method.invoke(t,value[0]);
}else if (type== Date.class){
java.util.Date date = new SimpleDateFormat("yyyy-MM-dd").parse(value[0]);
method.invoke(t,date);
}else if (type==Integer.class){
method.invoke(t,Integer.parseInt(value[0]));
}else if (type.isArray()){
method.invoke(t,new Object[]{value});
}
}
return t;
}
}
至此,java反射结束,创作不易,希望大家多多支持,我在此感谢大家了!