当前位置: 首页 > 工具软件 > Field Bird > 使用案例 >

Field类的使用

蓝华皓
2023-12-01

概述

Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。

Field类中提供了对反射获取的类中成员变量进行操作的方法。

类中每个成员变量都有数据类型数据值

在Java中数据类型分为基本数据类型引用数据类型

基本数据类型分为四类八种:

  • 整数:byte、short、int、long
  • 浮点数:float、double
  • 字符:char
  • 布尔值:boolean

引用数据类型:

  • 所有引用数据类型都继承自java.lang.Object,如String就是引用数据类型
  • 而自定义的类、枚举、数组、接口都是引用数据类型。
  • java.io.Serializable接口,基本数据类型的包装类(如Integer、Character等)都是引用数据类型。

获取Field

可以通过如下方法来获取Field类对象,但必须是Class类型的对象来调用下面的方法。

方法说明
Field[] getFields()获取类中的字段Field,getFields()获取某个类中所有公共(public)的字段,包括父类中的公共(public)字段。
Field getField(String name)获取指定name的字段Field,可以获取某个类中所有公共(public)的字段,包括父类中的公共(public)字段。
Field[] getDeclaredFields()获取某个类中所有声明的字段,包括public、private、protected和(default),但是不包括父类的声明字段。
Field getDeclaredField(String name)获取某个类中指定name的字段,包括public、private、protected和(default),但是不包括父类的声明字段。

实例如下:

public class Test {
    public static void main(String[] args) throws IOException, IllegalAccessException, NoSuchFieldException {
        Class<Bird> personClass = Bird.class;

        // 获取类中的字段Field,getFields()获取某个类中所有公共(public)的字段,包括父类中的字段
        // getDeclaredFields()获取某个类中所有声明的字段,包括public、private、protected和(default),但是不包括父类的声明字段
        // 同样类似的还有getConstructors()和getDeclaredConstructors()、getMethods()和getDeclaredMethods(),这两者分别表示获取某个类的方法、构造函数
        Field[] fields = personClass.getFields();
        Field heightField = personClass.getField("height");
        Field[] declaredFields = personClass.getDeclaredFields();
        Field idDeclaredField = personClass.getDeclaredField("id");

        // 打印结果
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        System.out.println("==================================");
        System.out.println(heightField.getName());
        System.out.println("==================================");

        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getName());
        }
        System.out.println("==================================");
        System.out.println(idDeclaredField.getName());
    }
}

class Animal {
    public String name;
}

class Bird extends Animal {
    private int id;
    protected Animal son;
    String[] masters;
    public double height;
}

常用方法

Field类对象可以有如下方法:

获取变量的数据类型

方法说明如下:

成员方法说明
Class<?> getType()返回一个Class对象,它标识了此 Field 对象所表示字段的数据类型。
Type getGenericType()返回一个Type对象,它表示此Field对象所表示字段的数据类型,一般情况二者返回相同的结果,但如果当前Field的数据类型是泛型则返回泛型类型,反之返回getType()的值。

实例如下:

public class Test {
    public static void main(String[] args) throws IOException, IllegalAccessException, NoSuchFieldException {
        Class<Bird> personClass = Bird.class;
        Field[] declaredFields = personClass.getDeclaredFields();

        for (Field declaredField : declaredFields) {
            // getType(),返回一个Class对象,它标识了此 Field 对象所表示字段的数据类型。
            // getGenericType(),返回一个Type对象,它表示此Field对象所表示字段的数据类型,一般情况二者返回相同的结果,但如果当前Field的数据类型是泛型则返回泛型类型,反之返回getType()的值
            Class<?> type = declaredField.getType();
            Type genericType = declaredField.getGenericType();
            System.out.println(type);
            System.out.println(genericType);
        }
    }
}

class Animal {
    public String name;
}

class Bird extends Animal {
    private int id;
    protected Animal son;
    String[] masters;
    public double height;
    public List<String> hobbies;
}
/*打印结果:
    int
    int
    class com.demo.bean.demo.Animal
    class com.demo.bean.demo.Animal
    class [Ljava.lang.String;
    class [Ljava.lang.String;
    double
    double
    interface java.util.List
    java.util.List<java.lang.String>
 */

