文档章节

聊一聊Java反射中的Field

trayvon
 trayvon
发布于 2017/04/08 22:01
字数 1328
阅读 50
收藏 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反射

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

小刀爱编程
11/07
0
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
Git撤销已经推送(push)至远端仓库的提交(commit)信息

有时,在git push之后,才发现还有一些代码需要进行很小的改动,这些改动在原则上不应该作为一次新的提交。这时,我们需要撤销这次推送(git push)与提交(git commit),然后进行代码修改,再重...

春哥大魔王的博客
07/05
0
0
Java中的String对象是不可变的吗

有个仁兄在 StackOverflow 上发起了一个问题,是这么问的: 众所周知Java中的String对象是不可变的,但我们来看下面这段代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 String s1 ...

LCZ777
2014/03/25
0
0
java 过滤list的几种方式

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

黄威
07/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

小程序异步操作 跨js执行 在微信小程序里面实现跨页面通信

我们知道,在小程序里面一个页面的变化,是通过调用 setData 函数来实现的。所以想做到在二级页面里让一级页面产生变化,最 Quick And Dirty 的做法就是把一级页面的 this 传入到二级页面去,...

xiaogg
14分钟前
0
0
授于管理员登录其它用户

1.沙盒中,授予管理员登录 安全性控制==>登录访问权限政策

在山的那边
16分钟前
1
0
线程安全的CopyOnWriteArrayList介绍

证明CopyOnWriteArrayList是线程安全的 先写一段代码证明CopyOnWriteArrayList确实是线程安全的。 ReadThread.java import java.util.List; public class ReadThread implements Runnable {......

绝地逢生
18分钟前
0
0
Java重写的7个规则

几年前你可能会遇到这样一个面试题:“重写和重载的区别”、而现在随着科技的更迭、面试的问题越来越高级、面试官的问题也越来越深入、此文是上述面试题的一个延伸、让你从简单的重写规则中更...

architect刘源源
18分钟前
1
0
JavaScript异步编程:Generator与Async

从Promise开始,JavaScript就在引入新功能,来帮助更简单的方法来处理异步编程,帮助我们远离回调地狱。 Promise是下边要讲的Generator/yield与async/await的基础,希望你已经提前了解了它。...

前端攻城老湿
19分钟前
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部