您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 企业财务 > java反射与类加载器
反射class:定义Java类时的关键字.Class:Java程序中的各个Java类,它们是否属于同一类事物,是不是可以用一个类来描述这类事物呢?这个类的名字就是Class.有9个预定义的Class对象:8个基本类型+void.class.这8种基本类型分别是:boolean,char,byte,short,int,long,float,double.数组类型的Class实例对象:Class.isArray.总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如int[],void...Class.forName作用:返回字节码;返回方式1:这份字节码曾经被加载过,已经在java虚拟机中了,直接返回;返回方式2:java虚拟机中还没有这份字节码,用类加载器去加载,把加载进来的字节码缓存在虚拟机中,以后要得到这份字节码就不用加载了.反射就是把Java类中的各种成分映射成相应的Java类.例如,一个Java类用一个Class类的对象来表示,一个类中的组成部分:成员变量、方法、构造方法、包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机、变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,他们是Field、Method、Contructor、Package等等。一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后又什么用呢?怎么用呢?这正是学习和应用反射的要点。Constructor类代表某个类中的一个构造方法。1.得到某个类所有的构造方法:Constructor[]constructors=Class.forName(java.lang.String).getConstructors();2.得到某一个构造方法:Constructorconstructor=Class.forName(java.lang.String).getConstructor(StringBuffer.class);//获得构造方法时要用到类型3.创建实例对象:通常方式:Stringstr=newString(newStringBuffer(abc));反射方式:Stringstr2=(String)constructor.newInstance(newStringBuffer(abc));//调用获得的方法时要用到上面相同类型的实例对象4.Class.newInstance()方法:Stringobj=Class.forName(java.lang.String).newInstance();该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。该方法内部的具体是怎样的呢?用到了缓存机制来保存默认构造方法的实例对象。反射会导致程序性能下降。Field代表成员变量。Method类代表某个类中的一个成员方法。//专家模式1.得到类中的某一个方法:MethodcharAt=Class.forName(java.lang.String).getMethod(charAt,int.class);2.调用方法:通常方式:System.out.println(str.charAt(1));反射方式:System.out.println(charAt.invoke(str,1));3.jdk1.4和Jdk1.5的区别:jdk1.5:publicObjectinvoke(Objectobj,Object...args);jdk1.4:publicObjectinvoke(Objectobj,Object[]args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用jdk1.4改写为:charAt.invoke(str,newObject[]{1})形式.数组的反射:具有相同维度和元素类型的数组属于同一个类型,即具有相同的Class实例对象.代表数组的Class实例对象的getSuperclass()返回父类Object类对应的Class.基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组既可以被当作Object类型使用,也可以当作Object[]类型使用。Arrays.asList()方法处理int[]与String[]时的差异,见ReflectTest中的示例代码.java.lang.reflect.Array工具类用于完成对数组的反射操作.怎么得到一个数组的类型?不能得到,但可以得到数组中元素的类型.Object[]a=newObject[]{1,abc};a[0].getClass().getName();反射的作用---实现框架(Framework)功能.框架要解决的核心问题:我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。框架与工具的区别,工具类被用户的类调用,而框架则是调用用户提供的类.我在写框架(房子)时,你这个用户可能还在上小学,还不会写程序呢?我写的框架程序怎样能调用你以后写的类(门窗)呢?因为在写程序无法知道要被调用的类名,所以在程序中无法new某个类的实例对象了,而要采用反射方式来做,这样就达到了动态加载用户自定义类的目的.Java提供的放射机制允许你在运行时动态加载类、查看类信息、生成对象或操作生成的对象。反射机制的应用实例:在IDE(集成开发环境,如eclipse)中所提供的方法提示或是类查看工具。Jsp中的JavaBean自动收集请求信息也使用了反射。Java在真正需要使用一个类时才会加以加载,而不是在程序启动时就加载所有的类。因为大多数的用户都只使用到应用程序的部分资源,在需要某些功能时才加载某些资源,可以让系统的资源运用更有效率(Java本来就是为了资源有限的小型设备而设计的,这样的考虑是必然的)。enum(属于类的一种)、annotation(属于接口的一种)Class对象由JVM自动产生,每当一个类被加载时,JVM就自动为其生成一个java.lang.Class对象。可以通过Object的getClass()方法来取得每一个对象对应的Class对象,或者是通过class常量,如:Stringstr1=abc;/***如何得到各个字节码对应的实例对象(Class类型)?**/Classcls1=str1.getClass();Classcls2=String.class;Classcls3=Class.forName(java.lang.String);System.out.println(cls1==cls2);//trueSystem.out.println(cls1==cls3);//trueJava在真正需要类时才会加载类,所谓真正需要通常指的是:1:使用指定的类生成对象2:用户指定要加载类时(如:Class.forName()加载类、使用ClassLoader的loadClass加载类)使用类名称来声明参考名称并不会导致类的加载。静态区块:默认在类第一次被加载时会运行静态区块(说默认的原因,是因为可以设置加载类时不运行静态区块,使用Class生成对象时才运行静态区块)publicclassTestClass{static{System.out.println(“类被载入”);}}Class的静态forName()方法有两个版本:1:指定类名称的版本2:可以指定类名称、加载类时是否运行静态区块、指定类加载器staticClassforName(Stringname,booleaninitialize,ClassLoaderloader)第二个版本将initialize设置为false,这样加载类时并不会立即运行静态区块,而会在使用类建立对象时才会运行静态区块。第二个版本的forName()方法会需要一个类加载器,可以通过Thread.currentThread().getContextClassLoader()得到主线程的类加载器.super.getClass()方法调用下面程序的输出结果是多少?importjava.util.Date;publicclassTestextendsDate{publicstaticvoidmain(String[]args){newTest().test();}publicvoidtest(){System.out.println(super.getClass().getName());}}很奇怪,结果是Test在test方法中,直接调用getClass().getName()方法,返回的是Test类名由于getClass()在Object类中定义成了final,子类不能覆盖该方法,所以,在test方法中调用getClass().getName()方法,其实就是在调用从父类继承的getClass()方法,等效于调用super.getClass().getName()方法,所以,super.getClass().getName()方法返回的也应该是Test。如果想得到父类的名称,应该用如下代码:getClass().getSuperClass().getName();类加载器什么是类加载器和类加载器的作用?Java在需要使用类的时候,才会将来加载,Java类的加载是由类加载器来完成的。Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类加载器负责加载特定位置的类:BootstrapLoader,ExtClassLoader,AppClassLoader。类加载器也是Java类,因为其它是java类的类加载器本身也要被类加载器加载,显然必须有第一个不是java类,这正是BootStrapLoader,BootStrapLoader通常由C编写而成.ExtClassLoader,AppClassLoader(也可称为SystemLoader)都是java类,分别对应sun.misc.Launcher$ExtClassLoader与sun.misc.Launcher$AppClassLoader,它们都是Launcher(发射装置)中的内部类。java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个类加载器对象时,需要为其指定一个父级类加载器对象或者默认采用系统类加载器为其父级类加载。类加载器之间的父子关系和管辖范围?java程序启动与加载类的顺序图:当在命令行模式下执行javaXXX.class指令后,java运行程序会尝试找到JRE安装的所在目录,然后寻找jvm.dll(默认是在JRE目录下bin\client目录中),接着启动JVM并进行初始化动作,产生BootstrapLoader,BootstrapLoader会加载ExtendedLoader,并设置ExtendedLoader的parent为BootstrapLoader.BootstrapLoader会加载SystemLoader,并将SystemLoader的parent设置为ExtendedLoader.对象、Class、ClassLoader与Parent的关系图:类加载器在java中是以java.lang.ClassLoader类型存在,每一个类被加载后,都会有一个Class的实例来代表,而每个Class的实例都会记得自己是由哪个ClassLoader加载的。类载入器阶层的安全设计:Java的类加载器层次架构除了可以达到动态加载类的目的之外,还有着安全上的考虑。因为每次寻找类时都是委托parent开始寻找,所以除非有人可以侵入你的计算机,置换掉标准的JavaSEAPI与您自己安装的延伸包,否则不能通过编写自
本文标题:java反射与类加载器
链接地址:https://www.777doc.com/doc-2880751 .html