文档章节

聊一聊Java反射中的Field

trayvon
 trayvon
发布于 2017/04/08 22:01
字数 1328
阅读 54
收藏 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
粉丝 16
博文 125
码字总数 185343
作品 1
程序员
私信 提问
老司机带你深入浅出Java反射

反射,它就像是一种魔法,引入运行时自省能力,赋予了 Java 语言令人意外的活力,通过运行时操作元数据或对象,Java 可以灵活地操作运行时才能确定的信息 这里笔者就深入浅出总结下Java反射,...

小刀爱编程
2018/11/07
0
0
Java反射机制

问题: 在运行时,对一个JAVA类,能否知道属性和方法;能否调用它的任意方法? 答案是可以的,JAVA提供一种反射机制可以实现。 目录 什么是JAVA的反射机制 JDK中提供的Reflection API JAVA反...

长平狐
2012/08/29
552
0
类名.class, class.forName(), getClass()区别

1:Class cl=A.class; JVM将使用类A的类装载器, 将类A装入内存(前提是:类A还没有装入内存),不对类A做类的初始化工作.返回类A的Class的对象。 2:Class cl=对象引用o.getClass(); 返回引用o运行...

LCZ777
2014/09/17
0
0
黑马程序员--JDK1.5新特性(二)

----------------------android培训、java培训、期待与您交流!---------------------- Java反射机制定义: Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性、方法...

长平狐
2013/07/01
53
0
Java反射机制

一、什么是反射机制 简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。 二、哪里用到反射机制 有些时候...

长平狐
2012/10/09
479
0

没有更多内容

加载失败,请刷新页面

加载更多

刚入职阿里,告诉你真实的职场生活,兼谈P6、P7、P8的等级

一:拿下offer的人,基本上都有什么特征? 二:为什么选择阿里? 三:阿里的工作氛围什么样? 四:阿里的薪资情况? 五:阿里的晋升空间有多大? 最近部门招聘,很多工程师,包括我在内都参与...

java知识分子
16分钟前
2
0

中国龙-扬科
19分钟前
1
0
深入理解定时器系列第一篇——理解setTimeout和setInterval

很长时间以来,定时器一直是javascript动画的核心技术。但是,关于定时器,人们通常只了解如何使用setTimeout()和setInterval(),对它们的内在运行机制并不理解,对于与预想不同的实际运行状...

Jack088
22分钟前
2
0
windows 安装nvm

1、nvw-windows的官网:https://github.com/coreybutler/nvm-windows/releases 2、选择nvm-setup.zip安装 3、配置环境变量 4、检查nvm是否安装成功 使用管理员权限打开一个命令行。输入nvm v...

灰白发
32分钟前
1
0
MySQL

慢日志查询作用 慢日志查询的主要功能就是,记录sql语句中超过设定的时间阈值的查询语句。例如,一条查询sql语句,我们设置的阈值为1s,当这条查询语句的执行时间超过了1s,则将被写入到慢查...

士兵7
34分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部