获取变量的修饰符

成员变量可以被如下修饰符修饰,这些修饰符也可以被下面的方法获取到

  • 访问权限控制符:public、protected和private。注意,默认不写权限修饰符调用方法返回的是0但不会打印出任何字符串。
  • 静态修饰符:static。
  • 常量修饰符:final。
  • 序列化相关修饰符:transient。
  • 线程相关修饰符:volatile。

方法说明如下:

成员方法说明
int getModifiers()获取当前成员变量的修饰符,但是返回的是java.lang.reflect.Modifier中定义的整形值,需要使用Modifier.toString(int mod)解码成字符串。

实例如下:

public class Test {
    public static void main(String[] args) throws IOException, IllegalAccessException, NoSuchFieldException {
        Class<Bird> personClass = Bird.class;
        Field[] declaredFields = personClass.getDeclaredFields();

        for (Field declaredField : declaredFields) {
            // getModifiers(),获取当前成员变量的修饰符,但是返回的是java.lang.reflect.Modifier中定义的整形值,需要使用Modifier.toString(int mod)解码成字符串
            int modifiers = declaredField.getModifiers();
            System.out.println("变量名:" + declaredField.getName() + ", 修饰符:" + Modifier.toString(modifiers));
        }
    }
}

class Animal {
    public String name;
}

class Bird extends Animal {
    private int id;
    protected Animal son;
    String[] masters;
    public double height;
    public volatile List<String> hobbies;
    public final static transient String COMMENT = "XXX";
}
/*打印结果:
    变量名:id, 修饰符:private
    变量名:son, 修饰符:protected
    变量名:masters, 修饰符:
    变量名:height, 修饰符:public
    变量名:hobbies, 修饰符:public volatile
    变量名:COMMENT, 修饰符:public static final transient
 */

获取成员变量的值

可以分别获取八大基本数据类型和引用数据类型的值。其API方法如下,注意每个方法内的参数obj其实是类对象。

成员方法说明
byte getByte(Object obj)获取一个静态或实例的byte字段的值。
int getInt(Object obj)获取int类型的静态或实例字段的值,或通过扩展转换可转换为int类型的其他基本类型的值。
short getShort(Object obj)获取short类型的静态或实例字段的值,或通过扩展转换可转换为short类型的其他基本类型的值。
long getLong(Object obj)获取long类型的静态或实例字段的值,或通过扩展转换可转换为long类型的其他基本类型的值。
float getFloat(Object obj)获取float类型的静态或实例字段的值,或通过扩展转换可转换为float类型的其他基本类型的值。
double getDouble(Object obj)获取double类型的静态或实例字段的值,或通过扩展转换可转换为double类型的其他基本类型的值。
boolean getBoolean(Object obj)获取一个静态或实例boolean字段的值。
char getChar(Object obj)获取char类型的静态或实例字段的值,或通过扩展转换可转换为char类型的其他基本类型的值。
Object get(Object obj)获取指定对象上此Field表示的字段是引用数据类型所表示的值。

实例代码如下:

public class Test {
    public static void main(String[] args) throws IllegalAccessException {
        Bird bird = new Bird((byte) 1, 2, (short) 3, 4L, 5.0F, 6.0, false, 'X', "text");
        Class<? extends Bird> birdClass = bird.getClass();
        Field[] fields = birdClass.getFields();

        for (Field field : fields) {
            switch (field.getGenericType().getTypeName()) {
                case "byte":
                    byte b = field.getByte(bird);
                    System.out.println("字段名:" + field.getName() + ", 字段值:" + b);
                    break;
                case "short":
                    short s = field.getShort(bird);
                    System.out.println("字段名:" + field.getName() + ", 字段值:" + s);
                    break;
                case "int":
                    int i = field.getInt(bird);
                    System.out.println("字段名:" + field.getName() + ", 字段值:" + i);
                    break;
                case "long":
                    long l = field.getLong(bird);
                    System.out.println("字段名:" + field.getName() + ", 字段值:" + l);
                    break;
                case "float":
                    float f = field.getFloat(bird);
                    System.out.println("字段名:" + field.getName() + ", 字段值:" + f);
                    break;
                case "double":
                    double d = field.getDouble(bird);
                    System.out.println("字段名:" + field.getName() + ", 字段值:" + d);
                    break;
                case "boolean":
                    boolean bool = field.getBoolean(bird);
                    System.out.println("字段名:" + field.getName() + ", 字段值:" + bool);
                    break;
                case "char":
                    char c = field.getChar(bird);
                    System.out.println("字段名:" + field.getName() + ", 字段值:" + c);
                    break;
                default:
                    Object obj = field.get(bird);
                    System.out.println("字段名:" + field.getName() + ", 字段值:" + obj);
            }
        }
    }
}

