什么是反射?
反射机制是在【运行状态】中:
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
反射提供的功能:
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法。
生成动态代理
反射机制原理
Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。也就是说,ClassLoader找到了需要调用的类时(java为了调控内存的调用消耗,类的加载都在需要时再进行,很抠但是很有效),就会加载它,然后根据.class文件内记载的类信息来产生一个与该类相联系的独一无二的Class对象。该Class对象记载了该类的字段,方法等等信息。以后jvm要产生该类的实例,就是根据内存中存在的该Class类所记载的信息(Class对象应该和我所了解的其他类一样会在堆内存内产生、消亡)来进行。而java中的Class类对象是可以人工自然性的(也就是说开放的)得到的(虽然你无法像其他类一样运用构造器来得到它的实例,因为Class对象都是jvm产生的。不过话说回来,客户产生的话也是无意义的),而且,更伟大的是,基于这个基础,java实现了反射机制。
获取Class对象三种方式:
- 1.通过Object类的getClass()方法。例如:
Class perClazz = new String("").getClass(); - 2.通过Class类的静态方法——forName()来实现:
Class perClazz = Class.forName(“MyObject”); - 3.如果T是一个已定义的类型的话,在java中,它的.class文件名:T.class就代表了与其匹配的Class对象,例如:Class perClazz = Manager.class;Class c4 = int.class;
Class perClazz = Double[].class;
获取方法
- //获取所有的公共方法
Method[] methods = perClazz.getMethods(); - //获取当前类的所有方法(当前类,忽略访问修饰符限制)
Method[] declaredMethods = perClazz.getDeclaredMethods();
获取所有的接口
- //Java多实现,获取所有的接口
Class<?>[] interfaces = perClazz.getInterfaces();
获取父类
- //Java单继承,获取父类
Class<?> superClass = perClazz.getSuperclass();
获取构造方法
- //获取所有的构造方法
Constructor<?>[] constructors = perClazz.getConstructors(); - //获取指定的构造放方法,获取类型方法时,基本类型和包装类是不同的
Constructor constructor = perClazz.getConstructor(int.class);
获取类的属性
- //公共属性
Field[] fields = perClazz.getFields(); - //所有属性
Field[] declaerdields = perClazz.getDeclaredFields();
修改访问权限
- Field.setAccessible(true);//属性
- Method.setAccessible(true);//方法
- Constructor.setAccessible(true);//构造方法
调用Class属性/方法/构造器
-
属性
Field idField = perClazz.getDeclaredField(“id”);
//修改访问权限Field/Method.setAccessible(true);/
idField.setAccessible(true);
idField.set(person,1);
System.out.println(person.getId()); -
方法
Method priMethod = perClazz.getDeclaredMethod(“privateMethod”,null);
priMethod.setAccessible(true);
priMethod.invoke(person,null);//invoke()调用方法Method priMethod2 = perClazz.getDeclaredMethod(“privateMethod2”,String.class);
priMethod2.setAccessible(true);
priMethod2.invoke(person,“JavaMan”);//invoke()调用方法 -
构造器
Constructor constructor = perClazz.getConstructor(int.class);
Person person = (Person) constructor.newInstance(15);
System.out.println(person.getId());
绕过范性类型检查
编译器编译带参数说明的集合时会去掉类型的信息,转化为普通的链表,所以运行时,将不会受到泛型的影响。所以可以这样来绕开泛型的限制;
ArrayList<Integer> al = new ArrayList<Integer>();
al.add(1);
al.add(2);
//获取链表的add方法,注意这里是Object.class,如果写int.class会抛出NoSuchMethodException异常
Method m = al.getClass().getMethod("add", Object.class);
//调用反射中的add方法加入一个string类型的元素,因为add方法的实际参数是Object
m.invoke(al, "hello");
配置文件+反射机制
通过配置文件配置类的全路径和部分属性,可以创造工具类利用反射机制实现类的各种操作。
XXX.properties
ClassPath=com.javaman.reflect.Person
//Dome.class.getClassLoader()获取文件路径类加载器
InputStream in = Dome.class.getClassLoader().getResourceAsStream("XXX.properties");
//读取文件
Properties properties=new Properties();
properties.load(in);
String ClassPath = properties.getProperty("ClassPath");
其他方法
-
1.getName()
一个Class对象描述了一个特定类的特定属性,而这个方法就是返回String形式的该类的简要描述。 -
2.newInstance()
该方法可以根据某个Class对象产生其对应类的实例。需要强调的是,它调用的是此类的默认构造方法。 -
3.getClassLoader()
返回该Class对象对应的类的类加载器。 -
4.getComponentType()
该方法针对数组对象的Class对象,可以得到该数组的组成元素所对应对象的Class对象。例如:
int[] ints = new int[]{1,2,3};
Class class1 = ints.getClass();
Class class2 = class1.getComponentType();
而这里得到的class2对象所对应的就应该是int这个基本类型的Class对象。 -
5.getSuperClass()
返回某子类所对应的直接父类所对应的Class对象。 -
6.isArray()
判定此Class对象所对应的是否是一个数组对象。
代码测试
package com.javaman.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.FileHandler;
/**
* Created by zhahongsheng on 2019/4/14.
*/
public class TestReflect {
/**
* 获取反射对象(反射入口)
*/
public static void demo1(){
//获取反射对象(反射入口)1。Class.forName(全类名)2.xx.Class(),3.对象.getclass()
try {
Class<?> perClazz = Class.forName("com.javaman.reflect.Person");
System.out.println(perClazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class<?> perClazz2= Person.class;
System.out.println(perClazz2);
Person per = new Person();
Class<?> perClazz3 = per.getClass();
System.out.println(perClazz3);
}
//获取方法
public static void demo2(){
//Class入口
Class<?> perClazz = null;
try {
perClazz = Class.forName("com.javaman.reflect.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//获取所有的公共方法
Method[] methods = perClazz.getMethods();
for(Method method : methods){
System.out.println(method);
}
System.out.println("=========================================================");
//获取当前类的所有方法(当前类,忽略访问修饰符限制)
Method[] declaredMethods = perClazz.getDeclaredMethods();
for (Method method : declaredMethods){
System.out.println(method);
}
}
//获取所有的接口
public static void demo3(){
Class<?> perClazz =null;
try {
perClazz = Class.forName("com.javaman.reflect.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class<?>[] interfaces = perClazz.getInterfaces();
for(Class<?> inter : interfaces ){
System.out.println(inter);
}
}
//获取父类
public static void demo4(){
Class<?> perClazz =null;
try {
perClazz = Class.forName("com.javaman.reflect.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class<?> superClass = perClazz.getSuperclass();
System.out.println(superClass);
}
//获取所有的构造方法
public static void demo5() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> perClazz =null;
try {
perClazz = Class.forName("com.javaman.reflect.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Constructor<?>[] constructors = perClazz.getConstructors();
for(Constructor constructor : constructors){
System.out.println(constructor);
}
//获取指定的构造放方法
//在获取类型方法时,基本类型和包装类是不同的
Constructor constructor = perClazz.getConstructor(int.class);
Person person = (Person) constructor.newInstance(15);
System.out.println(person.getId());
}
//获取所有的公共属性
public static void demo6(){
Class<?> perClazz =null;
try {
perClazz = Class.forName("com.javaman.reflect.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//公共属性
Field[] fields = perClazz.getFields();
for(Field field : fields){
System.out.println(field);
}
//所有属性
Field[] declaerdields = perClazz.getDeclaredFields();
for(Field field : declaerdields){
System.out.println(field);
}
}
public static void demo7() throws IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
Class<?> perClazz =null;
try {
perClazz = Class.forName("com.javaman.reflect.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Object instance = perClazz.newInstance();
if(instance instanceof Person){
Person person = (Person)instance;
person.interfaceMethod();
Field idField = perClazz.getDeclaredField("id");
//修改访问权限Field/Method.setAccessible(true);/
idField.setAccessible(true);
idField.set(person,1);
System.out.println(person.getId());
Method priMethod = perClazz.getDeclaredMethod("privateMethod",null);
priMethod.setAccessible(true);
priMethod.invoke(person,null);//invoke()调用方法
Method priMethod2 = perClazz.getDeclaredMethod("privateMethod2",String.class);
priMethod2.setAccessible(true);
priMethod2.invoke(person,"JavaMan");//invoke()调用方法
}
}
public static void main(String[] args) {
// demo1();
// demo2();
// demo3();
// demo4();
try {
demo5();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
// demo6();
try {
demo7();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
总结
反射机制是java框架的核心,反射机制的重点在于运行状态下工作