反射是指在程序运行期间,能够观察和修改类或者类的对象的属性和行为的特性。
项目开发中常见的使用反射的场景:
使用JDBC连接数据库、
Servlet在Web容器中加载和运行
Java反射机制提供了以下的功能:
1、在运行是获取类的修饰符,包名,类名,实现的接口,继承的父类
2、在运行时获取类的所有属性名,属性修饰符,属性类型
3、运行时获取所以方法,方法的返回值类型,方法名,方法参数值,方法参数类型
4、在运行时调用加载类的方法
通过Class类的对象可以获取类的属性、方法;生成类的实例;调用实例的方法、属性
反射:通过操控Class类的对象实现对类的操作;实现对对象的操作;
类的执行过程:
Java常用的反射类:
java.lang.Class:反射核心类,可获取类的属性,方法等信息,生成类的实例
Class类常用方法:
forName()--获取类型
newInstance()--构造对象,只能够调用 无参的构造函数,即默认的构造函数;要求被调用的构造函数是可见的,也即必须是 public类型的;
获取属性:
getFields()----所有可访问的公共字段
getDeclaredFields()----所有字段
getField(String name)----返回一个特定的公共Field对象
获取方法:
getMethods()----所有的公共方法,包括从超类和超接口继承的声明,返回的是方法数组;
getDeclaredMethods()----所有方法,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法,返回的是方法数组;
例如:
Method m[] = c.getDeclaredMethods();
getMethod(String name,Class[] parameterTypes)----返回一个方法对象
获取构造方法
getConstructor();
getDeclaredConstructor();
java.lang.reflect.Method:表示类的方法,可以用来获取类的方法信息或执行方法
getName()
invoke(object)
java.lang.reflect.Constructor:表示类的构造方法
setAccessible(boolean)
newInstance()--创建对象;可以根据传入的参数,调用 任意构造构造函数。在特定的情况下(即setAccessible(true))可以 调用私有的构造函数
java.lang.reflect.Field;表示类的成员变量,可用来获取和设置类的属性值
getName()
java.lang.Modifier.Modifier:(修饰符工具类) 用于判断和获取某个类、变量或方法的修饰符,将各个修饰符表示为相对应的整数,在源码中用16进制进行表示
Java反射机制是Java语言被视为准动态语言的关键特性
Java反射机制有优点也有缺点
可以通过下面代码了解反射机制
package cn.kgc.rfc; import cn.kgc.Student; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Scanner; /** * @Author:Adminstrator * @Date:2021 * @Description:演示反射 * className:类型全类名 * paramsTypes:构造方法参数类型列表 * params:构造方法参数值列表 */ public class TestReflect<T> { //获取对象实例,创建新的对象实例方法(抛异常) public T getInstance(String className,Class[] paramsTypes,Object... params) throws Exception{ Class<T> c = (Class<T>) Class.forName(className); Constructor<T> cons = c.getDeclaredConstructor(paramsTypes); cons.setAccessible(true); return(T) cons.newInstance(params); } //获取对象实例,创建新的对象实例方法(处理异常) // public T getInstance(String className,Class[] paramsTypes,Object... params) { // T t = null; // try { // Class<?> c = Class.forName(className); // Constructor<?> cons = c.getDeclaredConstructor(paramsTypes); // cons.setAccessible(true); // Object o= cons.newInstance(params); // t=(T) o; // } catch (ClassNotFoundException e) { // e.printStackTrace(); // } catch (NoSuchMethodException e) { // e.printStackTrace(); // } catch (InstantiationException e) { // e.printStackTrace(); // } catch (IllegalAccessException e) { // e.printStackTrace(); // } catch (InvocationTargetException e) { // e.printStackTrace(); // } // return t; // } public static void main(String[] args) throws Exception { //1、获取类型Class Class<Student> sc =Student.class;//使用.class获取 // Student s=new Student();//由于s的类型不能确定具体的对象地址(可能是子类) // Class<? extends Student> sc1 =s.getClass();//使用对象.getClass() // Class<?> sc2=Class.forName("cn.kgc.Student"); //2、获取构造方法,并创建对象 // Constructor<Student> c = sc.getConstructor(int.class,double.class);//获取公共的构造方法 Constructor<Student> c = sc.getDeclaredConstructor(int.class,double.class,String.class);//获取构造方法 c.setAccessible(true);//强行获取访问权限 Student s = c.newInstance(1,1.5,"王思聪");//通过构造方法创建对象 System.out.println(s); // System.out.println(s.getScore()); System.out.println(s.getName()); //3、使用对象调用方法 // Method getStuNo = sc.getDeclaredMethod("getStuNo");//根据方法名获取方法 Method method = sc.getDeclaredMethod("setStuNo", int.class); method.setAccessible(true);//强行获取访问权限 Object o= method.invoke(s,15); // Object o = method.invoke(s);//执行对象方法 System.out.println(o); System.out.println(s); //4.使用对象强行对属性赋值 Field stuNo = sc.getDeclaredField("stuNo"); stuNo.setAccessible(true); stuNo.set(s,18); System.out.println(s); //5、获取父类 Class<? super Student> suc = sc.getSuperclass();//获取父类的Class对象 Constructor<? super Student> cs = suc.getConstructor();//获取父类默认的构造方法 Object object = cs.newInstance(); System.out.println(object); Method think = suc.getMethod("think"); think.invoke(object); //6.获取接口 Class<?>[] i = sc.getInterfaces(); Class<?> inter = i[0];//获取父接口 TestReflect<Student> t=new TestReflect<>(); // t.getInstance(); } }
总结:
反射优点:
运行期类型的判断,动态类加载;
提高了程序的灵活性、扩展性,降低耦合性;
提高自适应能力,无需提前硬编码目标类;
缺点:
性能问题,安全问题,内部暴露;
基于反射生成类的实例并调用方法步骤:
Class类--getConstructor(Class[] parameterTypes)
Constructor类--newInstance(Object[] initargs)
Method类--invoke(Object obj,Object...args)