概述
什么是反射
下面是 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.
通过编程方式获取类的字段、方法、构造函数并操作相关的属性。但有以下限制条件:
-
必须是已加载的类
-
在安全限制范围内
反射的使用
下面就简述一个在安全范围内对一个已加载的类进行反射操作的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)的使用。
最后
以上就是自然电话为你收集整理的java反射基础的全部内容,希望文章能够帮你解决java反射基础所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复