1、Java 反射(Reflection)使用场景
反射在以下情况下很有用:
1)需要访问Jar包数据中的注解时。
2)检查和实例化jar包中的类型。
3)在运行时构建新类型。
4)编译时根本无法预知该对象的类型,程序只能依靠运行时来发现对象和类的具体信息
5)执行后期绑定,访问在运行时创建的类型上的方法。可以动态调用执行方法。
6)可以动态生成类框架,如Gson。
7)Tomcat服务器是典型的反射机制应用
2、Java 反射(Reflection)的使用
1)获取Class对象
通过Java代码获取Class对象有四种方法,具体如下,
import java.util.*; public class Main { public static void main(String[] args) throws Exception { Class<?> class1 = null; Class<?> class2 = null; Class<?> class3 = null; Class<?> class4 = null; //调用Class的静态方法:forName(全类名) class1 = Class.forName("java.util.Date"); //通过运行时类的对象的getClass方法 class2 = new java.util.Date().getClass(); //调用运行时类的属性 class3 = java.util.Date.class; //ClassLoader中的loadClass(全类名)方式获取 ClassLoader classLoader = Main.class.getClassLoader(); class4 = classLoader.loadClass("java.util.Date"); System.out.println(class4); System.out.println("类名称 " + class1.getName()); System.out.println("类名称 " + class2.getName()); System.out.println("类名称 " + class3.getName()); System.out.println("类名称 " + class4.getName()); System.exit(0); //success } }
2)9个预定义Class对象
byte
,short
,int
,long
,char
,float
,double
,boolean
和void
关键字,都有class
属性。例如,
int.class; boolean.class;
int
的包装类是Integer
,Integer
和 int
不是同一种数据类型,8个基本数据类型的包装类中都有一个常量TYPE
,TYPE
表示的是该包装类对应的基本数据类型的Class
对象,
Integer.TYPE == int.class;//true Integer.TYPE != Integer.class;//true
3)获取类中的构造器
获取所有公有构造器:Class对象的getDeclaredConstructors();
获取所有构造器:Class对象的getDeclaredConstructors();
获取单个公有无参构造器:Class对象的getConstructor(null);
获取单个指定公有构造器:Class对象的getConstructor(String.class);
获取单个指定构造器:Class对象的getDeclaredConstructor(String.class);
4)获取成员变量的方法
方法 | 描述 |
Field[] getFields() | 获取当前Class所表示类的所有public字段。 |
Field[] getDeclaredFields() | 获取当前Class所表示类的所有字段, 包括:private、protected、默认、public。 |
public Field getField(String fieldName) | 获取当前Class所表示类指定的public字段。 |
public Field getDeclaredField(String fieldName) | 获取当前Class所表示类的指定字段 (可以为private) |
public void set(Object obj,Object value) | 参数 obj:要设置的字段所在的对象, value:要为字段设置的值 |
5)获取类中的成员方法
方法 | 描述 |
public Method[] getMethods() | 获取当前Class所表示类和继承的所有public方法(包含了父类的方法也包含Object类)。 |
public Method[] getDeclaredMethods() | 获取当前Class所表示类的所有成员方法,包括私有的(不包括继承的,和访问权限无关)。 |
public Method getMethod (String name, Class... parameterTypes) | 获取当前Class所表示类的指定的public方法(包括继承的)。 |
public Method getDeclaredMethod (String methodName, Class... parameterTypes) | 获取当前Class所表示类的指定的成员方法(不包括继承的)。 参数 methodName:方法名, Class ... parameterTypes:形参的Class类型对象 |
6)调用执行方法
public Object invoke(Object obj,Object ... args)
:参数 obj:要调用方法的对象,args:调用方法时所传递的实参。
使用示例:
import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class Main{ public static void main(String[] args) throws Exception { Sample s=new Sample(); s.setProp1("cjavapy.com"); s.setProp2(100); Class clazz=Sample.class;//获取Class对象 String clazzName=clazz.getName();//获取类名,含包名 String clazzSimpleName=clazz.getSimpleName();//获取类名,不含包名 System.out.println("getName:"+clazzName+"\tgetSimpleName:"+clazzSimpleName); int mod=clazz.getModifiers();//获取类修饰符 System.out.println("Modifier.isPublic:"+Modifier.isPublic(mod));//判断类修饰符 System.out.println("Modifier.isProtected:"+Modifier.isProtected(mod));//判断类修饰符 Package p=clazz.getPackage();//获取包 System.out.println("getPackage:"+p); Class superClass=clazz.getSuperclass();//获取父类 System.out.println("getSuperclass:"+superClass); Class[] interfaces=clazz.getInterfaces();//获取实现接口 System.out.println("getInterfaces:"+interfaces.length); Constructor[] cons=clazz.getConstructors();//构造方法 System.out.println("getConstructors:"+cons.length); Method[] methods=clazz.getMethods();//获取所有方法 System.out.println("getMethods:"+methods.length); for(Method method:methods){ System.out.println("method.getName:"+method); } Method method=clazz.getMethod("getProp1", new Class[]{});//获取指定方法 System.out.println("getMethod(,):"+method); Object methodVlaue=method.invoke(s, new Object[]{});//调用方法 System.out.println("method.invoke(,):"+methodVlaue); Method method3=clazz.getMethod("setProp3",Double.class);//获取指定方法 System.out.println("getMethod(,):"+method3); //调用setter方法,该方法没有返回值,所以methodVlaue3为null;此处注意参数2.0 ,不能用null Object methodVlaue3=method3.invoke(s, 2.0); System.out.println("method.invoke(,):"+methodVlaue3); Field[] fields=clazz.getDeclaredFields();//获取变量 System.out.println("getDeclaredFields:"+fields.length); for(Field field:fields){ field.setAccessible(true); field.set(s,null);//设置字段的值 //获取实例属性名和值 System.out.println("field.getAnnotations:"+field.getAnnotations().length+"\tfield.getName:"+field.getName()+"\tfield.get:"+field.get(s)); } Annotation[] annos=clazz.getAnnotations();//获取类注解 System.out.println("getAnnotations:"+annos.length); } } class Sample { private String prop1; private Integer prop2; private Double prop3; public String getProp1() { return prop1; } public void setProp1(String prop1) { this.prop1 = prop1; } public Integer getProp2() { return prop2; } public void setProp2(Integer prop2) { this.prop2 = prop2; } public Double getProp3() { return prop3; } public void setProp3(Double prop3) { this.prop3 = prop3; } }
3、Java 反射使用实例
1)反射调用执行main方法
import java.lang.reflect.Method; public class Main { public static void main(String[] args) { try { //获取Sample的字节码 Class clazz = Class.forName("Sample"); //获取main方法 Method methodMain = clazz.getMethod("main", String[].class);//第一个参数:方法名称,第二个参数:方法形参的类型, //调用main方法 //第一个参数,对象类型, //第二个参数是String数组,注意在jdk1.4时是数组,jdk1.5之后是可变参数, //将 new String[]{"a","b","c"} 拆成3个对象,所以需要将它强转。 methodMain.invoke(null, (Object)new String[]{"p1","p2","p3"});//方法一 // methodMain.invoke(null, new Object[]{new String[]{"p1","p2","p3"}});//方法二 } catch (Exception e) { e.printStackTrace(); } } } class Sample { public static void main(String[] args) { System.out.println("main方法执行"); } }
2)使用反射调用 ArrayList对象的add方法
import java.lang.reflect.Method; import java.util.ArrayList; public class Main { public static void main(String[] args) throws Exception{ ArrayList list = new ArrayList<>(); list.add("Java"); list.add("CJavaPy"); //获取ArrayList的Class对象,调用add()方法,添加数据 Class listClass = list.getClass(); //得到 list对象的字节码对象 //获取add()方法 Method m = listClass.getMethod("add", Object.class); //调用add()方法 m.invoke(list, "https://www.cjavapy.com"); //可以通过反射越过泛型检查的,添加整型的值 m.invoke(list,11); //遍历集合 for(Object obj : list){ System.out.println(obj); } } }
3)使用反射为对象赋值
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class Main { private String prop1; private Integer prop2; private Double prop3; public String getProp1() { return prop1; } public void setProp1(String prop1) { this.prop1 = prop1; } public Integer getProp2() { return prop2; } public void setProp2(Integer prop2) { this.prop2 = prop2; } public Double getProp3() { return prop3; } public void setProp3(Double prop3) { this.prop3 = prop3; } /** * 用于对类的字段赋值,无视private,project修饰符,无视set/get方法 * @param c 要反射的类 * @return */ @SuppressWarnings("unchecked") public static Object setClassValue(Class c, Object source, Object object) { try { Class<?> obj = object.getClass(); Class<?> s = source.getClass(); Field[] fields = obj.getDeclaredFields(); Field[] sfields = s.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { fields[i].setAccessible(true); for (int j = 0; j < sfields.length; j++) { if (sfields[j].getName().equals(fields[i].getName())) { fields[i].set(object, sfields[j].get(source)); break; } } } return object; } catch (Exception e) { e.printStackTrace(); } return null; } public static void main(String[] args) { try { Main s = new Main(); s.setProp1("Java"); s.setProp2(11); s.setProp3(22.00); Main o = new Main(); setClassValue(o.getClass(), s, o); System.out.println(o.getProp1()+" "+o.getProp2()+" "+o.getProp3()); } catch (Exception e) { e.printStackTrace(); } } }
4)使用反射获取注解
import java.lang.annotation.*; import java.lang.reflect.Method; @SampleAnnotation(Value = "java", Name = "cjavapy") public class Main { public static void main(String[] args) { Main s = new Main(); Class clazz = s.getClass(); Annotation[] annotations = clazz.getAnnotations(); for (Annotation anno : annotations) { System.out.println("Annotation Type: " + anno.annotationType()); } SampleAnnotation anno = (SampleAnnotation) clazz.getAnnotation(SampleAnnotation.class); System.out.println("Anno Value : " + anno.Value()); System.out.println("Anno Name: " + anno.Name()); try { Method m = clazz.getMethod("sayHi"); anno = m.getAnnotation(SampleAnnotation.class); System.out.println("Anno Value : " + anno.Value()); System.out.println("Anno Name: " + anno.Name()); } catch (NoSuchMethodException e) { e.printStackTrace(); } s.sayHello(); } @SampleAnnotation(Value = "Hi", Name = "Java") public void sayHi() { } @SampleAnnotation(Value = "Hello", Name = "CJavaPy") public void sayHello() { try { Method m = getClass().getMethod("sayHello"); SampleAnnotation anno = m.getAnnotation(SampleAnnotation.class); System.out.println(anno.Value() + " " + anno.Name()); } catch (NoSuchMethodException e) { e.printStackTrace(); } } } @Documented @Retention(RetentionPolicy.RUNTIME) @Inherited @interface SampleAnnotation { String Name()default "Java"; String Value()default "web"; }