一个类有多个组成部分,例如:成员变量,方法,构造方法等。反射就是加载类,并解剖出类的各个组成部分
反射技术用在哪里?在做框架时反射是一门不可或缺的技术。经常在配置文件中获取一个类的完整名称字符串,再创建出该类对象使用
要解剖一个类,首先就要得到这个类,加载这个类
Java中有个Class类用于代表某一个类的字节码
Class类既然代表某个类的字节码,它当然要提供加载某个类字节码的方法:forname().forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装
下面是加载类的三种方式:
1
2
3
4
5
6
7
8
9
10 |
//加载类的三种方式 // @Test public void addClass() throws
Exception{ //方式一: Class<Person1> clazz1 = (Class<Person1>) Class.forName( "peng.Demo.Person1" ); //方式二: Class<Person1> clazz2 = Person1. class ; //方式三: Class<Person1> clazz3 = (Class<Person1>) new
Person1().getClass(); } |
加载类后,如果要new出类对象,要需要解剖出构造方法
反射构造方法:
//反射构造函数 @Test public void reflectCon() throws Exception{ Class<Person1> clazz = (Class<Person1>) Class.forName("peng.Demo.Person1"); //无参的构造函数 /*Constructor<Person1> con = clazz.getConstructor(null); Person1 p = con.newInstance(null); System.out.println(p.name);*/ //另外一个new出对象的方法,只能new无参的构造函数 Person1 per = clazz.newInstance(); // //反射出带参的构造函数 // Constructor con = clazz.getConstructor(String.class,int.class); // Person1 pp = (Person1) con.newInstance("啦啦啦",123455); //反射出私有的构造函数 Constructor con = clazz.getDeclaredConstructor(List.class); //暴力破解 con.setAccessible(true); Person1 person = (Person1) con.newInstance(new ArrayList()); }
反射类字段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 |
//反射字段:public String name = "aaa" @Test public void test01() throws
Exception{ //加载类 Class clazz = Class.forName( "peng.Demo.Person1" ); Field field = clazz.getField( "name" ); Person1 p = (Person1) clazz.newInstance(); //获取字段类型 Class type = field.getType(); if (type.equals(String. class )){ System.out.println(field.get(p)); } //设置字段 field.set(p, "哈哈哈哈" ); System.out.println(p.name); } //反射字段:private int age = 14 @Test public
void test02() throws
Exception{ Class clazz = Class.forName( "peng.Demo.Person1" ); Field field = clazz.getDeclaredField( "age" ); Person1 p = (Person1) clazz.newInstance(); //获取访问权限 field.setAccessible( true ); System.out.println(field.get(p)); field.set(p, 123 ); System.out.println(field.get(p)); } //反射字段:public static double dou = 12.21 @Test public
void test03() throws
Exception, SecurityException{ Class clazz = Class.forName( "peng.Demo.Person1" ); Field field = clazz.getField( "dou" ); Person1 p = (Person1) clazz.newInstance(); System.out.println(field.get(p)); } |
反射出类方法:
//反射:public void demo() @Test public void test1() throws ClassNotFoundException, Throwable, SecurityException{ Class clazz = Class.forName("peng.Demo.Person1"); Person1 p = (Person1) clazz.newInstance(); Method method = clazz.getMethod("demo", null); method.invoke(p, null); } //反射:public void demo(String name,int password) @Test public void test2() throws Exception{ Class clazz = Class.forName("peng.Demo.Person1"); Person1 p = (Person1) clazz.newInstance(); Method method = clazz.getMethod("demo", String.class,int.class); method.invoke(p, "哈哈哈",1233); } //反射:public Class[] demo(String name) @Test public void test3() throws Exception{ Class clazz = Class.forName("peng.Demo.Person1"); Person1 p = (Person1) clazz.newInstance(); Method method = clazz.getMethod("demo", String.class); Class[] cls = (Class[]) method.invoke(p, "haha"); System.out.println(cls[0]); } //反射: private void demo(int password) @Test public void test4() throws Exception{ Class clazz = Class.forName("peng.Demo.Person1"); Person1 p = (Person1) clazz.newInstance(); Method method = clazz.getDeclaredMethod("demo", int.class); method.setAccessible(true); method.invoke(p, 11); } @Test //反射:public static void demo(List list) public void test5() throws Exception{ Class clazz = Class.forName("peng.Demo.Person1"); Person1 p = (Person1) clazz.newInstance(); Method method = clazz.getMethod("demo", List.class); method.invoke(p, new ArrayList()); //其实直接通过类名访问即可 }
反射main方法:
@Test public void test7() throws Exception{ Class clazz = Class.forName("peng.Demo.Person1"); Person1 p = (Person1) clazz.newInstance(); Method method = clazz.getMethod("main", String[].class); // method.invoke(p, (Object)new String[]{"1","2"}); //这样也行 method.invoke(p, new Object[]{new String[]{"1","2"}}); }
为什么要这么写?
在JDK1.4时,invoke()方法时这样的 invoke(Object obj,Object[] os);
当调用的方法有多个参数时,将多个参数写在一个数组中送给invoke,在调用方法时,会将该数组的参数打散,根据这些数组参数找到相对应的方法执行
在JDK1.5后,可变参数出现了,在使用invoke时,可以直接写多个参数 invoke(Object obj ,Obj...o);
为了向下兼容,如果你传递给invoke不是可变参数而是一个Object数组的话,仍旧会按照JDK1.4那样将数组打散
我们可以把数组强转为Object,这样就不会打散了,也可以在外面再嵌套一个数组,这样打散后里面的数组就能正常成为参数正常进行调用了
注意:只有Object数组才会打散,基本数据类型数组是不会的
原文:http://www.cnblogs.com/ZePeng/p/3595253.html