文档章节

聊一聊Java反射中的Field

trayvon
 trayvon
发布于 2017/04/08 22:01
字数 1328
阅读 47
收藏 0

简介

Java中一个重要的机制就是反射了,很多自动化的功能都是通过反射完成的,这对很多框架是非常重要的,因为很多框架就是做顶层抽象处理公用的逻辑,所以对于实现层的东西是不清楚的,有了反射机制,框架就可以在运行时获取到自己需要的实现层的一些信息,从而做更多的事情。

Java的的反射包java.lang.reflect中提供的最常用且重要的几个类就是Field、Method、Constructor这3个类了,这3个类提供的接口很类似,所以这里就先聊一聊Field这个类

实例

这里我们通过一个实例来说一下Field类中常用的接口的意义用法和一下注意事项。field代表的是字段,所以我们先来一个实体bean

public class FieldBean <T>{
    
    @FieldAnnotation(type="int",filedName="intField")
    @FieldId
    private int intField;
    
    @FieldAnnotation(type="String",filedName="stringField")
    private String stringField;
    
    @FieldAnnotation(type="char",filedName="charField")
    private char charField;
    
    @FieldAnnotation(type="double",filedName="doubleField")
    private double doubleField;
    
    @FieldAnnotation(type="long",filedName="longField")
    private long longField;
    
    @FieldAnnotation(type="short",filedName="shortField")
    private short shortField;
    
    @FieldAnnotation(type="byte",filedName="byteField")
    private byte byteField;
    
    @FieldAnnotation(type="float",filedName="floatField")
    private float floatField;
    
    public int publicField;
    
    public static int publicStaticField;
    
    public final static int publicFinalStaticField = 0;
    
    private T objectField;

    public int getIntField() {
        return intField;
    }

    public void setIntField(int intField) {
        this.intField = intField;
    }

    public String getStringField() {
        return stringField;
    }

    public void setStringField(String stringField) {
        this.stringField = stringField;
    }

    public char getCharField() {
        return charField;
    }

    public void setCharField(char charField) {
        this.charField = charField;
    }

    public double getDoubleField() {
        return doubleField;
    }

    public void setDoubleField(double doubleField) {
        this.doubleField = doubleField;
    }

    public long getLongField() {
        return longField;
    }

    public void setLongField(long longField) {
        this.longField = longField;
    }

    public short getShortField() {
        return shortField;
    }

    public void setShortField(short shortField) {
        this.shortField = shortField;
    }

    public byte getByteField() {
        return byteField;
    }

    public void setByteField(byte byteField) {
        this.byteField = byteField;
    }

    public float getFloatField() {
        return floatField;
    }

    public void setFloatField(float floatField) {
        this.floatField = floatField;
    }

    public int getPublicField() {
        return publicField;
    }

    public void setPublicField(int publicField) {
        this.publicField = publicField;
    }

    public static int getPublicStaticField() {
        return publicStaticField;
    }

    public static void setPublicStaticField(int publicStaticField) {
        FieldBean.publicStaticField = publicStaticField;
    }

    public T getObjectField() {
        return objectField;
    }

    public void setObjectField(T objectField) {
        this.objectField = objectField;
    }

    public static int getPublicfinalstaticfield() {
        return publicFinalStaticField;
    }

    @Override
    public String toString() {
        return "FieldBean [intField=" + intField + ", stringField=" + stringField + ", charField=" + charField
                + ", doubleField=" + doubleField + ", longField=" + longField + ", shortField=" + shortField
                + ", byteField=" + byteField + ", floatField=" + floatField + ", publicField=" + publicField
                + ", objectField=" + objectField + "]";
    }
    
