反射是Java底层的技术,反射主要通过Class,Filed,Method,Constructor这几个类来实现的
可以通过反射获取任意类的所有信息,还可以创建任意类的对象,还可以调用类中的方法等等
总的来说的,反射是一个强大的技术,可以让程序的设计更加的灵活
但是通常情况下很少会用到反射,反射一般在做框架封装的时候,才会大量使用到
任何一个强大的框架肯定少不了对反射的使用
比如说我自己封装了一个WEB框架,就是利用反射获取方法上面的注解,进而获取注解中携带的信息
类是用来描述对象的
反射可以理解为是用来描述类的
所有的类都具有相同的特征
每一个类都有自己的结构 比如 属性 方法 构造方法 都有 权限修饰符 特征 等等
Class 用来描述类本身 —-> 可以理解为Class对象与硬盘上的.class类文件产生了映射关系
Package 用来描述类所属的包
Filed 用来描述类中的属性
Method 用来描述类中的方法
Constructor 用来描述类中的构造方法
Annotation 用来描述类中的注解@Override 注解可以放在 类上面 属性上面 方法上面 构造方法上面 参数前面
1. 如何获取Class
有三种方式
1.1 Class = Class.forName(“包名.类名”);
1.2 Class = 类名.class; //类名必须存在
1.3 Class = 对象引用.getClass(); //Object类中的方法
2. Class中常用的方法
2.1 int = getModifiers();
//获取类的修饰符(权限 特征) 得到的结果是所有的对应的值相加
0 - 默认修饰符 1 - public 2 - private 4 - protected 8 - static
16 - final 32 - synchronized 64 - volatile 128 - transient
256 - native 512 - interface 1024 - abstract
2.2 String = getName();
//获取类的全名 包名加类名
String = getSimpleName();
//获取类名 仅仅就是类的名字
2.3 Package p = getPackage();
//获取包
p.getName();
//获取包名
2.4 Class = getSuperClass();
//获取父类
2.5 Class[] = getInterfaces();
//获取当前类的所有父接口
public static void main(String[] args){try {//通过包名和类名 可能找不到包 所以会出现异常// Class clazz = Class.forName("test_reflect.Person");ArrayList<String> list = new ArrayList<>();//通过类名.来获取ArrayList父类 因为都知道类名了 所以这里不会出现异常Class clazz = ArrayList.class;Class sclazz = clazz.getSuperclass();while(sclazz!=null){System.out.println(sclazz.getName());sclazz = sclazz.getSuperclass();}//获取clazz的所有父接口Class[] classes = clazz.getInterfaces();for(Class c:classes){System.out.println(c.getName());}//自己有结构 权限修饰符 特征修饰符int modify = clazz.getModifiers();//类名字clazz.getName();//类全名clazz.getSimpleName();//类名//获取类所在的包Package p = clazz.getPackage();System.out.println(p.getName());clazz.getSuperclass();} catch (ClassNotFoundException e) {e.printStackTrace();}}
2.6 Object obj = calzz.newInstance();
//相当于调用person类中默认无参数的构造方法创建person对象
//即 Person p = (Person)clazz.newInstance();
//如果无参数的构造方法被有参数的覆盖了 这时候抛出异常
//NOSuchMethodException
3. Field类
怎么获取类的属性Field —-> Class类中的方法
2.7 Filed nameField = getFiled(“属性名”); //需要导包
//获取类中的 指定属性 公有的 自己类+父类
Field[] fileds = getFields();
//获取类中的 全部属性 公有的 自己类+父类
2.8 Field = getDeclaredField(“属性名”);
//获取 本类中 指定的 公有的或私有的 属性
Field[] = getDeclaredFields();
//获取 本类中 全部的 公有的以及私有的 属性
public static void main(String[] args) throws Exception {String str = new String("abc");System.out.println(str);//反射技术可以获取私有属性 从而去操作私有属性 虽然很不合理//1.获取String类对应的Class 对象引用.getClass()来获取Class clazz = str.getClass();//2.通过clazz获取类中的私有属性valueField field = clazz.getDeclaredField("value");//3.直接操作属性是不可以的 找到私有属性不代表能修改 只是给你看见//要想修改就需要setAccessible 设置私有属性可以被操作field.setAccessible(true);//4. 获取value属性里面的值 即内存地址// private final char[] value = {'a','b','c'};char[] temp = (char[]) field.get(str);temp[0] = '你';temp[1] = '好';temp[2] = '啊';System.out.println(str);//此时value属性里面存的值就发生了改变}
Field类中的常用方法
3.1 int = getModifers();
//获取属性的修饰符
3.2 Class fclass = getType();
//获取 属性的类型 对应的那个类 比如String也有自己对应的Class
3.3 String fname = getName();
//获取 属性名
如何操作属性 往里面 存值 取值?
3.4 set(对象,值);
//存值
3.5 值 = get(对象);
//取值 因为不确定取值的类型 需造型
3.6 setAccessable(true);
//设置访问权限 让私有属性可以被操作
//若不写这个代码直接操作私有属性 会抛出异常 IllegalAccessException
public static void main(String[] args){try {//通过包名和类名 可能找不到包 所以会出现异常Class clazz = Class.forName("test_reflect.Person");Person p = (Person)clazz.newInstance();//相当于调用person类中默认无参数的构造方法创建对象//如果无参数的构造方法被有参数的覆盖了 这时候运行就会出现异常//通过clazz来获取类中对应的属性//要知道属性叫什么名字 且是公有的Field nameField = clazz.getField("name");//需要导包 获取类中的name属性//获取全部属性 继承过来的也算 且只能获取公有的//Field[] fileds = clazz.getFields();//System.out.println(fileds.length);nameField.getModifiers();//获取 属性的修饰符Class fclass = nameField.getType();//获取 属性的类型对应的那个类 比如String也有自己对应的ClassString fname = nameField.getName();//获取 属性名//给属性赋值nameField.set(p,"小兰");//取值String name = (String) nameField.get(p);//因为不确定是什么类型的 所以需要造型} catch (Exception e) {e.printStackTrace();}}
4. Method类
怎么获取类的方法Method —-> Class类中的方法
2.9 Method m = clazz.getMethod(“方法名”,Class…(参数列表对应的class类型) );
//获取 指定的 公有的方法(自己类+父类)
//找不到方法会抛出异常 NOSuchMethodException
Method[] m = clazz.getMethods();
//获取 所有的 公有的方法(自己类+父类)
2.10 Method m = clazz.getDeclaredMethod(“方法名”,Class…(参数列表对应的class类型) );
//获取 指定的 公有的+私有的 方法(自己类)
//找不到方法会抛出异常 NOSuchMethodException
Method[] m = clazz.getDeclaredMethods();
//获取 所有的 方法(不包括继承的)
Method类中常用方法
4.1 int = getModifers();
//获取方法的修饰符
4.2 Class fclass = getReturnType();
//获取 方法的 返回值数据类型所对应的类
4.3 String fname = getName();
//获取 方法名
4.4 Class[] = getParameterTypes();
//获取 方法的 参数列表类型所对应的类
4.5 Class[] = getExceptionTypes();
//获取 方法的 抛出异常类型所对应的类
如何操作方法 让其执行?
4.6 Object result = (Object) invoke(方法所属对象,执行方法需要传递的参数…);
//动态参数列表 传多少个参数都行 但是方法需要多少个参数就传几个 不然会抛出异常
4.7 setAccessable(true);
//设置访问权限 让私有方法可以被执行
//若不写这行代码直接执行私有方法 会抛出异常 IllegalAccessException
public class Person{private String name;public int age;public String toString(){return this.name+"-"+this.age;}public void eat(){System.out.println("我是Person类无参数的方法");}public String eat(String s){System.out.println("我是Person类带String参数的方法");return s;}private void privateMethod(){System.out.println("我是私有的方法");}}public static void main(String[] args) {try {//获取Person对应的ClassClass clazz = Person.class;Person p = (Person)clazz.newInstance();//通过方法名字定位方法 再通过方法参数类型对应的Class来找寻相对应的方法 如String类型有自己对应的ClassMethod m = clazz.getMethod("eat",String.class);//方法找不到会抛出异常String result = (String) m.invoke(p,"测试1");System.out.println(result);//获取私有的方法Method m1 = clazz.getDeclaredMethod("privateMethod");//访问私有方法的权限m1.setAccessible(true);//执行私有方法m1.invoke(p);} catch (Exception e) {e.printStackTrace();}}
5. Constructor类
怎么获取类的构造方法Costructor —-> Class类中的方法
2.11 Costructor c = clazz.getConstructor ( Class…(参数列表对应的class类型) );
//获取 指定 构造方法
Costructor[] cons = clazz.getConstructors ( Class…(参数列表对应的class类型) );
//获取 全部 构造方法
2.12 Costructor c = clazz.getDeclaredConstructor ( Class…(参数列表对应的class类型) );
//获取 指定的私有或公有的 构造方法
Costructor[] cons = clazz.getDeclaredConstructors ( Class…(参数列表对应的class类型) );
//获取 全部的私有+公有的 构造方法
Costructor类中常用方法
5.1 int = getModifers();
//获取 构造方法的修饰符
5.2 String fname = getName();
//获取 方法名
5.3 Class[] = getParameterTypes();
//获取 构造方法的 参数列表类型所对应的类
5.4 Class[] = getExceptionTypes();
//获取 构造方法的 抛出异常类型所对应的类
如何操作构造方法 创建对象?
5.5 Object result = (Object)newInstance ( 执行构造方法需要传递的参数… );
//动态参数列表 传多少个参数都行 但是 构造方法需要多少个参数就传几个 不然会抛出异常
5.6 setAccessable(true);
//设置访问权限 让私有构造方法可以被执行
//若不写这行代码直接执行私有构造方法 会抛出异常 IllegalAccessException
