欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

荐 Java基础-反射

程序员文章站 2022-04-19 13:22:19
前言疯狂复习基础ing~最近复习的Java基础反射做了应该总结,果然反射不只有那么一点点东西,多的是精髓!最重要的是最后推荐的那两篇文章,写的非常非常好!!反射1.反射的原理Java反射机制就是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意方法和属性;这种动态获取信息以及动态调用对象的功能称为Java语言的反射机制粗略的理解:反射就是在程序运行时,能够动态的操作类的成员。2.反射的用途在日常的第三方应用开发过程中,经常会遇到某个类...

前言

疯狂复习基础ing~
最近复习的Java基础反射做了应该总结,果然反射不只有那么一点点东西,多的是精髓!
最重要的是最后推荐的那两篇文章,写的非常非常好!!

反射

1.反射的原理

Java反射机制就是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意方法和属性;这种动态获取信息以及动态调用对象的功能称为Java语言的反射机制

粗略的理解:反射就是在程序运行时,能够动态的操作类的成员。

2.反射的用途

在日常的第三方应用开发过程中,经常会遇到某个类的成员变量、方法或是私有的或是只对系统应用开发,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或方法,框架的底层就用到了很多反射相关的操作。

3.反射机制的相关类

与Java反射相关的类如下

类名 用途
Class类 代表类的实体,在运行的Java应用程序中表示类和接口
Field类 代表类的成员变量(成员变量也称为类的属性)
Method类 代表类的方法
Constructor类 代表类的构造方法

3.1.Class类

Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供类很多有用的方法。

  • 获取类相关的方法
方法 用途
asSubclass(Class clazz) 把传递的类的对象转换成代表其子类的对象
Cast 把对象转换成代表类或是接口的对象
getClassLoader() 获得类的加载器
getClasses() 返回一个数组,数组中包含该类中所有公共类和接口类的对象
getDeclaredClasses() 返回一个数组,数组中包含该类中所有类和接口类的对象
forName(String className) 根据类名返回类的对象
getName() 获得类的完整路径名字
newInstance() 创建类的实例
getPackage() 获得类的包
getSimpleName() 获得类的名字
getSuperclass() 获得当前类继承的父类的名字
getInterfaces() 获得当前类实现的类或是接口
  • 获取类中属性相关的方法
方法 用途
getField(String name) 获得某个公有的属性对象
getFields() 获得所有公有的属性对象
getDeclaredField(String name) 获得某个属性对象
getDeclaredFields() 获得所有属性对象
  • 获取类中注解的相关方法
方法 用途
getAnnotation(Class annotationClass) 返回该类中与参数类型匹配的公有注解对象
getAnnotations() 返回该类所有的公有注解对象
getDeclaredAnnotation(Class annotationClass) 返回该类中与参数类型匹配的所有注解对象
getDeclaredAnnotations() 返回该类所有的注解对象
  • 获取类中构造器相关的方法
方法 用途
getConstructor(Class…<?> parameterTypes) 获得该类中与参数类型匹配的公有构造方法
getConstructors() 获得该类的所有公有构造方法
getDeclaredConstructor(Class…<?> parameterTypes) 获得该类中与参数类型匹配的构造方法,包含私有
getDeclaredConstructors() 获得该类所有构造方法
  • 获取类中方法的相关方法
方法 用途
getMethod(String name, Class…<?> parameterTypes) 获得该类某个公有的方法
getMethods() 获得该类所有公有的方法
getDeclaredMethod(String name, Class…<?> parameterTypes) 获得该类某个方法
getDeclaredMethods() 获得该类所有方法
  • 类中其他重要的方法
方法 用途
isAnnotation() 如果是注解类型则返回true
isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果是指定类型注解类型则返回true
isAnonymousClass() 如果是匿名类则返回true
isArray() 如果是一个数组类则返回true
isEnum() 如果是枚举类则返回true
isInstance(Object obj) 如果obj是该类的实例则返回true
isInterface() 如果是接口类则返回true
isLocalClass() 如果是局部类则返回true
isMemberClass() 如果是内部类则返回true

3.2.Field类

Field代表类的成员变量对象(成员变量也称为类的属性)

方法 用途
equals(Object obj) 属性与obj相等则返回true
get(Object obj) 获得obj中对应的属性值
set(Object obj, Object value) 设置obj中对应属性值
getName() 获取类中属性的名字

3.3.Method类

Method代表类的方法

方法 用途
invoke(Object obj, Object… args) 传递object对象及参数调用该对象对应的方法

3.4.Constructor类

Constructor代表类的构造方法

方法 用途
newInstance(Object… initargs) 根据传递的参数创建类的对象

4.反射的前提

通过字节码获取class对象

4.1.获取类的Class对象的方式

1.通过类的全路径名的字符串获取class对象

//例如
Class clazz = Class.forName("com.scholarTang.po.UserPo")

2.通过类名.class获取class对象

//例如
Class clazz = UserPo.class

3.通过类的实例获取父类的class对象

//例如
Class clazz = new UserPo().getClass();

4.通过子类的实例获取父类的类对象

//例如
UserPo user = new User();
Class userClazz = user.getClass();
Class supClazz = userClazz.getSuperclass();

5.反射操作

