java反射基础

什么是反射 

下面是 jdk8 对反射的一段原话描述:

Reflection allows programmatic access to information about the fields, methods and constructors of loaded classes, and the use of reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.

通过编程方式获取类的字段、方法、构造函数并操作相关的属性。但有以下限制条件:

  1. 必须是已加载的类

  2. 在安全限制范围内

反射的使用

 下面就简述一个在安全范围内对一个已加载的类进行反射操作的demo,5、6、7的例子已经超出了安全范围

/** 反射测试用类 */
public class ForTest {
	public String prop1;
	private String prop2;
	private String prop3 = "prop3";

	public void setProp2(String prop2) {
		this.prop2 = prop2;
	}

	private void setProp3(String prop3) {
		this.prop3 = prop3;
	}
}

ForTest类有三个属性,1个public属性2个private属性,其中prop2属性有一个set方法可以对其进行赋值操作,而prop3没有任何公开方法可以对其设置值。

1、通过反射获取该类构造函数

/**
 * java 反射基础, 基于JDK1.8
 */
public static void main(String[] args) throws Exception {
	// 获取该类的所有构造方法
	Constructor<?>[] cons = ForTest.class.getConstructors();
	for (Constructor<?> next : cons) {
		System.out.println("构造函数:" + next);
	}
	// 调用该类的构造方法初始化一个对象
	Constructor<?> c = cons[0];
	Object inst = c.newInstance();
	System.out.println("通过构造函数初始化对象:" + inst);
}

输出如下:

构造函数:public reflex.ForTest()
通过构造函数初始化对象:reflex.ForTest@15db9742 

2、通过反射获取该类public字段和所有字段

public static void main(String[] args) throws Exception {
	// 获取该类的public字段
	Field[] fs = ForTest.class.getFields();
	for (Field field : fs) {
		System.out.println("public字段:" + field);
	}
	// 获取该类的所有字段
	Field[] fs1 = ForTest.class.getDeclaredFields();
	for (Field field : fs1) {
		System.out.println("所有字段:" + field);
	}
}

输出如下:

public字段:public java.lang.String reflex.ForTest.prop1
所有字段:public java.lang.String reflex.ForTest.prop1
所有字段:private java.lang.String reflex.ForTest.prop2
所有字段:private java.lang.String reflex.ForTest.prop3

3、通过反射获取该类的public方法和所有方法

public static void main(String[] args) throws Exception {
	// 获取该类的public方法
	Method[] m1 = ForTest.class.getMethods();
	for (Method m : m1) {
		System.out.println("public方法:" + m);
	}
	System.out.println("------------------分隔符---------------------------");
	// 获取该类的所有方法
	Method[] m2 = ForTest.class.getDeclaredMethods();
	for (Method m : m2) {
		System.out.println("所有方法:" + m);
	}
}

输出如下: 

public方法:public void reflex.ForTest.setProp2(java.lang.String)
public方法:public final void java.lang.Object.wait() throws java.lang.InterruptedException
public方法:public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public方法:public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public方法:public boolean java.lang.Object.equals(java.lang.Object)
public方法:public java.lang.String java.lang.Object.toString()
public方法:public native int java.lang.Object.hashCode()
public方法:public final native java.lang.Class java.lang.Object.getClass()
public方法:public final native void java.lang.Object.notify()
public方法:public final native void java.lang.Object.notifyAll()
------------------分隔符---------------------------
所有方法:public void reflex.ForTest.setProp2(java.lang.String)
所有方法:private void reflex.ForTest.setProp3(java.lang.String)

注:由于 getMethods会获取父类的public方法,所以这里能直接打印出Object的所有public方法

4、修改对象public字段属性值

public static void main(String[] args) throws Exception {
	// 获取构造函数
	Constructor<?> c = ForTest.class.getConstructors()[0];
	// 实例化一个对象
	ForTest ins = (ForTest) c.newInstance();
	// 输出对象prop1字段的值
	System.out.println("对象prop1属性值:" + ins.prop1);
	// 获取该类的public字段
	Field fs = ForTest.class.getFields()[0];
	// 为ins对象直接设置prop1字段值
	fs.set(ins, "测试值");
	// 再次输出对象prop1字段的值
	System.out.println("对象prop1属性新值:" + ins.prop1);
}

