12.1Java类加载机制前面我们给大家介绍过JVM的功能(提供运行时环境、垃圾回收机制和提供中立的体系结构)。在提供运行时环境中有个子功能是ClassLoader(类加载器),它主要用于将主类(即包含了main方法的类)加载到JVM的codesegment(代码区)。然后运行环境找到main方法(程序入口)开始执行程序。在整个程序运行的过程中,会有更多的class被动态Load到内存中。类加载机制如图12-1所示:图12-1类加载机制需要注意的是:类并非一次性就全部加载完毕,而是在需要的时候(运行期间)动态加载到内存。利用java-verbose:classTest可以观察类的具体加载过程。12.2Java反射机制什么是反射Java程序在运行期间可以动态加载、解析和使用一些在编译阶段并不确定的类型数据,这一机制被称为反射(Reflection)。反射库(reflectionlibrary)提供了一个非常丰富且精心设计的工具类,以便编写能够动态操纵Java代码的程序。使用反射,在设计和运行中添加新类时,能够快速的应用开发工具动态的查询新添加类的能力。反射方式反射机制提供的功能·加载运行时才能确定的数据类型·解析类的结构、分析类的能力、获取其内部信息·操作类(进行实例化访问非静态成员,直接利用类名访问静态成员)或其实例(访问属性、调用方法、创建新对象)12.2.1Class类在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识,被称为Class(注意与class的区别)。通过Class可以完整的得到一个类中的完整结构,包括此类中的方法定义,属性定义等。Class是反射的源头或入口,通过查看JDK帮助手册其常见方法如图:12.2.2如何获取Class类对象12.2.2.1针对引用数据类型·通过ClassLoader的loadClass方法Classc1=ClassLoader.getSystemClassLoader().loadClass(com.itjob.Person);·调用静态方法Class.forName()Class.forName(com.itjob.Person);Class.forName(oracle.jdbc.dirver.OracleDriver);·调用Object类中定义的getClass()方法Personp=newPerson();Classc1=p.getClass();Classc2=Hello.getClass();·使用.class表达式Classc1=String.class;Classc2=com.itjob.Person.class;Classc3=oracle.jdbc.dirver.OracleDriver.class;12.2.2.2针对基本数据类型及void·使用.class表达式Classc1=int.class;Classc2=double.class;Classc3=void.class;·调用相应封装类的Type属性Classc1=Integer.TYPE;Classc2=Double.TYPE;Classc3=Void.TYPE;示例如下:try{//1.引用数据类型//1.1利用ClassLoader类的loaderClass(类全名称);手动加载,会有异常System.out.println(ClassLoader.getSystemClassLoader().loadClass(com.itjob.Person).getName());//1.2利用Class.forName(类全名称);手动加载,会有异常System.out.println(Class.forName(com.itjob.Person).getName());//1.3调用Object类中定义的getClass()方法System.out.println(newPerson().getClass().getName());//1.4使用.class表达式System.out.println(Person.class.getName());//2.基本数据类型和void//2.1使用.class表达式System.out.println(int.class.getName());System.out.println(double.class.getName());System.out.println(void.class.getName());//2.2通过各自的包装类.TYPESystem.out.println(Integer.TYPE);System.out.println(Double.TYPE);}catch(ClassNotFoundExceptione){e.printStackTrace();}12.2.3获取实例对象不光可以取得对象所在类的信息,也可以直接通过Class类的newInstance方法进行对象实例化操作。newInstance方法原型如下:publicTnewInstance()throwsInstantiationException,IllegalAccessException调用过程:p.getClass().newInstance();或:Person.class.newInstance();或:Class.forName(com.itjob.Person).newInstance()创建一个Person类的实例。newInstance方法调用默认的构造器初始化新创建的对象,如果这个类没有默认的构造器,就会抛出一个异常。要想调用有参构造方法,则必须使用Constructor类的newInstance方法。12.2.4获取类的结构Class类的实例用于表示运行时的Java数据类型,包括类、接口、数组、枚举、注解、基本数据类型。在类加载时,Java虚拟机会自动创建相应Class对象。通过反射得到一个类的完整结构要使用到java.lang.reflect包,此包下的常见类如下:java.lang.reflect.Fieldjava.lang.reflect.Methodjava.lang.reflect.ConstructorTjava.lang.reflect.Modifierjava.lang.reflect.Array12.2.4.1获取类实现的所有接口要想取得一个类所实现的全部接口,则必须使用Class类中的getInterfaces()方法。此方法定义如下:publicClass[]getInterfaces()。因为一个类可以同时实现多个接口,因此此方法返回一个Class类的对象数组,之后就可以直接利用Class类中的getName()方法输出即可。示例如下:interfaceA{}interfaceB{}classPersonimplementsA,B{}publicclassTest{publicstaticvoidmain(String[]args){Class[]c=Person.class.getInterfaces();for(Classcc:c){System.out.println(cc.getName());}}}12.2.4.2获取类所继承的父类一个类可以实现多个接口,但是只能继承一个父类,如果没有明确的指明继承那个类,则肯定继承的是Object类。所以要想取得一个类的父类,可以直接使用Class类中的getSuperclass()方法。此方法定义如下:publicClass?superTgetSuperclass()。此方法返回的是Class实例,和之前得到接口一样,可以通过getName()方法取得名称。示例如下:classA{}classPersonextendsA{}publicclassTest{publicstaticvoidmain(String[]args){System.out.println(Person.class.getSuperclass().getName());}}12.2.4.3获取类中的全部构造方法可以直接使用Class类中的getConstructors()方法或getDeclaredConstructors()方法取得本类中的全部构造方法。这两个方法的返回类型都是Constructor的数组。Constructor类定义在java.lang.reflect包中,常用方法如下:取得访问修饰权限的时候却发现返回的是一个int数字而不是public等类型的修饰符关键字。这是因为在整个Java中对于方法的修饰符是使用一顶的数字表示出来的,如图所示:如果要想把这个数字还原成用户可以看懂的关键字,则必须依靠Modifier类完成,此类定义在java.lang.reflect包中。直接使用Modifier类的以下方法即可将修饰符转变:publicstaticStringtoString(intmod);示例如下:importjava.lang.reflect.*;classPerson{privateStringname;privateintage;publicPerson(){}publicPerson(Stringname,intage){this.name=name;this.age=age;}@OverridepublicStringtoString(){//TODOAuto-generatedmethodstubreturn我叫+this.name+,我今年+this.age;}}publicclassTest{publicstaticvoidmain(String[]args){//获取所有的构造方法Constructor?cs[]=Person.class.getDeclaredConstructors();for(Constructor?c:cs){//遍历所有的构造方法//输出构造方法的修饰符System.out.println(构造器修饰符:+Modifier.toString(c.getModifiers()));//输出构造方法名称System.out.println(构造方法名:+c.getName());//输出构造方法所有参数Class?ct[]=c.getParameterTypes();if(ct.length==0)System.out.println(这是无参的构造方法);else{inti=0;for(Class?p:ct){System.out.println(参数+(i+1)+:+p.getName());i++;}}}}}现在我们已经知道如何获取一个类的所有构造方法规范,此时我们可以利用Constructor类的newInstance调用有参的构造方法来实例化对象,其过程如下:1、通过Class类中的getConstructors()方法或getDeclaredConstructors()取得本类中的全部构造方法。2、分析每个构造方法的参数情况,了解每个构造方法的原型。3、通过Class类中的getDeclaredConstructor(Class?...parameterTypes)方法,向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数。4、通过调用Constructor的newInstance(Object...initargs)方法实例化对象。示例如下:try{Constructor?c=Person.class.getDeclaredConstructor(String.class,int.class);System.out.println(c.newInstance(张三,25));}catch(IllegalArgumentExceptione){e.printStackTrace();}catch(InstantiationExceptione){e.