class Animal {
    public String name;
}

class Bird extends Animal {
    public byte b;
    public int i;
    public short s;
    public long l;
    public float f;
    public double d;
    public boolean bool;
    public char c;
    public String str;

    // 无参构造器、全参构造器、get和set方法
}
/*打印结果:
    字段名:b, 字段值:1
    字段名:i, 字段值:2
    字段名:s, 字段值:3
    字段名:l, 字段值:4
    字段名:f, 字段值:5.0
    字段名:d, 字段值:6.0
    字段名:bool, 字段值:false
    字段名:c, 字段值:X
    字段名:str, 字段值:text
    字段名:name, 字段值:null
 */

设置成员变量的值

为Field所表示的成员变量设置值的方法如下:

成员方法说明
void setByte(Object obj, byte b)将字段的值设置为指定对象上的一个 byte 值。
void setShort(Object obj, short s)将字段的值设置为指定对象上的一个 short 值。
void setInt(Object obj, int i)将字段的值设置为指定对象上的一个 int 值。
void setLong(Object obj, long l)将字段的值设置为指定对象上的一个 long 值。
void setFloat(Object obj, float f)将字段的值设置为指定对象上的一个 float 值。
void setDouble(Object obj, double d)将字段的值设置为指定对象上的一个 double 值。
void setBoolean(Object obj, boolean z)将字段的值设置为指定对象上的一个 boolean 值。
void setChar(Object obj, char c)将字段的值设置为指定对象上的一个 char 值。
void set(Object obj, Object value)将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

实例如下:

public class Test {
    public static void main(String[] args) throws IllegalAccessException {
        Bird bird = new Bird((byte) 1, 2, (short) 3, 4L, 5.0F, 6.0, false, 'X', "text");
        Class<? extends Bird> birdClass = bird.getClass();
        Field[] fields = birdClass.getFields();

        for (Field field : fields) {
            switch (field.getGenericType().getTypeName()) {
                case "byte":
                    // 设置byte类型的值
                    field.setByte(bird, (byte) 127);
                    break;
                case "short":
                    // 设置short类型的值
                    field.setShort(bird, (short) 128);
                    break;
                case "int":
                    // 设置int类型的值
                    field.setInt(bird, 999);
                    break;
                case "long":
                    // 设置long类型的值
                    field.setLong(bird, 1000L);
                    break;
                case "float":
                    // 设置float类型的值
                    field.setFloat(bird, 95.5F);
                    break;
                case "double":
                    // 设置double类型的值
                    field.setDouble(bird, 99.99);
                    break;
                case "boolean":
                    // 设置boolean类型的值
                    field.setBoolean(bird, true);
                    break;
                case "char":
                    // 设置char类型的值
                    field.setChar(bird, '中');
                    break;
                default:
                    // 以上八种都是基本数据类型的设置,这个方法表示是对引用数据类型值的设置
                    field.set(bird, "引用数据类型值");
            }
        }

        System.out.println(bird);
    }
}

class Animal {
    public String name;
}

class Bird extends Animal {
    public byte b;
    public int i;
    public short s;
    public long l;
    public float f;
    public double d;
    public boolean bool;
    public char c;
    public String str;

