什么是Java反射?
· JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
·Java反射机制主要提供了以下功能:在运行时判定任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判定任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
反射的应用场景:
· 逆向代码 ,例如反编译
· 与注解相结合的框架 例如spring
· 单纯的反射机制应用框架
· 动态生成类框架
反射机制的优缺点:
优点:
运行期类型的判断,动态类加载,动态代理使用反射。
缺点:
性能是一个问题,反射相当于一系列解释操作,通知jvm要做的事情,性能比直接的java代码
在学习之前有必要知道类加载器和实例对象(Class和newInstance)的区别:
·这篇文章写的蛮不错的 https://blog.csdn.net/championhengyi/article/details/78778575
示例下载地址: https://github.com/Hairo1/java-Reflect.git
1.通过反射创建对象
反射无参构造方法创建实例
Class<?> clazz = Class.forName("类路径");//如:com.xx.xxx.类名
Object o = clazz.newInstance();
System.out.println("通过无参构造方法反射实例化:"+o.toString());
反射带参构造方法创建实例
Class<?> clazz = Class.forName(calssPathName);
//获取String类型参数的构造方法
Constructor<?> constructor = clazz.getConstructor(String.class);
//反射实例化带String类型参数的构造方法
Object o = constructor.newInstance("Hairo");
System.out.println("通过带参构造方法反射实例化:"+o);
2.通过反射给成员变量赋值
Class clazz = Class.forName(this.classPathName);
//创建类实例
Object o = clazz.newInstance();
//获取指定属性名进行赋值 getField(name);--不能获取私有的属性
Field field = clazz.getDeclaredField("name");
//因为属性私有的所以必须开启权限才能操作
field.setAccessible(true);
//指定属性名赋值 k-v
field.set(o, "反射设置私有name属性的值");
//调用输出方法-输出null为赋值失败
//指定方法名获取show方法
Method method =clazz.getMethod("show");
//调用show方法 o代表那个对象的show方法,
method.invoke(o);
3.反射获取方法并调用
Class<?> clazz = Class.forName(classPathName);
Object o = clazz.newInstance();
//获取所有方法并执行
Method[] methods = clazz.getDeclaredMethods();
//获取所有实例方法
for (Method method : methods){
//method.getTypeParameters();获取方法的参数列表---懒得写了
System.out.println("执行方法:"+method);
//开启权限去执行方法
method.setAccessible(true);
//方法参数为0个的时候执行
if(method.getTypeParameters().length==0){
method.invoke(o);
System.out.println("");
}
}
4.反射获取注解
注解都是自定义的
01.获取类上运行期间有效的注解
Class clazz = Class.forName(classPathName);
//获取类上的所有运行期间有效的注解
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations){
System.out.println(classPathName+"类存在注解:"+annotation);
//判断类上是否存在某个注解
System.out.println("是否存在@Service注解:"+clazz.isAnnotationPresent(Service.class));
if(clazz.isAnnotationPresent(Service.class)){
//转换为该注解的类型
Service service = (Service) annotation;
//获取注解@Service name设置的值
System.out.println("@Service的name值:"+service.name());
//获取注解@Service value设置的值
System.out.println("@Service的value值:"+service.value());
}
}
02.获取属性上的注解
Class clazz = Class.forName(classPathName);
//获取所有属性,包括private修饰的属性
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields){
//System.out.println(field.getAnnotation(Resource.class));
//判断属性是否存在@Resource
if(field.isAnnotationPresent(Resource.class)){
Resource resource = field.getAnnotation(Resource.class);
System.out.println(resource.name());
System.out.println(resource.value());
//这里就可以实现如何按指定名称/类名小写开头/类型。。。注入
//@service 没有指定
if(resource.name().equals("default")){
//默认按类型或者按类名小写开头注入
}else{
//@service("xxxx");
//默认按指定名称注入。。。。。
}
}else{
//判断其他注解如:@Autowired主动注入
}
}
03.获取方法上的注解
Class clazz = Class.forName(classPathName);
//获取所有方法,包括private修饰的方法
Method[] methods = clazz.getDeclaredMethods();
for(Method method : methods){
System.out.println(method+"方法的注解"+method.getAnnotation(com.hairo.annotations.Method.class));
}
反射的其他Api,示例已经实现了大部分:
/**
*其他的api
* Calss<?>[] getClasses()
* 返回一个数组,其中包含 类对象代表所有的公共类和接口这个 类对象所表示的类的成员。
* Class<?>[] getInterfaces()
* 决定了接口由这个对象所表示的类或接口实现。
*int getModifiers()
* 返回Java语言修饰符的类或接口,编码在一个整数。
* String getName()
* 返回的实体的名称(数组类,接口,类、原始类型或空白)由这个 类对象,作为 String。
* Package getPackage()
* 这个类的包。
* ProtectionDomain getProtectionDomain()
* 返回该类的 ProtectionDomain。
* URL getResource(String name)
* 发现与一个给定名称的资源。
* InputStream getResourceAsStream(String name)
* 发现与一个给定名称的资源。
* Object[] getSigners()
* 这个类的签名者。
* String getSimpleName()
* 返回底层类的简单的名称在源代码中给出。
* Class<? super T> getSuperclass()
* 返回 类代表实体的超类(类,接口,原始类型或空白)由这 类表示。
* String getTypeName()
* 返回一个字符串信息为这种类型的名称。
* TypeVariable<类>[] getTypeParameters()
* TypeVariable对象返回一个数组表示泛型声明的变量类型声明由这个 GenericDeclaration对象,按声明顺序。
* boolean isAnnotation()
* 返回true,如果这 类对象代表一个注释类型。
* boolean isAnnotationPresent(类<? extends Annotation> annotationClass)
* 返回true,如果指定类型的注释出现在这个元素,其他的错误的。
* boolean isAnonymousClass()
* 返回 true当且仅当底层类是一个匿名类。
* boolean isArray()
* 决定如果这 类对象表示一个数组类。
* boolean isAssignableFrom(类<?> cls)
* 确定这个 类对象所表示的类或接口是一样的,或者是一个超类或超接口,所表示的类或接口指定 类参数。
* boolean isEnum()
* 返回true当且仅当这个类声明为enum的源代码。
* boolean isInstance(Object obj)
* 确定指定的 Object型态与对象由这 类表示。
* boolean isInterface()
* 确定指定的 类对象表示一个接口类型。
* boolean isLocalClass()
* 返回 true当且仅当底层类是当地的一个类。
* boolean isMemberClass()
* 返回 true当且仅当底层类是一个类成员。
* boolean isPrimitive()
* 确定如果指定的 类对象代表一个原始类型。
* boolean isSynthetic()
* 返回 true如果这类是一个合成类;否则返回 false
* T newInstance()
* 创建一个新的这个 类对象所表示的类的实例。
* String toGenericString()
* 返回一个字符串描述这个 类,包括修饰符和类型参数信息。
* String toString()
* 将对象转换为一个字符串。
*
*/