【JavaSE】反射与内省与注解

本文详细介绍了Java中的反射机制,包括通过字节码对象获取构造器、方法和字段并进行操作。同时,讲解了内省在JavaBean中的应用,如获取属性描述器、实现JavaBean与Map之间的转换。此外,还提到了注解的基本定义和使用,包括元注解@Target和@Retention。
摘要由CSDN通过智能技术生成

【JavaSE】反射与内省

1. 反射

  • 为什么要用反射?

通过反射,可以获得它的真实类型,以及调用该对象中的方法

1.1字节码对象
1.2 获取字节码对象

三种方式:

  1. Class.forName(类的全限定名);
  2. 对象.getClass();
  3. 通过类型的class字段:Student.class/int.class/Integer.class
1.3 获取构造器
1.3.1 反射获取构造器
// 获取所有的public修饰构造器
public Constructor<?> getConstructors();
// 获取所有的(包括非public)构造器
public Constructor<?> getDeclaredConstructors();
// 获取指定的构造器(通过传递参数类型)
public Constructor getConstructor(Class... parameterTypes);
public Constructor getDeclaredConstructor(Class... parameterTypes);
1.3.2 调用构造器
// 调用构造器
Constructor con1 = clz.getConstructor();
Object obj = con1.newInstance();

// 调用私有构造器,必须先设置为可访问
Constructor con2 = clz.getDeclaredConstructor(String.class);
con2.setAccessible(true);
Object obj = con2.newInstance("Tom");
  • Class对象.newInstance()
// 反射
Class clz = Class.forName("com.hyh.Student");
Constructor con = clz.getConstructor();
Object obj = con.newInstance();
// 简便
Class clz = Class.forName("com.hyh.Student");
Object obj = clz1.newInstance();
1.4 获取操作方法
  • Method类
1.4.1 反射获取方法
// 获取所有方法:
// 获取到所有的公共方法,包括继承的方法
public Method[] getMethods();
// 获取去到奔雷中所有的方法,包括非public的, 不包括继承的
public Method[] getDeclaredMethod();

// 获取指定的方法:
public Method getMethod(String name, Class<?>...parameterTypes);
public Method getDeclaredMethod(String name, Class<?>...parameterTypes);
1.4.2 调用方法
public Object invoke(Object obj, Object... args);
obj:表示该方法要作用在哪个对象上
args: 调用方法的实际参数
// 例子:
Method method = clz.getMethod("study",String.class);
method.invoke(obj, "语文");
// 调用私有方法,必须先设置为可访问
Method sleep = clz.getDeclaredMethod("sleep", int.class);
// 设置可访问
sleep.setAccessible(true);
sleep.invoke(obj, 8);
1.5 操作字段
1.5.1 获取字段
// 获取单个字段, name: 表示要获取的字段的名称
public Field getField(String name);
public Field getDeclaredField(String name);
// 获取所有字段
public Field[] getFields();
public Field[] getDeclaredFields();
1.5.2 操作字段
get(Object obj)
set(Object, Object value)
// 例子:    
Field nameField = clz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj, "Tom");
System.out.println(nameField.get(obj));

小结:

  1. 理解为什么需要反射
  2. 获取字节码对象的三种方式
  3. 通过字节码对象获取构造器,调用构造器
  4. 通过字节码对象获取方法,调用方法

2. 内省

2.1 JavaBean规范
  1. 类名使用public修饰
  2. 字段私有化
  3. 提供get/set方法
  4. 公关的无参构造
  • 什么是属性?

JavaBean可以封装数据,就是将数据保存到一个bean对象的属性中的。属性不是字段,属性是通过get/set方法推导出来的。(只要是标准的get/set方法,就存在属性)

2.2 内省的基本操作
  • 核心类:Introspector

  • 内省的作用:

  1. 获取属性名和属性类型等相关状态信息
  2. 获取属性对应的读写方法,操作属性的值 等操作方式
  • 常用API
// 1.通过字节码对象,获取到JavaBean的描述对象,
// 会获取到父类的描述对象,stopClass表示到哪个父类不获取
public static BeanInfo getBeanInfo(Class beanClass, Class stopClass);
// 2.通过JavaBean描述对象获取属性描述器
PropertyDescriptor[] getPropertyDescriptors()
// 3.通过属性描述器, 获取到属性名,属性类型,读写方法
public String getName()
public Class<?> getPropertyType()
public Method getReadMethod()
public Method getWriteMethod()
2.3 JavaBean和Map相互转换
  • map2bean
public static Object map2bean(Map<String, Object> map, Class clz) throws Exception {
        Object obj = clz.newInstance();
        // 1. 获取所有属性
        BeanInfo beanInfo = Introspector.getBeanInfo(clz, Object.class);
        PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            // 2. 获取属性名作为map的key,
            String key = pd.getName();
            // 获取属性值,
            Object value = map.get(key);
            // 调用Setter方法设置属性值
            pd.getWriteMethod().invoke(obj, value);
        }
        return obj;
    }
  • bean2map
	public static Map<String, Object> bean2map(Object obj) throws Exception {
        Map<String, Object> map = new HashMap<>();
        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass(), Object.class);
        PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            String key = pd.getName();
            // 获取属性的getter方法并调用,得到属性值作为map的value
            Object value = pd.getReadMethod().invoke(obj);
            map.put(key, value);
        }
        return map;
    }

3. 注解的基本定义和使用

3.1 元注解:
@Target: 表示注解可以贴在哪些位置(,方法上,构造器上等等).位置的常量封装在 ElementType 枚
举类中:
ElementType.ANNOTATION_TYPE只能修饰Annotation
ElementType.CONSTRUCTOR只能修饰构造方法
ElementType.FIELD只能修饰字段(属性),包括枚举常量
ElementType.LOCAL_VARIABLE只能修饰局部变量
ElementType.METHOD 只能修饰方法
ElementType.PACKAGE只能修饰包(极少使用)
ElementType.PARAMETER只能修饰参数
ElementType.TYPE只能修饰类,接口,枚举
@Retention: 表示注解可以保存在哪一个时期. 表示时期的值,封装在RetentionPolicy枚举类中: 
@Documented: 使用 @Documented 标注的标签会保存到 API文档中.
@Inherited: @Inherited标注的标签可以被子类所继承.
3.2 注解语法
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface 注解名 {
    // 定义抽象方法,
    // 在注解中,抽象方法叫属性,抽象方法名叫属性名,返回值叫属性值的类型
    返回值类型 方法名() default 默认值;
}

例子:

@Targer(ElementType.TYPE)
@Rentation(RetentionPolicy.RUNTIME)
public @interface VIP{
    String name() default "狗子";
    int age();
    String[] hobby();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值