反射是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获取类中的私有属性value
Field 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也有自己对应的Class
String 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对应的Class
Class clazz = Person.class;
Person p = (Person)clazz.newInstance();
//通过方法名字定位方法 再通过方法参数类型对应的Class来找寻相对应的方法 如String类型有自己对应的Class
Method 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