学习任务:

视频学习

认识反射成员变量API

准备环境

测试获取成员变量

测试Field

测试获取成员变量的值

测试设置成员变量的值

通过Class对象的如下方法可获取一个对象的成员变量信息:

// 返回所有公共成员变量对象的数组,包括父类
public Field[] getFields()		
// 返回所有成员变量对象的数组(包含私有的),不包括父类
public Field[] getDeclaredFields()	
// 返回单个公共成员变量对象,包括父类
public Field getField(String name)	
// 返回单个成员变量对象(可以使用私有的),不包括父类
public Field getDeclaredField(String name)	

下边分别测试这些API方法。

本节选用“多态案例”章节的类,包括:基础学生类、普通学生类、vip学生类、课程类等。

/**
 * 
 */
package com.pbteach.javase.oop.reflect2;

/**
 * 学生信息类(基础类)
 * 
 * @author 攀博课堂
 * @version v1.0
 */
public class PbStudent {

	// 学生编号
	public long id;

	// 学生昵称
	private String nickName;
	// 邮箱
	private String email;

	// 头像
	private String pic;
	// 密码
	private String password;
	// 选课列表
	private static PbCourse[] selections;
	

	//学生选课方法
	public void selectCourse(PbCourse course) {
		System.out.println("学生选课");
	}

	//父类的默认构造方法
	public PbStudent() {
		

	}
	
	//自定义的构造方法
	public PbStudent(long id, String nickName, String email) {
		this.id = id;
		this.nickName = nickName;
		this.email = email;
	}

	//getter/setter...
	
}

/**
 * 
 */
package com.pbteach.javase.oop.reflect2;

import java.time.LocalDate;

/**
 * vip学生类
 * 
 * @author 攀博课堂
 * @version v1.0
 */
public class PbStudentVip extends PbStudent {

	// vip服务截止时间
	private LocalDate vipDeadline;
	// vip服务的购买时间
	private LocalDate vipCreateTime;
	// vip专属指导老师
	public String pbteacher;
	// vip专属群
	public String pbgroup;

	public PbStudentVip(long id, String nickName, String email) {
		super(id, nickName, email);
	}

	// 获取学生在攀博课堂的服务内容
	public void getService() {
		System.out.println("=======vip学生======");
		System.out.println("攀博课堂自学Java课程");
		System.out.println("资源下载");
		System.out.println("在线问答交流");
		System.out.println("攀博课堂Vip专属老师指导");
		System.out.println("攀博课堂Vip专属交流群");

	}
	
	//子类扩展了一个和父类完全不一样的方法
	//判断vip账户是否有效
	public boolean isValid() {
		//如果vipDeadline截止时间在当前时间之后则有效
		if(vipDeadline.isAfter(LocalDate.now())) {
			System.out.println("账户有效");
			//账户有效
			return true;
		}
		System.out.println("账户无效");
		//账户无效
		return false;
		
	}
	//获取折扣
	public float getDiscount() {
		//实际企业开发中这里可有会从数据库来获取配置的折扣信息...
		
		return 0.7f;
	}
	//getter/setter

}

package com.pbteach.javase.oop.reflect2;

import java.lang.reflect.Field;

/**
 * Class类测试
 * @author 攀博课堂
 * @version v1.0
 */
public class ReflectTest {

	//测试反射获取成员变量
	public static void test1() throws Exception {
		//获取Class对象
		Class stuVipClass = PbStudentVip.class;
		//获取父类的public成员变量
		Field idField = stuVipClass.getField("id");
		System.out.println(idField);
		//获取本类的public成员变量
		Field pbteacherField = stuVipClass.getField("pbteacher");
		System.out.println(pbteacherField);
		//获取本类的私有成员变量 ,获取本类的public成员变量也可以使用本方法
		Field vipDeadlineField = stuVipClass.getDeclaredField("vipDeadline");
		System.out.println(vipDeadlineField);
		//获取父类的私有成员变量, stuVipClass.getSuperclass()表示获取父类的Class对象
		Field nickNameField = stuVipClass.getSuperclass().getDeclaredField("nickName");
		System.out.println(nickNameField);
		
		//获取包括父类的public成员变量(多个)
		System.out.println("获取包括父类的public成员变量(多个)");
		Field[] publicFields = stuVipClass.getFields();
		for(int i=0;i<publicFields.length;i++) {
			System.out.println(publicFields[i]);
		}
		
		//获取本类所有成员变量(包括私有)
		System.out.println("获取本类所有私有成员变量");
		Field[] declaredFields = stuVipClass.getDeclaredFields();
		for(int i=0;i<declaredFields.length;i++) {
			System.out.println(declaredFields[i]);
		}
		
	}
	public static void main(String[] args) throws Exception {
		test1();
	}
}

输出:

public long com.pbteach.javase.oop.reflect2.PbStudent.id
public java.lang.String com.pbteach.javase.oop.reflect2.PbStudentVip.pbteacher
private java.time.LocalDate com.pbteach.javase.oop.reflect2.PbStudentVip.vipDeadline
private java.lang.String com.pbteach.javase.oop.reflect2.PbStudent.nickName
获取包括父类的public成员变量(多个)
public java.lang.String com.pbteach.javase.oop.reflect2.PbStudentVip.pbteacher
public java.lang.String com.pbteach.javase.oop.reflect2.PbStudentVip.pbgroup
public long com.pbteach.javase.oop.reflect2.PbStudent.id
获取本类所有私有成员变量
private java.time.LocalDate com.pbteach.javase.oop.reflect2.PbStudentVip.vipDeadline
private java.time.LocalDate com.pbteach.javase.oop.reflect2.PbStudentVip.vipCreateTime
public java.lang.String com.pbteach.javase.oop.reflect2.PbStudentVip.pbteacher
public java.lang.String com.pbteach.javase.oop.reflect2.PbStudentVip.pbgroup

