前言 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中的中的加载驱动
参考