    public static <E> FieldBean<E> getDefaultFieldBean(E object){
        FieldBean<E> bean = new FieldBean<E>();
        bean.byteField = Byte.MAX_VALUE;
        bean.charField = 'c';
        bean.doubleField = Double.MIN_NORMAL;
        bean.floatField = Float.MAX_VALUE;
        bean.intField = Integer.MAX_VALUE;
        bean.longField = Long.MAX_VALUE;
        bean.shortField = Short.MAX_VALUE;
        bean.stringField = "string";
        bean.objectField = object;
        return bean;
    }

}

上面的实体bean使用到的2个注解:

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldAnnotation {
    
    public String type();
    
    public String filedName();

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldId {

}

主类:

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Date;

public class FieldStart {
    
    public static void main(String[] args) {
        Date date = new Date(System.currentTimeMillis());
        FieldBean<Date> bean = FieldBean.getDefaultFieldBean(date);
        System.out.println(bean);
        Class<?> clazz = bean.getClass();
        Field[] fields = clazz.getDeclaredFields();
        printFieldInfo(fields);
        dealIntField(clazz,bean);
        dealGetGenericType(clazz);
    }
    
    private static void dealGetGenericType(Class<?> clazz){
        try {
            Field field = clazz.getDeclaredField("objectField");
            Type type = field.getGenericType();
            System.out.println(type);
            System.out.println(type instanceof TypeVariable);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }
    
    private static void dealIntField(Class<?> clazz,FieldBean<Date> bean){
        try {
            Field intField = clazz.getDeclaredField("intField");
            Annotation[] annotations = intField.getAnnotations();
            for (int i = 0; i < annotations.length; i++) {
                System.out.println(annotations[i]);
            }
            FieldAnnotation fieldAnnotation = intField.getAnnotation(FieldAnnotation.class);
            System.out.println(fieldAnnotation.type()+"  "+fieldAnnotation.filedName());
            intField.setAccessible(true);
            int intValue = intField.getInt(bean);
            System.out.println(intValue);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    
    private static void printFieldInfo(Field[] fields){
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            System.out.println("name:"+field.getName());
            System.out.println("modify:"+Modifier.toString(field.getModifiers()));
            System.out.println("declaringClass:"+field.getDeclaringClass());
            System.out.println("genericType:"+field.getGenericType());
            System.out.println("type:"+field.getType());
        }
    }

}

下面以FieldBean中的intField为例来介绍一下各个接口:

@FieldAnnotation(type="int",filedName="intField")
@FieldId
private int intField;

使用最多的接口getName()接口,这个接口就是获取字段的名字,那么上面这个字段代表的Field实例上调用getName()接口,获取的值就是intField。

另外2个常用的接口就是getAnnotations()和getAnnotation(Class)了,getAnnotations()是获取字段上的所有注解实例,同样如上面的字段代表的Field调用getAnnotations()获取到的就是包含了FieldAnnotation和FieldId的数组。调用getAnnotation(FieldAnnotation.class)获取的就是FieldAnnotation的实例,调用getAnnotation(FieldId.class)就是获取的FieldId实例。

注解的确是非常方便的,所以很多框架就通过注解来避免xml配置和强制继承,进而避免和实现层的强耦合,也避免了侵入到实现层的代码中。例如:在类上的注解@Controller,在参数上的注解@Param,在字段上的注解@JSONField,@Id,@Resource,@Autowired等。

获取值,Field类提供了getInt(Object),getLong(Object)等基本类型的方法来获取object实例对应的值,也提供了getObject(Object)接口。 注意:获取值的接口是有访问权限的可以通过setAccessible(true);来避免权限检查。

getDeclaringClass()接口是获取字段所在的类Class,上面的intField字段所代表的Filed实例上调用getDeclaringClass()获取的就是FieldBean.class

getType()接口是获取字段的类型,上面的intField字段所代表的Filed实例上调用getType()获取到的值就是int.class

getModifiers()接口是获取字段的修饰符,例如下面的intField字段所代表的Filed实例上调用getModifiers()方法获取的就是public static final,注意:getModifiers()获取到的是一个int类型的可以通过Modifier.toString(field.getModifiers()))转换一下。

public final static int publicFinalStaticField = 0;

getGenericType()接口是获取字段的泛型类型,例如下面的intField字段所代表的Filed实例上调用getGenericType()获取到的就是:T,实际的类型是TypeVariable

private T objectField;

总结

  1. Field可以通过getName获取字段名称
  2. Field可以通过getAnnotations()和getAnnotation(Class)获取字段注解
  3. Field可以通过getInt(Object)获取指定对象字段的值
  4. 通过setAccessible(true)可以访问私有字段

© 著作权归作者所有

共有 人打赏支持
trayvon
粉丝 15
博文 124
码字总数 184644
作品 1
程序员
二〇一八-美团工程师面试解析(Java)

一轮面试: 小数是怎么存的 算法题:N二进制有多少个1 Linux命令(不熟悉 JVM垃圾回收算法 C或者伪代码实现复制算法 volatile 树的先序中序后序以及应用场景 Mysql存储记录的数据结构 索引数...

Java互联网架构师
08/27
0
0
新浪、百度、好未来3offer到手全记录 | 牛客面经

新浪、百度、好未来3offer到手全记录 牛客面经 原创 2017-09-19 牛友 招聘消息汇总 渣渣的秋招之路 附上新浪,百度,好未来面经 作者:offer快到碗里来?。! 来源:牛客网 楼主是本科渣渣,...

公子只识黛玉
04/17
0
0
一份关于 Java、Kotlin 与 Android 的学习笔记

JavaKotlinAndroidLearn 这是一份关于 Java 、Kotlin 、Android 的学习笔记,既包含对基础知识点的介绍,也包含对一些重要知识点的源码解析,笔记的大纲如下所示: Java 重拾Java(0)-基础知...

叶应是叶
08/08
0
0
Direct Memory只会在Full GC时回收

今天面试一个senior的老同事 聊的GC很细节当聊到jvm优化时 老兄提到了 给jvm加参数取消 System.gc() 来避免gc的频繁调动因为在netty中显式调用的地方所以有点疑惑人走后特意查了下 soga Dir...

xffforever
2014/04/02
0
0
java 过滤list的几种方式

java中 过滤list的几种方式 方式一:使用java 8语法:stream+反射 抽取为通用的过滤方法: 进一步抽取: 方式二:遍历+反射 反射类 ReflectHWUtils 见 https://github.com/liuyu520/io0007 的com...

黄威
07/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

读书(附电子书)|小狗钱钱之白色的拉布拉多

关注公众号,在公众号中回复“小狗钱钱”可免费获得电子书。 一、背景 之前写了一篇文章 《小狗钱钱》 理财小白应该读的一本书,那时候我才看那本书,现在看了一大半了,发现这本书确实不错,...

tiankonguse
32分钟前
0
0
Permissions 0777 for ‘***’ are too open

异常显示: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: UNPROTECTED PRIVATE KEY FILE! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ......

李玉长
34分钟前
0
0
区块链10年了,还未落地,它失败了吗?

导读 几乎每个人,甚至是对通证持怀疑态度的人,都对区块链的技术有积极的看法,因为它有可能改变世界。然而,区块链技术问世已经10年了,我们仍然没有真正的用上区块链技术。 几乎每个人,甚...

问题终结者
今天
2
0
20180921 su与sudo命令、限制root用户通过ssh远程登录

su 命令 用户切换。 su # 切换到root用户su username # 切换到username用户# su 后面加-时,会初始化当前用户的各种环境su - username # 指定用户执行某些命令 su - -c "touch /tm...

野雪球
今天
2
0
Windows 下双 Python 开发环境配置

Windows 下双 Python 开发环境配置作者:老农民(刘启华)QQ: 46715422Email: 46715422@qq.com微信: 46715422 本人曾经在 Windows 下被两个版本环境折腾够呛,现在总结两个 Python...

新疆老农民
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部