写这篇文章的初衷还是为了对自己学习的一些知识做一个小小的总结,以前知道反射,但是由于平常不常用,了解的也不透彻,所以借着这两天的时间专门巩固学习了一下java反射的原理知识。以对自己学习之后的一个自我检查和练习。
反射相关内容:
反射是什么?官方文档描述:
Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.
翻译:反射是常用的程序需要能够检查或修改Java虚拟机中运行的应用程序的运行时行为。这是一个相对先进的功能和应使用只有开发人员有很强的把握语言的基础。记住,警告,反射是一种强大的技术,可以使应用程序执行操作,否则是不可能的。
理解:反射功能很强大,能够在程序运行时修改程序行为。反射为非常规手段,有风险,应谨慎使用。
反射入口
1、Class
Class首字母为大写,不同于class,class代表声明一个类;Class本身是一个类。
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement{}
2、获取Class有三种方法:Object.class; object.getClass(); Class.forName("name");
public class OneClass {
public void start() {
TwoClass twoClass = new TwoClass();
Class mClass = TwoClass.class;
LogUtil.logMessage(".class====" + mClass);
Class mClass2 = twoClass.getClass();
LogUtil.logMessage("getClass()====" + mClass2);
try {
Class mClass3 = Class.forName("com.wtt00.testdemopj.TwoClass");
LogUtil.logMessage("Class.forName()====" + mClass3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
打印结果为:
.class====class com.wtt00.testdemopj.TwoClass
getClass()====class com.wtt00.testdemopj.TwoClass
Class.forName()====class com.wtt00.testdemopj.TwoClass
反射的名字
1、Class获取Name:
String name = mClass.getName();//正常名称
LogUtil.logMessage("name---"+name);
String simpleName = mClass.getSimpleName();//简单名称
LogUtil.logMessage("simpleName---"+simpleName);
String canonicalName = mClass.getCanonicalName();//官方名称,如没有官方名称返回null;
LogUtil.logMessage("canonicalName---"+canonicalName);
打印结果为:
name===com.wtt00.testdemopj.TwoClass
simpleName===TwoClass
canonicalName===com.wtt00testdemopj.TwoClass
反射中的成员
1、成员包括属性Field、方法Method、构造器Constuctor;
反射中的Field
1、创建类,声明属性:
public class TwoClass {
public int one = 3;
private int two = 6;
public void oneMethod() {
LogUtil.logMessage("this is public one method");
}
public void oneMethod(int one) {
this.one = one;
}
private void twoMethod() {
LogUtil.logMessage("this is private two method");
}
private void twoMethod(int two) {
this.two = two;
}
public int getOne() {
return one;
}
public void setOne(int one) {
this.one = one;
}
public int getTwo() {
return two;
}
public void setTwo(int two) {
this.two = two;
}
}
try {
Field field=mClass.getField("one");
LogUtil.logMessage("getField()===="+field);
Field field1=mClass.getDeclaredField("one");
LogUtil.logMessage("getDeclaredField()===="+field1);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
打印结果为:
getField()====public int com.wtt00.testdemopj.TwoClass.one
getDeclaredField()====public int com.wtt00.testdemopj.TwoClass.one
try {
Field field=mClass.getField("two");
LogUtil.logMessage("getField()===="+field);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
抛异常:
java.lang.NoSuchFieldException: two
try {
Field field1=mClass.getDeclaredField("two");
LogUtil.logMessage("getDeclaredField()===="+field1);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
打印结果为:
getDeclaredField()====private int com.wtt00.testdemopj.TwoClass.two
为什么获取同样的参数报异常了呢?因为
getField(String name)方法只能获取public修饰的属性
getDeclaredField(String name)方法获取非public修饰的所有属性
public class ThreeClass extends TwoClass {//继承TwoClass
public int three = 7;
private int three2 = 8;
}
Field[] fields=mClass.getFields();
for (Field field : fields) {
LogUtil.logMessage("fields==="+field.getName());
}
打印结果:
fields===three
fields===one
Field[] fields1=threeC.getDeclaredFields();
for (Field field : fields1) {
LogUtil.logMessage("fields1==="+field.getName());
}
打印结果:
fields1===three
fields1===three2
getFields()获取的所有public属性,包括super类中的public;
getDeclaredFields()获取了当前类中的所有属性,获取不到super类中的属性;
2、修改属性值:
try {
//获取类对象
TwoClass twoCl= (TwoClass) mClass.newInstance();
LogUtil.logMessage("one========="+twoCl.getOne());
//修改属性值
Field field =mClass.getField("one");
field.set(twoCl,1222);
LogUtil.logMessage("updata one========="+twoCl.getOne());
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
打印结果
one=========3
updata one=========1222
反射中的Method
1、反射中的Method获取及调用是核心的地方,很多时候主要都是为了调用某个类中的某个功能的方法,
/*get method*/
try {
//public 无参数方法
Method method = mClass.getMethod("oneMethod", null);
LogUtil.logMessage("method===" + method);
//public 有参数方法
Method method1 = mClass.getMethod("oneMethod", int.class);
LogUtil.logMessage("method1===" + method1);
//private 无参数方法
Method method2 = mClass.getMethod("twoMethod", null);
LogUtil.logMessage("method2===" + method2);
//private 有参数方法
Method method3 = mClass.getMethod("twoMethod", int.class);
LogUtil.logMessage("method3===" + method3);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
打印结果:
method===public void com.wtt00.testdemopj.TwoClass.oneMethod()
method1===public void com.wtt00.testdemopj.TwoClass.oneMethod(int)
抛异常:
java.lang.NoSuchMethodException: twoMethod []
为什么会抛异常呢,原因同属性一样;
getMethod(String name, Class<?>... parameterTypes)只能获取public修饰的方法
try {
Method method4 = mClass.getDeclaredMethod("oneMethod",null);
LogUtil.logMessage("method4===" + method4);
Method method5=mClass.getDeclaredMethod("twoMethod", null);
LogUtil.logMessage("method5===" + method5);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
打印结果:
method4===public void com.wtt00.testdemopj.TwoClass.oneMethod()
method5===private void com.wtt00.testdemopj.TwoClass.twoMethod()
getDeclaredMethod(String name, Class<?>... parameterTypes) 获取任意的方法
获取所有方法
Method[] methods=mClass.getMethods();
for (Method method : methods) {
LogUtil.logMessage("方法:==="+method);
}
Method[] methods1=mClass.getDeclaredMethods();
for (Method method : methods1) {
LogUtil.logMessage("方法:***"+method);
}
调用方法,主要调用方法的
//当前类对象,参数类型
public native Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
try {
//获取类对象
TwoClass twoClass1= (TwoClass) mClass.newInstance();
//public 无参数方法
Method method = mClass.getMethod("oneMethod", null);
method.setAccessible(true);//不调用setAccessible(true)会抛异常,无法访问
method.invoke(twoClass1);
//public 有参数方法
Method method1 = mClass.getMethod("oneMethod", int.class);
method1.setAccessible(true);
method1.invoke(twoClass1,88);
//private 无参数方法
Method method5=mClass.getDeclaredMethod("twoMethod", null);
method5.setAccessible(true);
method5.invoke(twoClass1);
//private 有参数方法
Method method6=mClass.getDeclaredMethod("twoMethod", int.class);
method6.setAccessible(true);
method6.invoke(twoClass1,99);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
调用方法,抛异常:
java.lang.IllegalArgumentException
解决方法:调用
method.setAccessible(true);
打印结果:
this is public one method
this is public one method,one===88
this is private two method
this is public one method,two===99
反射中的Constructor
1、获取构造方法
/*反射中的Constructor*/
try {
Constructor constructor=mClass.getConstructor(null);
LogUtil.logMessage("***constructor==="+constructor);
Constructor constructor2=mClass.getConstructor(int.class);
LogUtil.logMessage("***constructor2==="+constructor2);
Constructor constructor1=mClass.getDeclaredConstructor(null);
LogUtil.logMessage("***constructor1==="+constructor1);
Constructor[] constructors=mClass.getConstructors();
for (Constructor constructor3 : constructors) {
LogUtil.logMessage("***constructors==="+constructor3);
}
Constructor[] constructors1=mClass.getDeclaredConstructors();
for (Constructor constructor3 : constructors1) {
LogUtil.logMessage("***constructors==="+constructor3);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
反射中的数组
1、获取反射中的数组类型
/*创建类*/
public class Shuzu {
public int[] shuzu={0,1,2};
public int[] getShuzu() {
return shuzu;
}
public void setShuzu(int[] shuzu) {
this.shuzu = shuzu;
}
}
/*反射中的数组*/
Class shuzuCl=Shuzu.class;
Field[] shuzu=shuzuCl.getFields();
for (Field f : shuzu) {
Class type= f.getType();
if(type.isArray()){
LogUtil.logMessage("Type is "+type.getName());
LogUtil.logMessage("ComponentType type is :"+type.getComponentType());
}
}
打印结果:
Type is [I
ComponentType type is :int
动态创建数组:
public static Object newInstance(Class<?> componentType, int... dimensions)
throws IllegalArgumentException, NegativeArraySizeException {}
try {
Shuzu shu = (Shuzu) shuzuCl.newInstance();
Field sh = shuzuCl.getField("shuzu");
sh.setAccessible(true);
/*数组相关的主要类Array*/
Object obj = Array.newInstance(int.class, 3);
Array.set(obj, 0, 55);
Array.set(obj, 1, 66);
Array.set(obj, 2, 77);
sh.set(shu, obj);
int[] s = shu.getShuzu();
for (int i = 0; i < s.length; i++) {
LogUtil.logMessage("i=====" + i + "value====" + s[i]);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
打印结果
i=====0value====55
i=====1value====66
i=====2value====77
反射中的枚举Enum
/*创建枚举类*/
public enum FourClass {
ONE,
TWO,
THREE,
test0();
int test1() {
return 0;
}
}
public class Meiju {
public FourClass fourClass=FourClass.ONE;
public FourClass getFourClass() {
return fourClass;
}
public void setFourClass(FourClass fourClass) {
this.fourClass = fourClass;
}
}
/*反射中的Enum*/
Class enumCl = FourClass.class;
if (enumCl.isEnum()) {
LogUtil.logMessage(enumCl.getSimpleName() + " is Enum");
//获取field
Field[] fields2=enumCl.getFields();
for (Field field : fields2) {
LogUtil.logMessage("==="+field.getName());
}
}
打印结果:
FourClass is Enum
===ONE
===THREE
===TWO
===test0
try {
Class mClass3=Meiju.class;
Meiju meiju=new Meiju();
Field field=mClass3.getField("fourClass");
FourClass fourClass= (FourClass) field.get(meiju);
LogUtil.logMessage("current==="+fourClass);
field.set(meiju,FourClass.THREE);
LogUtil.logMessage("updata==="+meiju.getFourClass());
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
打印结果:
current===ONE
updata===THREE
反射基本相关原理知识大概差不多了,可以自己去自己的项目中,进行实战练习。
总结
1、学习理论知识的同时,必须实践一遍才能加深理解和掌握。
2、通过 Class.newInstance() 和 Constructor.newInstance() 都可以创建类的对象实例,但推荐后者。因为它适应于任何构造方法,而前者只会调用可见的无参数的构造方法。
3、数组和枚举可以被看成普通的 Class 对待。
4、可以根据API去选择合适的方法。
5、在运用过程中,可能会出现不同的问题,在这推荐篇文章,可以借鉴一下编写反射代码值得注意的诸多细节
上述所写的都是自己亲手敲的,目的是为了让自己加深理解,也是对自己学习一个技术点的小小记录和总结,也希望可以帮到跟我一样的朋友,哈哈😄,在这里特别感谢这个博主的文章(点击了解详情)很详细,也借鉴了此博客中的书写方式,有哪里写的不对的地方,欢迎大家提出。
完结打卡ing。。。
网友评论