这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战
前言
反射机制在Java内容中十分重要,也是Java被称为准动态语言的一部分原因。
动态语言:是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。
静态语言:是在编译时确定变量的数据类型的语言,多数静态类型语言要求在使用变量之前必须声明数据类型。
什么是反射?
能够分析类能力的程序称之为反射--《Java核心技术》
简单来说,在执行完类加载后,在堆里会出现一个存放该类信息的一个Class对象,通过这个对象我们可以得到
加载的类的一些结构信息,就好像镜子里的自己,这种现象就被称为反射
反射机制的作用
- 在运行时分析类的能力
- 在运行时检查对象
- 实现泛型数组操作代码
- 利用Method等对象
咱们一个一个来说
1. 利用反射分析类的能力
在java.lang.reflect包内存在三个Field、Method、Constructor类,分别用来描述类的成员变量,方法以及构造器
而在之前我们也看到过这些类会出现在类加载中出现的Class类对象中
所以提供Class类对象,我们可以了解到很多很多对应类的信息。
@SuppressWarnings({"all"})
public class Test01 {
public static void main(String[] args) throws NoSuchMethodException,NoSuchFieldException {
Cat cat = new Cat();
Class aClass = cat.getClass();
// 得到aClass对象中对应Cat类中方法的方法对象数组
Method[] methods = aClass.getMethods();
// 提供方法名去得到对应的方法对象
Method method = aClass.getMethod("CarName");
// 得到aClass对象中对应Cat类中字段的字段对象数组
Field[] fields = aClass.getFields();
// 提供字段名去得到对应的字段对象
Field age = aClass.getField("age");
// 得到aClass对象中对应Cat类中构造器的构造器对象数组
Constructor[] constructors = aClass.getConstructors();
// 要得到指定的构造器就比较特殊,需要传入对应对象的类的Class对象
Constructor constructor = aClass.getConstructor(String.class, int.class);
/**
* public Cat(String name, int age) {
* this.name = name;
* this.age = age;
* }
*/
}
}
复制代码
2、利用反射在运行时检查对象
同样也是去利用Class对象,在运行时得到有关类的信息,并且进行一定的操作(比如说:创建一个针对所有类的一个toString方法)
public class test1 {
private String name = "test";
private int age = 12;
private String home = "home";
public void mms (){
System.out.println("Mod");
}
public String toString()
{
Field[] fields=this.getClass().getDeclaredFields();
StringBuffer strBuf=new StringBuffer();
strBuf.append(this.getClass().getName());
strBuf.append("[");
for(int i=0;i<fields.length;i++)
{
Field fd=fields[i];
strBuf.append(fd.getName()+":");
try
{
strBuf.append(fd.get(this));
}
catch (Exception e)
{
e.printStackTrace();
}
if(i!=fields.length-1)
strBuf.append("|");
}
strBuf.append("]");
return strBuf.toString();
}
}
复制代码
3、利用反射机制实现泛型数组操作代码
Java.reflect.Array类允许动态的创建数组,所以可以进行一些相关的操作,比如使用Array.copyOf方法实现数组扩容
public class test2 {
private static int[] tmp = {1,2};
public static int[] add(int[] num, int newLength){
// 拿到数组的Class类对象
Class<? extends int[]> aClass = tmp.getClass();
// 判断是不是数组类
if(!aClass.isArray()){
System.out.println("不是数组");
return null;
}
else {
// 表示数组类的对象定义了这个类,确定数组的正确类型
Class<?> componentType = aClass.getComponentType();
int length = Array.getLength(tmp);
// 创建新的数组
Object o = Array.newInstance(componentType, newLength);
return (int[]) o;
}
}
public static void main(String[] args) {
System.out.println(tmp.length);
int[] add = add(tmp, 5);
System.out.println(add.length);
}
}
复制代码
4.利用Method等对象,进行调用方法
反射机制可以让你通过获得Class对象中的Method对象来调用对应方法
之前调用是 对象.方法(如:cat.CarName())
通过Method方法调用是 Method对象.invoke(对象)(如:carName.invoke(o))
public class Test4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
// 通过反射动态加载类
Class aClass = Class.forName("reflex.testclass.Cat");
// 通过方法名获得指定方法对象
Method carName = aClass.getMethod("CarName");
// 通过newInstance创建实例对象(使用无参构造器)
Object o = aClass.newInstance();
// 通过Method方法调用 执行方法
String invoke = (String) carName.invoke(o);
// 输出返回值
System.out.println(invoke);
}
}
复制代码
近期评论