什么是反射机制?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个 对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java语言的反射机制。
Java反射 API
反射API用来生成JVM中的类、接口或则对象的信息。
1. Class 类:反射的核心类,可以获取类的属性,方法等信息。
2. Field 类:Java.lang.reflec 包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。
3. Method 类: Java.lang.reflec 包中的类,表示类的方法,它可以用来获取类中的方法信息或者执 行方法。
4. Constructor 类: Java.lang.reflec 包中的类,表示类的构造方法。
反射使用步骤(获取 Class 对象、调用对象方法)
1. 获取想要操作的类的 Class 对象,他是反射的核心,通过 Class 对象我们可以任意调用类的方法。
2. 调用 Class 类中的方法,既就是反射的使用阶段。
3. 使用反射 API 来操作这些信息。
获取 Class 对象的 3 种方法
调用某个对象的getClass()方法
Person p=new Person();
Class clazz=p.getClass();
调用某个类的class属性来获取该类对应的Class对象
Class clazz=Person.class;
使用Class类中的forName()静态方法(最安全/性能最好)
Class clazz=Class.forName("类的全路径"); (最常用)
当我们获得了想要操作的类的 Class 对象后,可以通过 Class 类中的方法获取并查看该类中的方法和属 性。
//获取 Person 类的 Class 对象
Class clazz=Class.forName("reflection.Person");
//获取 Person 类的所有方法信息
Method[] method=clazz.getDeclaredMethods();
for(Method m:method){
System.out.println(m.toString());
}
//获取 Person 类的所有成员属性信息
Field[] field=clazz.getDeclaredFields(); for(Field
f:field){
System.out.println(f.toString());
}
//获取 Person 类的所有构造方法信息
Constructor[] constructor=clazz.getDeclaredConstructors();
for(Constructor c:constructor){
System.out.println(c.toString());
}
创建对象的两种方法
Class对象的newInstance()
1. 使用 Class 对象的 newInstance()方法来创建该 Class 对象对应类的实例,但是这种方法要求该 Class 对象对应的类有默认的空构造器。
调用Constructor 对象的newInstance()
2. 先使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance() 方法 来创建 Class 对象对应类的实例,通过这种方法可以选定构造方法创建实例。
//获取 Person 类的 Class 对象
Class clazz=Class.forName("reflection.Person");
//使用.newInstane 方法创建对象
Person p=(Person) clazz.newInstance();
//获取构造方法并创建对象
Constructor
c=clazz.getDeclaredConstructor(String.class,String.class,int.class);
//创建对象并设置属性
Person p1=(Person) c.newInstance("李四","男",20);
静态编译和动态编译
静态编译:在编译时确定类型,绑定对象
动态编译:运行时确定类型,绑定对象
反射机制优缺点
优点: 运行期类型的判断,动态加载类,提高代码灵活度。
缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能 比直接的java代码要慢很多。
Java获取反射的三种方法
1.通过new对象实现反射机制
2.通过路径实现反射机制
3.通过类名实现反射机制
public class Student {
private int id;
String name;
protected boolean sex;
public float score;
}
public class Get {
//获取反射机制三种方式
public static void main(String[] args) throws ClassNotFoundException {
//方式一(通过建立对象)
Student stu = new Student();
Class classobj1 = stu.getClass();
System.out.println(classobj1.getName());
//方式二(所在通过路径-相对路径)
Class classobj2 = Class.forName("fanshe.Student");
System.out.println(classobj2.getName());
//方式三(通过类名)
Class classobj3 = Student.class;
System.out.println(classobj3.getName());
}
}
反射中,Class.forName和classloader的区别
java中class.forName()和classLoader都可用来对类进行加载。
class.forName()前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static 块。
而classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在 newInstance才会去执行static块。
Class.forName(name, initialize, loader)带参函数也可控制是否加载static块。并且只有调用了 newInstance()方法采用调用构造函数,创建类的对象
反射机制的应用场景有哪些?
反射是框架设计的灵魂。 在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实 际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代 理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架也大量使用到了反射机 制。
举例:①我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序; ②Spring框架也用到很多反射机制, 经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:1) 将程序内所有 XML 或 Properties 配置文件加载入内存中; 2)Java类里面解析xml或 properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制,根据这 个字符串获得某个类的Class实例; 4)动态配置实例的属性
获取类中的成员方法并执行
1.Class类获取成员方法对象:
方法分类Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
Method getMethod(String methodName, Class...parameterTypes):返回单个公共成 员方法对象
Method getDeclaredMethod(String methodName, Class...parameterTypes):返回单 个成员方法对象
2.Method类型:
1)表示成员方法的类型,该类型的每个对象,都是一个具体的成员方法2)成员方法对象具有的功能: 获取成员方法信息,比如:注解,名称,返回值类型,参数类型等等, 及运行方法.
3.Method类用于执行方法的功能:
//参数1: 要执行是那个对象的该方法 p.eat(), 参数1就是p//参数2: 执行方法是需要的实参,都是Object类型, 基本类型自动装箱
// 返回值类型: Object 表示方法执行完之后的返回值 返回值是基本类的,会自动装箱 Object invoke(Object obj, Object...values):调用obj对象的成员方法,参数是 values,返回值是Object类型.
————————————————
// 反射获取成员方法对象
public class GetMethod {
public static void main(String[] args) throws Exception{
// 获取类对象
Class c1 = Class.forName("com.ujiuye.demo01.Person");
// 获取public修饰的方法,既能获取到自己类中声明公开的方法,也能获取到父类中声明的
公开方法
Method[] ms1 = c1.getMethods();
for (Method method : ms1) {
System.out.println(method);
}
System.out.println("-----------------------------------------");
// 获取所有的方法, 获取到自己类中声明的方法,父类继承的拿不到
Method[] ms2 = c1.getDeclaredMethods();
for (Method method : ms2) {
System.out.println(method);
}
System.out.println("=======================================");
// 创建一个该类的对象
Constructor con = c1.getConstructor();
Object o = con.newInstance();
// 获取某一个public修饰的方法对象
// 参数1: 获取方法对象的方法名
// 参数2: 方法中声明参数的类型的类对象
// getMethod(String methodName, Class...type);
// public void eat()
Method m1 = c1.getMethod("eat");
System.out.println(m1);
暴力反射
代码示例
// 执行方法m1
Object r1 = m1.invoke(o); // o.eat()
System.out.println(r1);
// public void eat(String name)
Method m2 = c1.getMethod("eat", String.class);
System.out.println(m2);
// 执行方法m1
m2.invoke(o, "翔"); // o.eat("翔")
// public int sum(int a, int b)
Method m3 = c1.getMethod("sum", int.class, int.class);
System.out.println(m3);
// 执行方法m3
Object r3 = m3.invoke(o, 10, 20);
System.out.println(r3);
System.out.println(r3.getClass());
// private double sum(double a, double b)
// 获取本类中任何一个方法对象
// getDeclaredMethod(String methodName. Class...type)
Method m4 = c1.getDeclaredMethod("sum", double.class, double.class);
System.out.println(m4);
Method m5 = c1.getDeclaredMethod("buy");
System.out.println(m5);
// 执行方法m4
Object r5 = m5.invoke(o); // o.buy()
System.out.println(r5);
}
}
暴力反射
1.通过Class类中:
getDeclaredXXX方法: 可以获取类中的所有声明的成员(属性、方法、构造),私有的成员也可以获取 到.但是私有成员进行访问使用时,会因为权限问题导致失败,因此就需要暴力反射解决访问私有的问题.
2.修改该对象的访问权限:
AccessibleObject类是Field,Method和Constructor对象的基类. 它提供了在使用它时反射对象 将其标记为抑制默认Java语言访问控制检查的功能.
setAccessible(boolean flag): true的值表示反射对象应该在使用时抑制Java语言访问检 查,false的值表示反映的对象应该强制执行Java语言访问检查.
3.一旦设定当前对象可以访问,私有的成员也可以被访问,被修改.