Field对象描述了成员变量的信息,包括:成员变量的名称、类型、权限等,测试代码如下:

//测试Field
	public static void test2() throws Exception {
		//获取Class对象
		Class stuVipClass = PbStudentVip.class;
		//获取父类的public成员变量
		Field idField = stuVipClass.getField("id");
		//输出成员变量的信息
		outputField(idField);
	}
	
	private static void outputField(Field field) {
		//获取成员变量的名称
		System.out.println(field.getName());
		//获取成员变量的类型
		System.out.println(field.getType());
		//获取成员变量的修饰符
		System.out.println("获取成员变量的修饰符");
		int modifiers = field.getModifiers();
		System.out.println("private:"+Modifier.isPrivate(modifiers));
		System.out.println("public:"+Modifier.isPublic(modifiers));
		System.out.println("static:"+Modifier.isStatic(modifiers));
		System.out.println("final:"+Modifier.isFinal(modifiers));
		System.out.println("protected:"+Modifier.isProtected(modifiers));
	}
	
	public static void main(String[] args) throws Exception {
		test2();
	}

输出:

id
long
获取成员变量的修饰符
private:false
public:true
static:false
final:false
protected:false

通过Field对象的getXX方法可以获取成员变量的值,方法列表如下:

//返回该所表示的字段的值 Field ,指定的对象上。  
Object get(Object obj) 
//获取静态或实例的值 boolean字段。  
boolean getBoolean(Object obj) 
//获取静态或实例的值 byte字段。  
byte getByte(Object obj) 
//获取类型为 char的静态或实例字段的值,或通过扩大转换获得可转换为类型 char的另一个原始类型的值。
char getChar(Object obj) 
//获取类型为 double的静态或实例字段的值,或通过扩展转换转换为类型 double的另一个基本类型的值。 
double getDouble(Object obj) 
//获取类型为 float的静态或实例字段的值,或通过加宽转换转换为类型 float的另一个基本类型的值。 
float getFloat(Object obj) 
//获取类型为 int的静态或实例字段的值,或通过扩展转换转换为类型 int的另一个原始类型的值。
int getInt(Object obj) 
//获取类型为 long的静态或实例字段的值,或通过扩大转换获得可转换为类型 long的另一个基本类型的值。
long getLong(Object obj) 

测试代码如下:

1、获取public成员变量的值

	//获取public成员变量的值
	public static void test3() throws Exception {
		PbStudentVip pbStudentVip = new PbStudentVip(101L, "攀博", "1759102882@qq.com");
		Class class1 = pbStudentVip.getClass();
		//得到父类的public成员变量
		Field idField = class1.getField("id");
		long id = idField.getLong(pbStudentVip);
		System.out.println(id);
	}

输出:

101

2、获取私有成员变量的值

获取私有成员变量的值需要抑制成员变量权限检查,调用Field的setAccessible(boolean flag)方法,如下:

//将此对象的accessible标志设置为指示的布尔值,true的值表示反射对象应该在使用时抑制Java语言访问检查。 false的值表示强制执行Java语言访问检查。
public void setAccessible(boolean flag)
                   throws SecurityException

注意:setAccessible(true)会受Java安全管理器SecurityManager安全策略的影响,此操作会被拒绝。

测试代码如下:

	//获取私有成员变量的值
	public static void test4() throws Exception {
		PbStudentVip pbStudentVip = new PbStudentVip(101L, "攀博", "1759102882@qq.com");
		Class class1 = pbStudentVip.getClass();
		//得到父类的Class对象
		Class superclass = class1.getSuperclass();
		Field field = superclass.getDeclaredField("nickName");
		//true的值表示反射对象应该在使用时抑制Java语言访问检查
		field.setAccessible(true);
		String nickName = (String) field.get(pbStudentVip);
		System.out.println(nickName);
	}

输出:

攀博

调用Field对象的setXX方法可以给成员变量赋值,如下:

image-20210219110552116

和获取成员变量的值一样,如果给public成员变量设置值可以直接调用这些方法即可完成,如果给私有成员变量赋值则需要调用setAccessible(true)方法抑制成员变量的权限检查。

测试 代码如下:

	//设置成员变量的值
	public static void test5() throws Exception{
		PbStudentVip pbStudentVip = new PbStudentVip(101L, "攀博", "1759102882@qq.com");
		Class class1 = pbStudentVip.getClass();
		Field idField = class1.getField("id");
		//向id赋值
		idField.setLong(pbStudentVip,102L);
		//取值
		System.out.println(idField.get(pbStudentVip));
		System.out.println(pbStudentVip.getId());
		//得到父类的Class对象
		Class superclass = class1.getSuperclass();
		Field nickNameField = superclass.getDeclaredField("nickName");
		//true的值表示反射对象应该在使用时抑制Java语言访问检查
		nickNameField.setAccessible(true);
		nickNameField.set(pbStudentVip, "攀博pbteach.com");
		System.out.println(nickNameField.get(pbStudentVip));
		System.out.println(pbStudentVip.getNickName());
		
	}
提问-攀博课堂
我要提问 不会就问,有效沟通
关注公众号,加入微信群交流提问。 攀博课堂官方公众号
问答列表,查看本知识点所有问题