1.通过反射获取目标类的类对象

2.通过类对象获取目标类中的构造方法对象,通过构造方法对象创建目标类对象

3.通过类对象获取目标类中的成员变量对象,在指定对象obj中将此 成员变量对象表示的成员变量设置为指定的新值

4.通过类对象获取目标类中的指定方法对象,调用该方法

5.通过类对象获取目标类中的注解,获取注解中的参数信息

5.1.准备

准备一个目标类

package com.scholarTang.demo;

/**
 * @Author ScholarTang
 * @Date 2020/7/1 4:15 下午
 * @Desc 程序员类
 */

public class Programmer {
  /**
     * 唯一标识
     */
  private String id;
  /**
     * 姓名
     */
  private String name;
  /**
     * 年龄
     */
  private Integer age;
  /**
     * 性别
     */
  private String sex;
  /**
     * 工作经验
     */
  private Integer workExperience;

  public String work(String content){
    return this.name + "正在"+content;
  }

  private String learning(String content){
    return this.name + "正在" + content;

  }

  //空参构造函数.......
  //有参构造函数.......
  //Get、Set.......
  //toString.......

}

自定义注解类

package com.scholarTang.demo;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author ScholarTang
 * @Date 2020/7/4 4:15 下午
 * @Desc 自定义注解,用来描述类的详细信息
 */
@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Deprecated
public @interface ClassDescribe {
     String describe() default "";
}

5.2.反射操作

1.通过反射获取目标类的类对象
/**
  * 获取目标类的类对象(class对象)获取类的类对象有三种方式,我这里选择的是通过类的全路径名来获取类的类对象
  */
Class<?> programmerClazz = Class.forName("com.scholarTang.demo.Programmer");
2.通过类对象获取目标类中的构造方法对象,通过构造方法对象创建目标类对象
/**
 		* 通过类对象获取被public修饰的构造方法
    * 如果是获取空参构造方法,那么getConstructor()方法的传参为null
    * 如果是获取有参构造方法(前提是必须要保证目标类中存在有参构造方法),那么getConstructor()方法的传参数为 属性类型.class
    */
Constructor<?> constructor = programmerClazz.getConstructor(String.class,String.class,Integer.class,String.class,Integer.class);
/**
	* 通过构造方法创建对象并在构造方法中为类中的成员变量赋值
  */
Object obj = constructor.newInstance("CXY001","忙碌的指尖",20,"男",1);
/**
	* 4.打印查看
  * 打印结果:Programmer{id='CXY001', name='忙碌的指尖', age=20, sex='男', workExperience=1}
  */
System.out.println(obj);
3.通过类对象获取目标类中的成员变量对象,在指定对象obj中将此 成员变量对象表示的成员变量设置为指定的新值
/**
	* 获取类对象中的所有成员变量对象(包含公有、私有)
  */
Field[] fields = programmerClazz.getDeclaredFields();
for (Field field : fields) {
	/**
		* 暴力反射 setAccessible(true);
  	* 类对象中的成员可能有的是被私有化了(被public修饰的就不需要进行这一步),这时候操作这些成员对象的时候Java语言会开启访问检查,
  	* 但是我们可以通过暴力反射的方式来关闭Java语言访问检查,从而可以操作私有化的成员对象
  	*/
  field.setAccessible(true);
  /**
  	* 获取通过构造方法创建的对象中的值
    * 打印结果:id:CXY001 name:忙碌的指尖 age:20 sex:男 workExperience:1
    */
  System.out.print(field.getName() + ":" + field.get(obj) + " ");
}
4.通过类对象获取目标类中的指定方法对象,调用该方法
/**
	* 6.获取类对象中指定的方法对象,并调用这个方法
  */
//getMethod() 获取类对象中指定的公有方法对象,方法有两个构造函数:第一个是方法的名字,第二个是方法的参数类型
Method workMethodObj = programmerClazz.getMethod("work", String.class);
//调用类对象中的这个方法,不管方法是否有返回值,invoke()方法的返回值都会是Object
Object invoke = workMethodObj.invoke(obj, "写代码");
System.out.println(invoke);
//获取类对象中指定的方法,不管是公有的还是私有的都可以被获取到
//            Method learningMethodObj = programmerClazz.getDeclaredMethod("learning", String.class);
//如果是私有的方法要对其进行使用需要对其就行暴力反射
//            learningMethodObj.setAccessible(true);
//            Object invoke = learningMethodObj.invoke(obj, "学习反射");
//            System.out.println(invoke);
5.通过类对象获取目标类中的注解,获取注解中的参数信息
/**
	* 获取类中与参数类型匹配的公有注解对象
  */
ClassDescribe annotation = programmerClazz.getAnnotation(ClassDescribe.class);
if (annotation != null){
  System.out.println(annotation.describe());
}

6.深度好文推荐

以上的内容我只是描述了反射是如何使用的,并没有描述太多真正的关于发射的内涵知识。

但是在复习反射的过程中我也查了比较多的资料,譬如下两篇把反射的描述淋漓尽致,自叹不如写不出这么有深度的文章,但是好的文章应该被更多人看到!

学习java应该如何理解反射?

为什么要反射?

本文地址:https://blog.csdn.net/ScholarTang/article/details/107125124