Java反射Field类的使⽤全⽅位解析
Field 提供有关类或接⼝的单个字段的信息,以及对它的动态访问权限。反射的字段可能是⼀个类(静态)字段或实例字段。Field 成员变量的介绍
每个成员变量有类型和值。
flect.Field 为我们提供了获取当前对象的成员变量的类型,和重新设值的⽅法。
获取变量的类型
类中的变量分为两种类型:基本类型和引⽤类型:
基本类型( 8 种)
整数:byte, short, int, long
浮点数:float, double
字符:char
布尔值:boolean
引⽤类型
所有的引⽤类型都继承⾃ java.lang.Object
类,枚举,数组,接⼝都是引⽤类型
java.io.Serializable 接⼝,基本类型的包装类(⽐如 java.lang.Double)也是引⽤类型
flect.Field 提供了两个⽅法获去变量的类型:
Class<?> getType()
返回⼀个 Class 对象,它标识了此 Field 对象所表⽰字段的声明类型。
Type getGenericType()
返回⼀个 Type 对象,它表⽰此 Field 对象所表⽰字段的声明类型。
骑虎难下的意思
实例:
测试类:
public class A
{
public String id;
protected String name;
int age;
private String x;
int[][] ints;
}
main⽅法:
public class Test
{
/**
* 返回该类所在包的包名字字符串
* @param thisClass ⼀个类的Class对象
* @return 该类的包名字字符串
*/
public static String getThisPackageName(Class<?> thisClass)
{
String Name();
String thispackage=thisClassName.substring(0,thisClassName.lastIndexOf("."));
return thispackage;
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException
{
开心的一天作文Class strClass=Class.forName(getThisPackageName(Test.class)+".A");
//获取类的所有声明的字段
Field[] DeclaredFields();
for (Field field : sField)
{
//获取字段的名字
System.out.printf("Field:%-4s|",Name());
//获取字段的类型的Class类,然后获取规范化的名字
System.out.printf("Type:%-18s|",Type().getCanonicalName());
//获取字段的类型的Type类对象,然后获取类的名字
System.out.printf("GenericType:%-18s|",GenericType().getTypeName());
System.out.println();
}
}
}
运⾏结果:
Field:id |Type:java.lang.String |GenericType:java.lang.String |
Field:name|Type:java.lang.String |GenericType:java.lang.String |
Field:age |Type:int |GenericType:int |
Field:x |Type:java.lang.String |GenericType:java.lang.String |
Field:ints|Type:int[][] |GenericType:int[][] |
可以看到这个两个⽅法都能正确的返回当前字段的类型。这两个⽅法的区别还是在返回类型上getType()⽅法返回的是Class<?>类型的,⽽getGenericType()返回的是Type类型的。
获取成员变量的修饰符
成员变量可以被以下修饰符修饰:
访问权限控制符:public, protected, private
限制只能有⼀个实例的:static
不允许修改的:final
不会被序列化:transient
线程共享数据的⼀致性:volatile
注解
类似获取 Class 的修饰符,我们可以使⽤ Modifiers() ⽅法获取当前成员变量的修饰符。返回 flect.Modifier 中定义的整形值。然后使⽤ String(int mod)解码成字符串实例:获取上⾯的A类的字段的类型和修饰符:
public static void printField(Class<?> class1)
{
// 获取类的所有声明的字段
Field[] sField = DeclaredFields();
for (Field field : sField)
{
真题试卷// 获取字段的名字
System.out.printf("字段:%-4s|", Name());
// 获取字段的类型的Class类,然后获取规范化的名字
System.out.printf("类型:%-18s|",GenericType().getTypeName());
//使⽤Modifiers(),可获取字段的修饰符编码,
//然后再使⽤String(int code),来解码成字字符串
System.out.printf("修饰符:%s", Modifiers()));
System.out.println();
}
}
main⽅法:
public static void main(String[] args) throws ClassNotFoundException,
NoSuchFieldException, SecurityException
{
Class AClass = Class.forName(getThisPackageName(Test.class) + ".A");
printField(AClass);
}
运⾏结果:
字段:id |类型:java.lang.String |修饰符:public
字段:name|类型:java.lang.String |修饰符:protected
字段:age |类型:int |修饰符:
字段:x |类型:java.lang.String |修饰符:private
字段:ints|类型:int[][] |修饰符:
由于 Field 间接继承了 flect.AnnotatedElement ,因此运⾏时也可以获得修饰成员变量的注解,当然前提是这个注解被 java.lang.annotation.RetentionPolicy.RUNTIME 修饰。
获取和修改成员变量的值
拿到⼀个对象后,我们可以在运⾏时修改它的成员变量的值,对运⾏时来说,反射修改变量值的操作和类中修改变量的结果是⼀样的。
1.基本类型的获取⽅法:
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 类型的基本类型的静态或实例字段的值。
2.基本类型的tter⽅法:
void tByte(Object obj, byte b)
将字段的值设置为指定对象上的⼀个 byte 值。
void tShort(Object obj, short s)
将字段的值设置为指定对象上的⼀个 short 值。
void tInt(Object obj, int i)
将字段的值设置为指定对象上的⼀个 int 值。
void tLong(Object obj, long l)
将字段的值设置为指定对象上的⼀个 long 值。
void tFloat(Object obj, float f)
将字段的值设置为指定对象上的⼀个 float 值。
void tDouble(Object obj, double d)
将字段的值设置为指定对象上的⼀个 double 值。
void tBoolean(Object obj, boolean z)
将字段的值设置为指定对象上的⼀个 boolean 值。
void tChar(Object obj, char c)
将字段的值设置为指定对象上的⼀个 char 值。
3.引⽤类型的getters⽅法:
Object get(Object obj)
返回指定对象上此 Field 表⽰的字段的值。
4.引⽤类型的tters⽅法:
void t(Object obj, Object value)
将指定对象变量上此 Field 对象表⽰的字段设置为指定的新值。
实例:
(1)基本类型的获取和修改:
测试类:
public class C
{
private int a;
private double d;蒸糯米饭
private boolean flag;
@Override
public String toString()
{
return "C [a=" + a + ", d=" + d + ", flag=" + flag + "]";
}
public C(int a, double d, boolean flag)
{
super();
this.a = a;
this.d = d;
this.flag = flag;
}
public int getA()
{
return a;
}
public void tA(int a)
{
this.a = a;
}
public double getD()
{
return d;
文明家庭主要事迹
}
public void tD(double d)
{
this.d = d;
}
public boolean isFlag()
{
return flag;
}
public void tFlag(boolean flag)
{
this.flag = flag;
}
}
main⽅法类:
import flect.Field;
public class TestGetSetBa
{
public static void main(String[] args)
throws IllegalArgumentException, IllegalAccessException
{
C c = new C(10, 123.456, true);
System.out.println("c对象的值:");
System.out.println(c);
System.out.println("-------------------------------");
Class cClass = c.getClass();
/
/ 获取所有的字段
Field[] cFields = DeclaredFields();
for (Field field : cFields)
{
field.tAccessible(true);
一个人绝望到死的句子System.out.println("获取到字段:" + Type().getCanonicalName() + ",值:" + (c));
}
for (Field field : cFields)
{
if (Type().getCanonicalName() == "int")
{
field.tInt(c, 30);
} el if (Type().getCanonicalName() == "double")
{
field.tDouble(c, 6789.9901);
} el if (Type().getCanonicalName() == "boolean")
{
field.tBoolean(c, fal);
}
// System.out.Type().getCanonicalName());
}
System.out.println("-------------------------------");
System.out.println("现在的c对象的值:");
System.out.println(c);
}
}
运⾏结果:
c对象的值:
C [a=10, d=123.456, flag=true]
王羲之吃墨-------------------------------
获取到字段:int,值:10
获取到字段:double,值:123.456
获取到字段:boolean,值:true
-
------------------------------
制作一份个人简历
现在的c对象的值:
C [a=30, d=6789.9901, flag=fal]
(2)引⽤类型的获取和修改
测试类:
public class B
{
private String id;
private String Name;
public B(String id, String name)
{
super();
this.id = id;
Name = name;
}
public B(){}
@Override
public String toString()
{
return "B [id=" + id + ", Name=" + Name + "]";
}
public String getId()
{
return id;
}
public void tId(String id)
{
this.id = id;
}
public String getName()
{
return Name;
}
public void tName(String name)
{
Name = name;
}
}
这⾥测试的类B的字段都是private类型的,在外部类是⽆法直接访问到这些成员属性的,想要获取和修改只能通过B类的getters和tters⽅法进⾏。使⽤反射我可以绕过这些限制,因为是私有类型的要使⽤ Field.tAccessible(true); ⽅法解除限制main⽅法类:
import flect.Field;
public class TestGetSet
{
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException
{
B b=new B("B1000","⼩明");