目录
一,基本概念
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
根据虚拟机的工作原理,一般情况下,类需要经过:加载->验证->准备->解析->初始化->使用->卸载这个过程,如果需要反射的类没有在内存中,那么首先会经过加载这个过程,并在在内存中生成一个class对象,有了这个class对象的引用,就可以发挥开发者的想象力,做自己想做的事情了。
- 使用“类对象”来执行反射操作,这里的类对象并不是new出来的对象,而是方法区被加载的类;
- 通过反射可以获得一个类的定义信息;
- 通过反射创建对象;
- 通过反射调用成员变量和方法;
- 获得类对象的三种方式:
- 通过类名.class;
- Class.forName("完整路径的类名")
- a.getClass()
下面通过案例来演示:
public class ToOtherFather { private String s1="1";//私有成员变量 public char c=1;//公有成员变量 public ToOtherFather() {}//私有无参构造函数 public ToOtherFather(String s2) {}//公有有参构造函数 public void method1(float x1,float x2) {}//公有方法 private void method5() {}//私有方法 public void method4() {}//公有方法 }
public class ToOther extends ToOtherFather{ private int x=1;//私有成员变量 public int y=1;//公有成员变量 private float k=2f;//私有成员变量 public double z=1l;//公有成员变量 public ToOther() {}//公有无参构造函数 public ToOther(double y,String s) {}//公有无参构造函数 private ToOther(int x) {}//私有有参构造函数 @Override public void method1(float x1,float x2) { } public void method2(String s) { } private void method3(int x,double y) { } }
public class Test { public static void main(String[] args) { getName();//获取包名类名 System.out.println("----------------------------------------------------------------"); getBianliang();//获取成员变量 System.out.println("----------------------------------------------------------------"); getGouzao();//获取所有构造方法 System.out.println("----------------------------------------------------------------"); getFangfa();//获取所有方法 System.out.println("----------------------------------------------------------------"); } private static void getName() { try { Class<?>sClass=Class.forName("反射.ToOther"); System.out.println(sClass.getName()); System.out.println(sClass.getPackageName()); System.out.println(sClass.getPackage().getName()); System.out.println(sClass.getSimpleName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } private static void getBianliang() { try { Class<?>sClass=Class.forName("反射.ToOther"); Field[]a=sClass.getDeclaredFields();//获取所有成员变量,包括私有,除了继承的变量 Field[]b=sClass.getFields();//获取所有成员变量,包括继承的变量,除了私有 System.out.println("------获取所有成员变量,除了继承的父类变量,包括私有------"); for (Field field : a) { System.out.println("成员类型"+field.getGenericType() +" 成员名称"+field.getName() +" 变量所在类:"+field.getDeclaringClass().getSimpleName()); } System.out.println(); System.out.println("------获取所有成员变量,包括继承父类的变量,除了私有------"); for (Field field : b) { System.out.println("成员类型"+field.getType().getSimpleName() +" 成员名称"+field.getName() +" 变量所在类:"+field.getDeclaringClass().getSimpleName()); } System.out.println(); try { System.out.println("------getField()获取单个成员变量,除了私有成员------"); Field c=sClass.getField("y"); System.out.println(c.getName()); System.out.println("------getDeclaredField()获取单个成员变量,除了私有成员------"); Field d=sClass.getDeclaredField("x"); System.out.println(d.getName()); } catch (Exception e) { e.printStackTrace(); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } private static void getGouzao() { try { Class<?>sClass=Class.forName("反射.ToOther"); System.out.println("------获取所有构造函数,除了私有构造函数------"); Constructor<?>[]a=sClass.getConstructors(); for (Constructor<?> c : a) { Class<?>[]p=c.getParameterTypes();//构造方法参数列表 System.out.println(sClass.getSimpleName()+" "+ Arrays.toString(p) ); } System.out.println(); System.out.println("------获取所有构造函数,包括私有构造函数------"); Constructor<?>[]b=sClass.getDeclaredConstructors(); for (Constructor<?> c : b) { Class<?>[]p=c.getParameterTypes();//构造方法参数列表 System.out.println(sClass.getSimpleName()+" "+ Arrays.toString(p) ); } System.out.println(); System.out.println("------通过参数列表,获取单个构造函数,不包括私有构造函数------"); Constructor s2=sClass.getConstructor(double.class,String.class); Class<?>[]p=s2.getParameterTypes();//构造方法参数列表 System.out.println(sClass.getSimpleName()+" "+ Arrays.toString(p) ); } catch (Exception e) { e.printStackTrace(); } } private static void getFangfa() { try { Class<?>sClass=Class.forName("反射.ToOther"); System.out.println("------获取所有方法,包括父类,除了私有方法------"); Method[]a=sClass.getMethods(); for (Method method : a) { Class<?>[]p=method.getParameterTypes(); System.out.println( method.getName()+" "+ Arrays.toString(p)); } System.out.println(); System.out.println("------获取所有方法,不包括父类,包括私有方法------"); Method[] b=sClass.getDeclaredMethods(); for (Method method : b) { Class<?>[]p=method.getParameterTypes(); System.out.println( method.getName()+" "+ Arrays.toString(p)); } System.out.println(); System.out.println("------获取单个方法------"); Method c=sClass.getMethod("method1", float.class,float.class); Class<?>[]p=c.getParameterTypes(); System.out.println( c.getName()+" "+Arrays.toString(p)); } catch (Exception e) { } } }
打印输出结果:
反射.ToOther 反射 反射 ToOther ---------------------------------------------------------------- ------获取所有成员变量,除了继承的父类变量,包括私有------ 成员类型int 成员名称x 变量所在类:ToOther 成员类型int 成员名称y 变量所在类:ToOther 成员类型float 成员名称k 变量所在类:ToOther 成员类型double 成员名称z 变量所在类:ToOther ------获取所有成员变量,包括继承父类的变量,除了私有------ 成员类型int 成员名称y 变量所在类:ToOther 成员类型double 成员名称z 变量所在类:ToOther 成员类型char 成员名称c 变量所在类:ToOtherFather ------getField()获取单个成员变量,除了私有成员------ y ------getDeclaredField()获取单个成员变量,除了私有成员------ x ---------------------------------------------------------------- ------获取所有构造函数,除了私有构造函数------ ToOther [double, class java.lang.String] ToOther [] ------获取所有构造函数,包括私有构造函数------ ToOther [int] ToOther [double, class java.lang.String] ToOther [] ------通过参数列表,获取单个构造函数,不包括私有构造函数------ ToOther [double, class java.lang.String] ---------------------------------------------------------------- ------获取所有方法,包括父类,除了私有方法------ method1 [float, float] method2 [class java.lang.String] method4 [] wait [long] wait [long, int] wait [] equals [class java.lang.Object] toString [] hashCode [] getClass [] notify [] notifyAll [] ------获取所有方法,不包括父类,包括私有方法------ method1 [float, float] method2 [class java.lang.String] method3 [int, double] ------获取单个方法------ method1 [float, float] ----------------------------------------------------------------
总结:
getDeclaredFields() | 获取所有成员变量,包括私有,除了继承的变量 | ||
getFields() | 获取所有成员变量,包括继承的变量,除了私有 | ||
getDeclaredField("x") | 获取单个成员变量,包括私有成员 | ||
getField("y") | 获取单个成员变量,除了私有成员 | ||
getConstructors() | 获取所有构造函数,除了私有构造函数 | ||
getDeclaredConstructors() | 获取所有构造函数,包括私有构造函数 | ||
getConstructor(double.class,String.class) | 通过参数列表,获取单个构造函数,不包括私有构造函数 | ||
getDeclaredConstructor(double.class,String.class) | 通过参数列表,获取单个构造函数,包括私有构造函数 | ||
getMethods() | 获取所有方法,包括父类,除了私有方法 | ||
getDeclaredMethods() | 获取所有方法,不包括父类,包括私有方法 | ||
getMethod("method1", float.class,float.class) | 获取单个方法 | ||
getDeclaredMethod("method1", float.class,float.class) | 获取单个方法 |
二,通过反射创建对象
- 通过类对象的反射操作来新建对象,但是在java9之后,该方法不建议使用了;
- 通过构造方法的反射操作,来新建对象;
public class Test2 { public static void main(String[] args) { f1();//通过类对象的反射操作,来新建对象 f2();//通过构造方法的反射操作,来新建对象 } private static void f1() { try { Class<?>c=Class.forName("反射.ToOther"); Object o1=c.newInstance();//此方法在java9以后就不建议使用 System.out.println(o1.toString()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } private static void f2() { try { Object o2=null; Class<?>c=Class.forName("反射.ToOther"); o2=c.getConstructor(double.class,String.class).newInstance(11.11,"11.11"); System.out.println(o2.toString()); //如果是私有构造函数,要进行setAccessible,除了允许访问私有,还有允许设置数值创建 Object o3=null; Class<?>c2=Class.forName("反射.ToOther"); Constructor<?>t2=c2.getDeclaredConstructor(int.class); t2.setAccessible(true); o3=t2.newInstance(11); System.out.println(o3.toString()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
打印:
三,通过反射访问成员变量并赋值
public class Test3 { public static void main(String[] args) { ToOther toOther1=new ToOther(); ToOther toOther2=new ToOther(); try { Class<ToOther>c=ToOther.class; //给指定对象的变量赋值 System.out.println(toOther1); Field field=c.getDeclaredField("x"); field.setAccessible(true); field.set(toOther1, 100); System.out.println(toOther1); //如果是静态变量,不用区分是哪个对象的,传null,属于全局 Field field2=c.getDeclaredField("sum"); field2.setAccessible(true); field2.set(null, 100); System.out.println(toOther1); //也可以强转 int sum=(int) field2.get(toOther1); System.out.println(sum); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
打印:
四,通过反射访问方法并赋值
public class Test4 { public static void main(String[] args) { //获取方法,并赋值 ToOther toOther=new ToOther(); try { Class<?>c=Class.forName("反射.ToOther"); Method t1=c.getMethod("setX",int.class); Method t2=c.getMethod("getX"); t1.invoke(toOther, 1000);//通过方法给x赋值 int obj=(int) t2.invoke(toOther); //默认是Object,这里进行了强转 System.out.println(obj); / Method t3=c.getDeclaredMethod("setK", float.class); Method t4=c.getDeclaredMethod("getK"); t3.setAccessible(true); t4.setAccessible(true); t3.invoke(toOther, 1000.33f); Object obj2=t4.invoke(toOther); System.out.println(obj2); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
打印结果