反射机制
1>指的是可以于运行时加载,探知,使用编译器间完全未知的类。
2>程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;
String path = "com.shc.test.reflect.User";
Class clazz = Class.forName(path);
3>对象是表示或封装一些数据,一个类被加载后,JVM会创建一个对应的Class对象,类的整个结构信息会放到对应的Class对象中。这个Class对象就像一面镜子一样,通过这面镜子可以看到对应类的全部信息。
4>一个类只对应一个Class对象(反射对象),如果下面还有
Class clazz2 = Class.forName(path);
则clazz与clazz2的hashCode是相等的。
5>加载完类之后,在堆内存中,就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。
6>获取Class类对象的三种方式:
1.运用getClass(),
如:Class strClazz1 = "abc".getClass();
2.运用Class.forName()<最常用>,
3.运用.class语法
如:Class strClazz2 = String.class;
Class intClazz = int.class;
其中strClazz1==strClazz2
int[] arr1 = new int[1];
int[] arr2 = new int[10];
其中:arr1.getClass().hashCode()==arr2.getClass.hashCode();
因为:Class类的实例代表一个运行java应用程序的类和接口。枚举是一种类,注解是一种接口。每一个数组也属于一个类,该类被反映为一个类对象,该对象由所有具有相同元素类型和维数的数组共享(如是一个一维数组和二维数组则不相等)。原始的java类型(boolean
, byte
, char
, short
, int
, long
, float
, and double
),keyword 和 void
也表示为类对象。
反射机制常见作用
String path = "com.shc.test.reflect.User";
Class clazz = Class.forName(path);
1>动态加载类,动态获取类的信息(属性,方法,构造器)
clazz.getName();//获取包名+类名
clazz.getSimpleName();//获取类名
//属性信息
Field[] fields = clazz.getFields();//只能获取public修饰的属性
clazz.getDeclaredFields();//获取所有的属性
clazz.getDeclaredField("name");//获取指定的属性
//方法信息
Method[] methods = clazz.getDeclaredMethods();//获取所有的方法
clazz.getDeclaredMethod("getUserName", null);//获取指定方法,第二个参数为可变参数类型
//如果要获取的方法有一个或者多个参数,可以在后面将参数的类型一一写出
clazz.getDeclaredMethod("setObj", String.class,Integer.class);
//获得构造器信息
clazz.getConstructors();//获得public的构造器
clazz.getDeclaredConstructors();//获得所有的构造器
clazz.getDeclaredConstructor(int.class,String.class);//根据传递的参数个数与类型获取指定的构造器
2>动态构造对象
User u = (User)clazz.newInstance();//其实是调用了User的无参构造方法
反射被大量应用到了框架中,大部分开源框架创建对象的时候都是以newInstance()的方式,这就是为什么javabean必须有无参构造器
也可以通过指定的构造器构造对象
Constructor<User> c = clazz.getDeclaredConstructor(int.class,String.class);
User u2 = c.newInstance(100,"shc");
3>动态调用类和对象的任意方法,构造器
User u1 = clazz.newInstance();
Method method = clazz.getDeclaredMethod("setName",String.class);
method.invoke(u1,"shc");//invoke激活
其中下两行代码等于u1.setName("shc");,反射的调用方式比较灵活,方法名称和值都是字符串,可以以参数的形式传入,实现动态的调用。
4>动态调用和处理属性
Field f = clazz.getDeclaredField("name");
f.setAccessible(true);//访问私有属性时需要(告诉这个属性不用做安全检查,可以直接访问)Method也有这个
//禁止安全检查还可以提高反射的运行速度
f.set(u1,"shc1");//通过反射直接写属性值
5>获取泛型信息
不常用
6>处理注解
//获得类的所有有效注解
Annotation[] annotations = clazz.getAnnotations();
//获得类的指定的注解
SxtTable st = (SxtTable)clazz.getAnnotation(SxtTable.class);
//获得类的属性的注解
Field f = clazz.getDeclaredField("name");
SxtField sxtField = f.getAnnotation(SxtField.class);