输出如下:

对象prop1属性值:null
对象prop1属性新值:测试值

 5、通过public方法修改对象属性值

public static void main(String[] args) throws Exception {
	// 获取构造函数
	Constructor<?> c = ForTest.class.getConstructors()[0];
	// 实例化一个对象
	ForTest ins = (ForTest) c.newInstance();
	// 获取private字段prop2
	Field fs = ForTest.class.getDeclaredField("prop2");
	// 输出对象prop2字段的值
	fs.setAccessible(true);// 强制可以访问该私有属性,如果没有这段会抛出can not access a member异常
	System.out.println("对象prop2属性值:" + fs.get(ins));
	// 获取该类的public方法setProp2
	Method m = ForTest.class.getDeclaredMethod("setProp2", String.class);
	// 通过public方法setProp2私有字段修改属性值
	m.invoke(ins, "通过public方法setProp2私有字段修改属性值");
	// 再次输出对象prop2字段的值
	System.out.println("对象prop2属性新值:" + fs.get(ins));
}

输出如下:

对象prop2属性值:null
对象prop2属性新值:通过public方法setProp2私有字段修改属性值

 注:这里已经使用了setAccessible(true)方法,强制对象私有属性可以访问。这是很危险的做法,因为可以修改系统中任意类属性值。

6、强制修改对象private属性值 [安全范围内以外]

public static void main(String[] args) throws Exception {
	// 获取构造函数
	Constructor<?> c = ForTest.class.getConstructors()[0];
	// 实例化一个对象
	ForTest ins = (ForTest) c.newInstance();
	// 获取private字段prop3
	Field fs = ForTest.class.getDeclaredField("prop3");
	// 输出对象prop3字段的值
	fs.setAccessible(true);// 强制可以访问该私有属性,如果没有这段会抛出can not access a member异常
	System.out.println("对象prop3属性值:" + fs.get(ins));
	// 1、通过私有字段修改属性值
	fs.set(ins, "通过私有字段修改属性值");
	System.out.println("对象prop3属性新值1:" + fs.get(ins));
	// 获取该类的public方法setprop3
	Method m = ForTest.class.getDeclaredMethod("setProp3", String.class);
	m.setAccessible(true);// 强制可以访问该私有属性,如果没有这段会抛出can not access a member异常
	// 2、通过public方法setprop3私有字段修改属性值
	m.invoke(ins, "通过public方法setprop3私有字段修改属性值");
	// 再次输出对象prop3字段的值
	System.out.println("对象prop3属性新值2:" + fs.get(ins));
}

输出如下:

对象prop3属性值:prop3
对象prop3属性新值1:通过私有字段修改属性值
对象prop3属性新值2:通过public方法setprop3私有字段修改属性值

7、对final修饰的属性进行修改测试

我们先将测试用类修改为如下:

/** 反射测试用类 */
public class ForTest {
	public final String prop3 = "prop3";
}

然后进行如下操作:

public static void main(String[] args) throws Exception {
	// 获取构造函数
	Constructor<?> c = ForTest.class.getConstructors()[0];
	// 实例化一个对象
	ForTest ins = (ForTest) c.newInstance();
	// 获取final字段prop3
	Field fs = ForTest.class.getDeclaredField("prop3");
	// 修改final字段的值
	try {
		fs.set(ins, "修改final字段值");
	} catch (Exception e) {
		System.err.println(e.getMessage());
	}
	// 强制修改final字段值
	fs.setAccessible(true);
	fs.set(ins, "强制修改final字段值");
	System.out.println("对象prop3属性值:" + fs.get(ins));
}

输出如下:

Can not set final java.lang.String field reflex.ForTest.prop3 to java.lang.String
对象prop3属性值:强制修改final字段值

可以看出平时我们认为final修饰的不可变属性都可以通过setAccessible(true)强行修改,所以我们在使用反射写底层代码的时候一定要主要setAccessible(true)的使用。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值