简介Java反射机制是一个非常强大的功能,在Spring、Mybatis等很多大型项目中都能看到它的身影。通过反射机制,我们可以在运行时获取对象的类型信息。利用这个特性,我们可以实现工厂模式、代理模式等设计模式,也可以解决Java泛型擦除等令人苦恼的问题。在本文中,我们将从实际应用的角度来应用Java的反射机制。反射基础p.s:本文要求读者对反射机制的API有一定的了解。如果没有接触过,建议阅读官方文档的QuickStart。在应用反射机制之前,我们先来看看如何获??取一个对象对应的反射类。在Java中,我们有3种方法来获取一个对象的反射类。通过Java中的getClass方法,每个Object都有一个getClass方法。通过getClass方法,我们可以得到这个对象对应的反射类:Strings="ziwenxie";Cl??ass>c=s.getClass();ForName方法我们也可以调用Class类的静态方法forName:Class>c=Class.forName("java.lang.String");使用.class或者我们也可以直接使用.class:Class>c=String.class;获取类型信息在文章的开头,我们提到了反射的一个好处就是可以让我们在运行时获取对象的类型信息。让我们通过一个例子来看一下。首先,我们在typeinfo.interfacea包下新建一个接口A:packagetypeinfo.interfacea;公共接口A{voidf();然后我们在typeinfo.packageaccess包下新建一个接口C,接口C继承自接口A,另外我们还创建了几个测试用的方法。注意以下方法的权限是不同的。packagetypeinfo.packageaccess;importtypeinfo.interfacea.A;C类实现A{publicvoidf(){System.out.println("publicC.f()");}publicvoidg(){System.out.println("publicC.g()");}protectedvoidv(){System.out.println("protectedC.v()");}voidu(){System.out.println("包C.u()");privatevoidw(){System.out.println("privateC.w()");}}publicclassHiddenC{publicstaticAmakeA(){returnnewC();}}我们在callHiddenMethod()方法中使用了几个新的API,其中getDeclaredMethod()用于根据方法名获取Class类引用的对象的某个方法,然后我们可以触发相关方法通过调用invoke()方法传入对象的实际对象:packagetypeinfo;导入typeinfo.interfacea.A;导入typeinfo.packageaccess.HiddenC;导入java.lang.reflect.Method;公共类HiddenImplementation{publicstaticvoidmain(String[]args)throwsException{Aa=HiddenC.makeA();a.f();System.out.println(a.getClass().getName());//糟糕!倒影静物允许我们调用g():callHiddenMethod(a,"g");//甚至是不易访问的方法!callHiddenMethod(a,"u");callHiddenMethod(a,"v");callHiddenMethod(a,"w");}staticvoidcallHiddenMethod(Objecta,StringmethodName)throwsException{Methodg=a.getClass().getDeclaredMethod(methodName);g.setAccessible(真);g.调用(一);}}输出结果,我们可以看到无论是public、default、protect还是pricate方法,我们都可以通过反射类自由调用。当然,我们只是在这里展示反射的强大力量。实际开发中不提倡这种技术。publicC.f()typeinfo.packageaccess.CpublicC.g()packageC.u()protectedC.v()privateC.w()应用实践我们有如下业务场景,我们有一个泛型集合类List>,我们需要统计这个集合类中具体宠物的数量。由于Java的泛型擦除,像List,因为编译器做了静态类型检查后,JVM在运行时会把集合中的所有对象都当做Pets,但是并不知道Pet是代表Cat还是Dog,所以的类型信息该对象实际上在运行时丢失了。p.s:关于genericerasure:我在上一篇文章中有详细讲解,有兴趣的朋友可以看看。为了实现我们上面的例子,我们先定义几个类:publicclassPetextendsIndividual{publicPet(Stringname){super(name);}publicPet(){super();}}publicclassCatextendsPet{publicCat(Stringname){super(name);}公共猫(){超级();}}publicclassDogextendsPet{publicDog(Stringname){super(name);}publicDog(){super}}publicclassEgyptianMauextendsCat{publicEgyptianMau(Stringname){super(name);}publicEgyptianMau(){super();}}publicclassMuttextendsDog{publicMutt(Stringname){super(name);}publicMutt(){super();}}上面的Pet类继承自Individual。Individual类的实现稍微复杂一些。我们实现了Comparable接口,重新自定义类的比较规则。如果不是很懂也没关系,我们已经抽象出来了,所以不懂实现原理也没关系。publicclassIndividualimplementsComparable{privatestaticlongcounter=0;privatefinallongid=counter++;私有字符串名称;//name是可选的publicIndividual(Stringname){this.name=name;}publicIndividual(){}publicStringtoString(){returngetClass().getSimpleName()+(name==null?"":""+name);}publiclongid(){返回id;}publicbooleanequals(Objecto){returnoinstanceofIndividual&&id==((Individual)o).id;}publicinthashCode(){int结果=17;if(name!=null){结果=37*结果+name.hashCode();}结果=37*结果+(int)id;返回结果;}publicintcompareTo(Individualarg){//首先按类名比较:Stringfirst=getClass().getSimpleName();StringargFirst=arg.getClass().getSimpleName();国际第一Compare=first.compareTo(argFirst);如果(firstCompare!=0){返回firstCompare;}if(name!=null&&arg.name!=null){intsecondCompare=name.compareTo(arg.name);如果(secendCompare!=0){返回secendCompare;}}return(arg.id>getTypes();publicPetrandomPet(){//创建一个随机宠物intn=rand.nextInt(getTypes().size());尝试{returngetTypes().get(n).newInstance();}catch(InstantiationExceptione){thrownewRuntimeException(e);}catch(IllegalAccessExceptione){thrownewRuntimeException(e);}}publicPet[]createArray(intsize){Pet[]result=newPet[size];for(inti=0;iarrayList(intsize){ArrayListresult=newArrayList();Collections.addAll(结果,createArray(大小));返回结果;}}接下我们来实现在针对上面的抽象类,解释下面的代码。在下面的代码中,我们声明了两个集合类,allTypes和types,其中allTypes包含了我们上面声明的所有类,但是我们具体的type其实只有两种,分别是Mutt和EgyptianMau,所以我们真正需要的宠物new的只是types中包含的类型,以后我们可以通过调用getTypes()来获取types中包含的类型。publicclassLiteralPetCreatorextendsPetCreator{@SuppressWarnings("unchecked")publicstaticfinalList>allTypes=集合。unmodifiableList(Arrays.asList(Pet.class,Dog.class,Cat.class,Mutt.class,EgyptianMau.class));私有静态最终列表<类>类型=allTypes。subList(allTypes.indexOf(Mutt.class),allTypes.size());公共列表<类>getTypes(){返回类型;}}整体逻辑已经完成,***我们实现了TypeCounter类,用于统计集合中相关Pet类的个数。解释一下isAssignalbeFrom()方法,它可以判断一个反射类是反射类的子类还是间接子类。而getSuperclass(),顾名思义,就是获取一个反射类的父类。publicclassTypeCounterextendsHashMap,Integer>{privateClass>baseType;publicTypeCounter(Class>baseType){this.baseType=baseType;}publicvoidcount(Objectobj){Class>type=obj.getClass();if(!baseType.isAssignableFrom(type)){thrownewRuntimeException(obj+"不正确的类型"+type+",应该是"+baseType的类型或子类型);}计数类(类型);}privatevoidcountClass(Class>type){整数数量=get(type);put(type,quantity==null?1:quantity+1);类>superClass=type.getSuperclass();if(superClass!=null&&baseType.isAssignableFrom(superClass)){countClass(superClass);}}@OverridepublicStringtoString(){StringBuilderresult=newStringBuilder("{");对于(Map.Entry,Integer>pair:entrySet()){result.append(pair.getKey().getSimpleName());结果追加(“=”);结果.append(对.getValue());结果.追加(",");}result.delete(result.length()-2,result.length());结果.追加(“}”);返回结果.toString();}}