上一篇博客: Java反射详解(二)
写在前面:大家好!我是
晴空๓
。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正,感谢大家的不吝赐教。我的唯一博客更新地址是:https://ac-fun.blog.csdn.net/。非常感谢大家的支持。一起加油,冲鸭!
用知识改变命运,用知识成就未来!加油 (ง •̀o•́)ง (ง •̀o•́)ง
文章目录
前言
之前两篇主要介绍了反射与 Class类 的关系以及通过 Class对象 我们可以获得什么信息以及可以做什么操作,还有如何通过反射获取 Class类 具体字段的信息以及具体方法的信息。本篇书接上文,继续进行梳理我们可以通过反射做什么。
创建对象
通过 Class 的 newInstance() 方法可以创建对象。这里需要注意该方法会调用类的默认的构造方法(即无参的 public 方法),如果我们操作的类没有无参构造方法,调用该方法会抛出 InstantiationException 异常。
java
public class TestClass {
@Test
public void test() throws IllegalAccessException, InstantiationException {
Class<Person> personClass = Person.class;
Person person = personClass.newInstance();
person.eat(); // 生物进食
}
}
构造器相关方法
getConstructors()
getConstructors() 获取当前运行时类中所有 public 构造方法。
java
public class TestClass {
@Test
public void test() {
Class<Person> personClass = Person.class;
Constructor<?>[] constructors = personClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor); // public ReflectionTest.Person()
}
}
}
getDeclaredConstructors()
获取所有的构造器方法,包括 非public 的。
java
public class TestClass {
@Test
public void test() {
Class<Person> personClass = Person.class;
Constructor<?>[] constructors = personClass.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
/**
* public ReflectionTest.Person()
* private ReflectionTest.Person(java.lang.String,java.lang.String)
*/
}
}
}
其他几种方法
Constructor类的方法如下,这里列举几个主要的方法:
- public Constructor getConstructor(Class<?>... parameterTypes) 获取指定参数类型的public构造方法。
- public Constructor getDeclaredConstructor(Class<?>... parameterTypes) 获取指定参数类型的构造方法,包括 非public 的。
- public Class<?>[] getParameterTypes() 返回构造函数的参数类型数组。
- public Annotation[] getAnnotations() 返回构造函数的注解
- public void setAccessible(boolean flag) 设置构造器是否可访问
- public T newInstance(Object ... initargs) 通过构造器创建对象
- public Class<?>[] getExceptionTypes() 返回构造方法声明抛出的异常类型
- public int getModifiers() 返回构造器的修饰符
类的声明信息
Class还有很多方法可以获取类的声明信息,例如修饰符、父类、接口、注解等等,相关方法如下:
java
//获取修饰符,返回值可通过Modifier类进行解读
public native int getModifiers()
//获取父类,如果为Object,父类为null
public native Class<? super T> getSuperclass()
//对于类,为自己声明实现的所有接口,对于接口,为直接扩展的接口,不包括通过父类继承的
public native Class<? >[] getInterfaces();
//自己声明的注解
public Annotation[] getDeclaredAnnotations()
//所有的注解,包括继承得到的
public Annotation[] getAnnotations()
//获取或检查指定类型的注解,包括继承得到的
public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
public boolean isAnnotationPresent(
Class<? extends Annotation> annotationClass)
Class的类型信息
Class 代表的类型既可以是普通的类,也可以是内部类,还可以是基本类型、数组等等。可以通过一下方法检查 Class对象 的类型:
java
public native boolean isArray() //是否是数组
public native boolean isPrimitive() //是否是基本类型
public native boolean isInterface() //是否是接口
public boolean isEnum() //是否是枚举
public boolean isAnnotation() //是否是注解
public boolean isAnonymousClass() //是否是匿名内部类
public boolean isMemberClass() //是否是成员类,成员类定义在方法外,不是匿名类
public boolean isLocalClass() //是否是本地类,本地类定义在方法内,不是匿名类
反射与数组
Class类 中还导入了 java.lang.reflect 包中专门针对数组的 Array类 ,注意该类与 java.util.Arrays 不同。 java.lang.reflect 包中的 Array类 提供了对于数组的一些反射支持,主要方法如下:
java
//创建指定元素类型、指定长度的数组
public static Object newInstance(Class<? > componentType, int length)
//创建多维数组
public static Object newInstance(Class<? > componentType, int... dimensions)
//获取数组array指定的索引位置index处的值
public static native Object get(Object array, int index)
//修改数组array指定的索引位置index处的值为value
public static native void set(Object array, int index, Object value)
//返回数组的长度
public static native int getLength(Object array)
//除Object类型之外Array也支持以各种基本类型操作数组元素
public static native double getDouble(Object array, int index)
public static native void setDouble(Object array, int index, double d)
public static native void setLong(Object array, int index, long l)
public static native long getLong(Object array, int index)
反射与枚举
对于枚举类型也有一个专门的方法用于获取所有的枚举常量。
java
public T[] getEnumConstants()
总结
其实还有很多方法没有列举出来,但是通过这三篇博客的概述我们可以深刻的体会到了反射的强大机制。基本我们想获取的信息或者想实现的操作都能够通过反射进行获取或执行。以上提到的只是反射的一些基础知识,最重要的我们如何看懂那些框架对反射的运用以及在特殊情况下我们如何通过反射完成相关的需求。
这里还是特别说明一下,我们在日常开发中基本用不到反射。虽然说反射可以让我们的代码更加灵活,但是这也是建立在特殊情况的前提之下的。使用反射也增加了安全问题(更容易出现运行时错误,使用显式的类和接口编译器还可以帮助我们做类型检查,减少错误。使用反射只能在运行时才知道);性能也相对差一些,之前看到过一些处理方式是将通过反射获取的信息存储到缓存或者数据库中。
- 《Java编程的逻辑》