前言
java反射机制指的是在java运行过程中,对于任意的类都可以知道他的所有属性以及方法,对于任意一个对象都可以任意的调用他的属性和方法,这种动态获取对象信息和动态调用对象方法的功能称为java反射机制,但是反射使用不当会造成很高的成本。
简单实例
反射获取类名称
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package top.crosssoverjie.study; public class Reflect { public static void main(String[] args) { Class<Reflect> c1 = Reflect.class; System.out.println(c1.getName()); Reflect r1 = new Reflect() ; Class<Reflect> c2 = (Class<Reflect>) r1.getClass() ; System.out.println(c2.getName()); try { Class<Reflect> c3 = (Class<Reflect>) Class.forName("top.crosssoverjie.study.Reflect"); System.out.println(c3.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
|
输出结果:
1 2 3
| top.crosssoverjie.study.Reflect top.crosssoverjie.study.Reflect top.crosssoverjie.study.Reflect
|
以上的 c1,c2,c3是完全一样的,他们都有一个统一的名称:叫做Reflect类的类类型。
反射的用处
获取成员方法
1 2
| public Method getDeclaredMethod(String name,Class<?>...parameterTypes) public Method getMethod(String name,Class<?>...parameterTypes)
|
通过反射获取成员方法调用的实例:
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| package top.crosssoverjie.study;
import java.lang.reflect.Method;
public class Person { private String name="crossover" ; private String msg ; public Person(String name, String msg) { this.name = name; this.msg = msg; System.out.println(name+"的描述是"+msg); }
public Person() { super(); }
public void say(String name ,String msg){ System.out.println(name+"说:"+msg); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public static void main(String[] args) { try { Class c1 = Class.forName("top.crosssoverjie.study.Person") ; Object o1 = c1.newInstance() ; Method m1 = c1.getMethod("say", String.class,String.class) ;
Method[] methods = c1.getDeclaredMethods() ;
Method[] methods2 = c1.getMethods() ; for (Method method : methods2) { System.out.println(method.getName()); } } catch (Exception e) { e.printStackTrace(); } } }
|
输出结果:
所以我们只要知道类的全限定名就可以任意的调用里面的方法。
1 2 3 4
| Method[] methods = c1.getDeclaredMethods() ; for(Method m : methods){ System.out.println(m.getName()); }
|
输出结果:
1 2 3 4 5 6
| main getName setName say getMsg setMsg
|
使用的还是之前那个Person类,所以这里只写了关键代码。这里输出的是Person的所有public方法。
如果我们调用getMethods()方法会是什么结果呢?
1 2 3 4
| Method[] methods2 = c1.getMethods() ; for (Method method : methods2) { System.out.println(method.getName()); }
|
输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| main getName setName say getMsg setMsg wait wait wait hashCode getClass equals toString notify notifyAll
|
这时我们会发现这里输出的结果会比刚才多得多,这时因为getMethods()方法返回的是包括父类的所有方法。
获取成员变量
我们还可以通过反射来获取类包括父类的成员变量,主要方法如下:
1 2
| public Field getDeclaredFiled(String name) public Filed getFiled(String name)
|
还是按照之前例子中的Person类举例,他具有两个成员变量:
1 2
| private String name="crossover" ; private String msg ;
|
我们可以通过以下方法来获取其中的成员变量:
1 2
| Class c1 = Class.forName("top.crosssoverjie.study.Person") ; Field field = c1.getDeclaredField("name");
|
通过以下例子可以获取指定对象上此field的值:
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
| package top.crosssoverjie.study;
import java.io.File; import java.lang.reflect.Field;
public class Reflect { public static void main(String[] args) { try { Class c1 = Class.forName("top.crosssoverjie.study.Person"); Field field = c1.getDeclaredField("name") ; Object o1 = c1.newInstance() ;
field.setAccessible(true); Object name = field.get(o1) ; System.out.println(name); } catch (Exception e) { e.printStackTrace() ; }
} }
|
输出结果:
我们也可以通过方法getDeclaredFieds()方法来获取所有的成员变量,返回是是一个Field[]数组,只需要遍历这个数组即可获所有的成员变量。例子如下:
1 2 3 4
| Field[] fields = c1.getDeclaredFields() ; for(Field f :fields){ System.out.println(f.getName()); }
|
输出结果如下:
获取构造方法
可以通过以下两个方法来获取构造方法:
1 2
| public Constructor getDeclaredConstructor(Class<?>...parameterTypes) public Constructor getConstructor(Class<?>...parameterTypes)
|
在之前的Person类中有以下的构造方法:
1 2 3 4
| public Person(String name, String msg) { this.name = name; this.msg = msg; }
|
我们可以通过以下方法来获取Person类的构造方法:
1
| Constructor dc1 = c1.getDeclaredConstructor(String.class,String.class) ;
|
具体代码如下:
1 2 3
| Constructor dc1 = c1.getDeclaredConstructor(String.class,String.class) ; dc1.setAccessible(true); dc1.newInstance("小明","很帅") ;
|
dc1.newInstance("小明","很帅");方法调用了Person类中的:
1 2 3 4 5
| public Person(String name, String msg) { this.name = name; this.msg = msg; System.out.println(name+"的描述是"+msg); }
|
这个构造方法,如果不传参数的话,那么调用的就是无参的构造方法。输出结果为:
通过反射了解集合泛型的本质
通过以下例子程序可以看出:
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 38 39 40 41 42
| package top.crosssoverjie.study;
import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List;
public class GenericEssence { public static void main(String[] args) { List list1 = new ArrayList() ; List<String> list2 = new ArrayList<String>() ; list2.add("你好") ;
System.out.println("list2的长度是:"+list2.size()); Class c1 = list1.getClass(); Class c2 = list2.getClass() ; System.out.print("c1,c2是否相等:"); System.out.println(c1==c2); try { Method method = c2.getDeclaredMethod("add", Object.class) ; method.invoke(list2, 123) ; System.out.println("现在list2的长度是:"+list2.size());
} catch (Exception e) { e.printStackTrace() ; } } }
|
所以可以看出,泛型只是在编译期间起作用,在经过编译进入运行期间是不起作用的。就算是不是泛型要求的类型也是可以插入的。
反射知识点

总结
泛型的应用比较多:
- spring的IOC/DI。
- JDBC中的中的加载驱动
参考