目录
反射
什么是反射?
提供了一种动态获取的机制,允许在程序运行时,直接操作class文件,获取属性、方法、构造器等。
为什么使用反射以及Class类的方法?
-
获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等
Class<Student> stuclass = Student.class;
stuclass.getName();//返回完整类名带包名
stuclass.getSimpleName();//返回类名
Field[] fields = stuclass.getDeclaredFields();//返回类中所有的属性
for (Field field : fields) {
System.out.println(field);//遍历数组依次输出
}
Method[] methods = stuclass.getDeclaredMethods();//返回类中所有的实例方法
for (Method method : methods) {
System.out.println(method);
}
Constructor<Student>[] stu =(Constructor<Student>[]) stuclass.getConstructors();//获取构造器
-
获取任意对象的属性,并且能改变该属性
操作字段步骤:
1.创建对象
Class<Student> cls = Student.class;
Student stu = cls.newInstance();
2.获取字段
Field field = cls.getDeclaredField("name");
field.setAccessible(true);//允许访问私有属性
3.操作字段
field.set(stu,"名字");//设置属性
System.out.println(field.get(stu).toString());
-
调用任意对象的方法
Class<StuDao> stuDaoClass = StuDao.class;
Method method = stuDaoClass.getMethod("方法名",Student.class);//获取指定的方法 对象 参数1:方法名 后续参数:方法中的参数的类型
-
实例化任意一个类的对象
Class<Student> cls = Student.class;
Student stu = cls.newInstance();//创建对象
-
判断任意一个对象所属的类
-
通过反射我们可以实现动态装配,降低代码的耦合度,动态代理等
反射的步骤?
-
首先,获取Class类的实例:
三种方法:
1. 类名.class;
2. 对象.getClass();
3.Class.forName("类的完全限定名");//包名+类名
-
其次,通过Class可以获取构造方法、属性、方法等
public Field[] getFields();//返回类中public修饰的属性
public Field[] getDeclaredFields();//返回类中所有的属性
public Field getDeclaredField(String name);//根据属性名name获取指定的属性
public Method[] getDeclaredMethods();//返回类中所有的实例方法
public Method getDeclaredMethod(String name, Class<?>… parameterTypes);//根据方法名name和方法形参获取指定方法
public Constructor getDeclaredConstructor(Class<?>… parameterTypes);//根据方法形参获取指定的构造方法
如何通过反射操作构造方法?
public class Test{
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<Student> stuclass = Student.class;
Constructor<Student> constructor = stuclass.getConstructor();//获取无参构造
Student stu = constructor.newInstance();//通过构造器创建实例
System.out.println(stu);
//获取带参数的构造方法
Constructor<Student> constructor1 = stuclass.getConstructor(String.class);
//给构造方法传递参数
Student stu1 = constructor1.newInstance("名字");
System.out.println(stu1);
}
}
如何通过反射操作字段?
public class Test {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
Class<Student> stuclass = Student.class;
//获取所有字段
Field[] fields = stuclass.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
Student stu = stuclass.newInstance();
Field name = stuclass.getDeclaredField("name");//根据字段名获取字段
name.setAccessible(true);//允许访问私有属性
name.set(stu,"名字");
System.out.println(name.get(stu));
}
}
如何通过反射操作方法?
public class Test {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class<StuDaoImpl> stuDaoClass = StuDaoImpl.class;
StuDaoImpl stuDao = stuDaoClass.newInstance();
//获取指定的方法 对象 参数1:方法名 后续参数:方法中的参数的类型
Method insert = stuDaoClass.getMethod("insert",Student.class);
//调用方法
boolean result = (boolean) insert.invoke(stuDao, new Student("名字"));
System.out.println(result);
Method[] methods = stuDaoClass.getMethods();返回类中所有的公有方法
for (Method method : methods) {
System.out.println(method);
}
}
}
如何使用反射实现通用查询方法的封装?
//查询
public static <T> List<T> query(Class<T> tclass,String sql,Object...params){
List<T> list = new ArrayList<>();//集合
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = getConnection();
statement = connection.prepareStatement(sql);
setParams(statement, params);
resultSet = statement.executeQuery();
ResultSetMetaData metaData = resultSet.getMetaData();
while(resultSet.next()){
//获取T的对象
T t = tclass.newInstance();
for (int i = 1; i <= metaData.getColumnCount(); i++) {
String columnName = metaData.getColumnLabel(i);//获取字段名
Object columnValue = resultSet.getObject(i);//获取字段值,引用类型
//获取字段名对应的实体类型的属性
Field field = tclass.getDeclaredField(columnName);
field.setAccessible(true);
//如果结果集中的字段类型不能直接转成实体的属性类型,强制转换
if(columnValue instanceof Long){//判断该字段是否是Long
Long value = (Long) columnValue;//Object--->转为Long
if(field.getType()==int.class){//如果实体中的该字段的类型是int类型
field.set(t,value.intValue());//获取Long中整型数字
}
}else if(columnValue instanceof Date){
Date value = (Date) columnValue;
if(field.getType() == LocalDate.class){
field.set(t,value.toLocalDate());
}
}
else {
field.set(t, columnValue);
}
}
list.add(t);
}
} catch (SQLException | InstantiationException | IllegalAccessException e) {
System.out.println(e.getMessage());
} catch (NoSuchFieldException e) {
System.out.println(e.getMessage());
} finally {
closeAll(connection, statement, resultSet);
}
return list;
}
//关闭所有
private static void closeAll(Connection connection, PreparedStatement statement, ResultSet resultSet) {
if(resultSet !=null){
try {
resultSet.close();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
if(statement !=null){
try {
statement.close();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
if(connection !=null){
try {
connection.close();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
}
//绑定参数
private static void setParams(PreparedStatement statement, Object[] params) throws SQLException {
if(params !=null){
for (int i = 0; i < params.length; i++) {
statement.setObject(i+1, params[i]);
}
}
}
//获取连接
private static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, pwd);
}