Java中反射详解
阅读目录
- java反射api
- 通过反射创建实例对象
- 通过反射调用私有方法
- 关于javap工具
- 参考资料
java反射api
java反射指的是在运行状态时,能够获取类的属性和方法或者修改类运行时行为的过程。
java.lang.class类提供了很多方法用于获取元数据、检查和改变类运行时的行为。
java的反射主要涉及java.lang和java.lang.reflect包下的类。
反射应用场景举例
- ide, 如eclipse、myeclipse、netbeans等;
- 调试器;
- 测试工具等;
- 各大框架、spring、hibernate等;
java.lang.class类
java.lang.class主要提供了以下两个功能:
- 提供方法用于访问运行期间类的元数据;
- 提供方法用于检查和修改类的运行时行为;
java.lang.class类常用方法
method | description |
---|---|
1) public string getname() | 返回类名 |
2) public static class forname(string classname)throws classnotfoundexception | 加载类并返回class对象 |
3) public object newinstance()throws instantiationexception,illegalaccessexception | 创建实例对象 |
4) public boolean isinterface() | 判断是否是接口 |
5) public boolean isarray() | 判断是否是数组 |
6) public boolean isprimitive() | 判断是否是原始数据类型 |
7) public class getsuperclass() | 返回父类class引用 |
8) public field[] getdeclaredfields()throws securityexception | 返回类的成员属性字段数组 |
9) public method[] getdeclaredmethods()throws securityexception | 返回类的方法数组 |
10) public constructor[] getdeclaredconstructors()throws securityexception | 返回类的构造方法数组 |
11) public method getdeclaredmethod(string name,class[] parametertypes)throws nosuchmethodexception,securityexception | 返回类中指定参数类型的方法 |
怎样获取class对象
有三种方式,如下:
- class类的forname()方法,动态加载,运行时,开始装入类, 并做类的静态初始化
- 对象的getclass()方法,静态加载(编译时已加载)
- .class语法, 静态加载(编译时已加载)
forname()方法示例
可用于动态加载,当你知道类的全限定名时,可以使用该方式。注意原始数据类型不适用该方法;
package tmp; class simple { } public class test { public static void main(string args[]) throws classnotfoundexception { class<?> c = class.forname("tmp.simple"); system.out.println(c.getname()); system.out.println(c.getsimplename()); } }
tmp.simple simple
getclass()方法示例:
从实例对象中获取class对象
package tmp; class simple { } public class test { void printname(object obj) { } public static void main(string args[]) { simple s = new simple(); class<? extends object> c = s.getclass(); system.out.println(c.getname()); system.out.println(c.getsimplename()); } }
tmp.simple simple
.class语法示例
作用于类名上,也可应用于原始数据类型,如下所示:
package tmp; public class test { public static void main(string args[]) { class<boolean> c = boolean.class; system.out.println(c.getname()); class<test> c2 = test.class; system.out.println(c2.getname()); } }
boolean tmp.test
判断class对象对应的类型
以下方法可用于判断class对象对应的类型:
1) public boolean isinterface(): 是否对应接口 |
2) public boolean isarray(): 是否对应数组 |
3) public boolean isprimitive(): 是否对应原始数据类型 |
代码示例:
package tmp; class simple { } interface my { } public class test { public static void main(string args[]) { try { class<?> c = class.forname("tmp.simple"); system.out.println(c.isinterface()); class<?> c2 = class.forname("tmp.my"); system.out.println(c2.isinterface()); } catch (exception e) { system.out.println(e); } } }
false true
通过反射创建实例对象
有两种方式,如下:
- 通过class对象的newinstance()方法创建,这种方式只能调用无参构造方法;
- 通过constructor对象的newinstance()方法创建,这种方式适用于有参构造方法,并且还可以破坏单例模式,调用私有构造方法;
所以,通常来讲,第二种方式比第一种使用范围更广。
class对象调用newinstance()方法示例
package tmp; class simple { void message() { system.out.println("hello java"); } } public class test { public static void main(string args[]) { try { class<?> c = class.forname("tmp.simple"); simple s = (simple) c.newinstance(); s.message(); } catch (exception e) { system.out.println(e); } } }
hello java
constructor对象调用newinstance()方法示例
注意这里可以根据传入参数的类型来得到指定的构造方法,还可以改变构造方法的访问权限限制。
package tmp; import java.lang.reflect.constructor; class simple { private string msg; void message() { system.out.println("hello java," + msg); } private simple(string s){ this.msg = s; } } public class test { public static void main(string args[]) { try { class<?> c = class.forname("tmp.simple"); constructor<?> con = c.getdeclaredconstructor(string.class); con.setaccessible(true); simple s = (simple) con.newinstance("..."); s.message(); } catch (exception e) { system.out.println(e); } } }
hello java,...
通过反射调用私有方法
通过反射,我们可以调用其它类的私有方法,主要涉及java.lang.class和java.lang.reflect.method类;
其中主要是用到了method类的setaccessible方法和invoke方法,前者修改访问权限,后者调用方法。
通过调用有参私有方法示例:
package tmp; import java.lang.reflect.method; class a { private void cube(int n) { system.out.println(n * n * n); } } class test { public static void main(string args[]) throws exception { class<a> c = a.class; object obj = c.newinstance(); method m = c.getdeclaredmethod("cube", new class[]{ int.class }); m.setaccessible(true); m.invoke(obj, 4); } }
关于javap工具
使用javap命令可以反汇编java的字节码文件,展示class文件中的字段属性、构造方法、普通方法信息;
使用说明:
javap java.lang.object示例
javap -c test示例:
写个简单的test类,如下:
package tmp; class simple { } public class test { public static void main(string args[]) { system.out.println("hello"); } }
输入javap -c test:
参考资料
基本属于翻译,做了小部分修改
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!