    // 无参构造器、全参构造器、get和set方法、toString方法
}
/*打印结果:
    Bird{name='引用数据类型值', b=127, i=999, s=128, l=1000, f=95.5, d=99.99, bool=true, c=中, str='引用数据类型值'}
 */

其他方法

其他还有一些方法,最常用的就是setAccessible和getName方法:

成员方法说明
void setAccessible(boolean flag)使用该方法会取消访问控制检查,一般来说,我们不能对私有字段(private修饰)进行操作,但有的时候我们必须对私有字段进行操作,所以就需要调用该方法。设置为true表示可以访问私有字段。
boolean equals(Object obj)将此Field与指定的对象进行比较。 如果对象相同,则返回 true。 如果两个Field对象由同一个类声明并且具有相同的名称和类型,则它们是相同的。
boolean isEnumConstant()如果此字段表示枚举类型的元素,则返回true ; 否则返回false 。
boolean isSynthetic()如果此字段是合成字段,则返回true ; 否则返回false 。
String getName()返回由此Field对象表示的字段的名称。
String toGenericString()返回描述此Field的字符串,包括其泛型类型。 格式是字段的访问修饰符(如果有),后跟通用字段类型,后跟一个空格,后跟声明该字段的类的完全限定名称,后跟一个句点,然后是该字段的名称。
String toString()返回描述此Field的字符串。 格式是字段的访问修饰符(如果有),后跟字段类型,后跟一个空格,后跟声明该字段的类的完全限定名称,后跟一个句点,后跟该字段的名称。
Annotation[] getAnnotations()获取直接存在此Field上的所有注解。
<T extends Annotation> T getAnnotation(Class<T> annotationClass)如果存在该元素的指定类型的注解,则返回这些注解,否则返回null。
Class<?> getDeclaringClass()返回表示类或接口的Class对象,该类或接口声明了由此Field对象表示的Field 。

实例

下面是一个简单的Field实例,利用实体类对象生成一条插入SQL语句。

public class Test {
    public static void main(String[] args) throws IllegalAccessException {
        User user = new User(3, "王五", "wangwu", "10086", "10086@qq.com", "描述", new Date());
        System.out.println(insertSql(user));
    }

    /**
     * 将一个实体类对象生成插入SQL语句
     *
     * @param obj 实体类对象
     * @return 返回插入SQL语句
     * @throws IllegalAccessException
     */
    public static String insertSql(Object obj) throws IllegalAccessException {
        // 获取实体类对象的Class类对象
        Class<?> aClass = obj.getClass();
        // 获取所有的字段(包括私有字段等)
        Field[] fields = aClass.getDeclaredFields();
        StringBuilder sql = new StringBuilder();
        sql.append("insert into ");
        sql.append(aClass.getSimpleName().toLowerCase());// 获取类名,并且转换为小写字母
        sql.append("(");
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            field.setAccessible(true);
            sql.append(field.getName().toLowerCase());
            if (i != fields.length - 1) {
                sql.append(",");
            }
        }
        sql.append(") values(");
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            // 设置允许访问私有字段
            field.setAccessible(true);
            // 添加值
            if ("java.lang.String".equals(field.getGenericType().getTypeName())) {
                // 对于String类型的值则需要添加单引号
                sql.append("'");
                sql.append(field.get(obj));
                sql.append("'");
            } else {
                sql.append(field.get(obj));
            }
            if (i != fields.length - 1) {
                sql.append(",");
            }
        }
        sql.append(");");
        return sql.toString();
    }
}

class User {
    public int id;
    public String username;
    public String password;
    public String phone;
    private String email;
    public String desc;
    public Date insert_time;

    public User() {
    }

    public User(int id, String username, String password, String phone, String email, String desc, Date insert_time) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.phone = phone;
        this.email = email;
        this.desc = desc;
        this.insert_time = insert_time;
    }
}
/*打印结果:
    insert into user(id,username,password,phone,email,desc,insert_time) values(3,'王五','wangwu','10086','10086@qq.com','描述',Sun Aug 08 19:03:26 CST 2021);
 */

参考链接:

 类似资料: