反射_类加载器_代理

来源:互联网 发布:怎样查电脑mac地址 编辑:程序博客网 时间:2024/06/04 21:56

一:概念介绍:

  1 ,   概念:什么是反射?要弄清楚反射,我们必须弄清楚什么是字节码,什么是类装载器。我们知道,Java是一个完全面向对象的语言,那么我们写好的 .java 文件经过编译后生成的 .class  ,对Java虚拟机来说,是不是应该也是一个对象呢?在Java中,的确是将.class 看做一类对象,既然是一类对象,这些对象有哪些共性(共同的属性和方法),是不是需要用一个Java类封装起来呢?是的。在Java中使用了 Class 这个Java类去封装 .class 这一类对象(要注意Class 与 java中定义一个类的关键字 class 区分开来)。

  2,,介绍:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

        简单一句话:反射技术可以对类进行解剖,动态的获取指定的类以及动态的调用类的内容。大大提高了程序的扩展性。


二,Class类介绍:

1,Class类:Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。所有的类文件都有共同属性,所以可以向上抽取,把这些共性内容封装成一个类,这个类就叫Class(描述字节码文件的对象)。此实例表示正在运行的java应用的类和接口,由此Class对象建模的类的类型,如String.class的类型是Class<String>.此类没有公共的构造方法。

class Class{//描述字节码文件的类Field field;//将字节码文件中的类Constructor cons;//将构造函数封装成了对象类型,Method method;//方法:getFiled();getMethod();getConstructor();}//将类中的成员都封装成了对象

2,属性:Filed(字段);method(方法);Constructor(构造函数)。

forname():返回与带有给定字符串名的类或接口相关联的Class对象。自动寻找.class文件,并加载进内存。

3,创建实例:

//通过newInstance(),就可以创建字节码对象所表示的类的实例。 

//通过new创建给定类的实例
//调用该类的构造函数,会调用该实例的构造函数
//通常被发射的类都会有构造函数。。
//没有对应的构造函数会报InstantiationException异常。
//如果有提供但权限不够,会报无效访问异常。

4,方法:

1,getDeclaredField(name)方法:返回一个field对象,该对象反映此Class对象所表示的类或接口的指定已声明字段,name参数是一个参数String。她指定所需字段的简称,注意此方法不反应数组类的length字段。
2,field1.setAccessible(true);//取消对age的权限检查,称为暴力访问。,不对age的私有进行检查
3,getXXX:获取都是类中公共的成员。
4,getDeclareXXX:获取类中已有的成员。得到各个字节码对应的实例对象的三种方法(Class类型):
类名.class,例如:System.class
对象.getClass();例如:new Date().getClass();
Class.forName("类名");例如,Class.forName("java.util.Date");

//反射得到变量:Field fieldstr1 = pt1.getClass().getDeclaredField("str1");


5,Class和class区别:

        1classJava中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,不同的实例对象有不同的属性值。

        2Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是ClassClassJava程序中各个Java类的总称;它是反射的基石,通过Class类来使用反射。


三,Constructor类:

1,Constructor 提供关于类的单个构造方法的信息以及对它的访问权限。

2,方法:

getName()  以字符串形式返回此构造方法的名称。

equals(Object obj)  将此Constructor 对象与指定的对象进行比较。

getParameterTypes()   按照声明顺序返回一组Class 对象,这些对象表示此Constructor 对象所表示构造方法的形参类型。

hashCode()  返回此Constructor 的哈希码。

newInstance(Object... initargs)  使用此Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

toString()  返回描述此Constructor 的字符串.


四,method类:

1,Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。

2,方法:

equals(Object obj) 将此Method 与指定对象进行比较。

getName()String 形式返回此Method 对象表示的方法名称。

hashCode()  返回此Method 的哈希码

invoke(Object obj,Object... args)   对带有指定参数的指定对象调用由此Method 对象表示的底层方法。

toString()返回描述此Method 的字符串。

 Method[] getMethods();//只获取公共和父类中的方法。

    Method[] getDeclaredMethods();//获取本类中包含私有。

        Method   getMethod("方法名",参数.class(如果是空参可以写null);

        Object invoke(Object obj ,参数);//调用方法

        如果方法是静态,invoke方法中的对象参数可以为null

//反射获取string的.charAt方法,并判断str1的1角标 的字符:Method methodCharAt = String.class.getMethod("charAt", int.class);System.out.println(methodCharAt.invoke(fieldstr1.get(pt1), 1));

package reflect;import java.lang.reflect.Method;public class ReflectTest2 {//通过用户提供的类名和方法,反射执行该类中的main方法public static void main(String[] args) throws Exception {//用静态代码的方式直接调用main方法://TestArguments.main(new String[]{"111","sss"});//当我们不知道类名时,我们需要使用反射的方式调用:Method mainMethod = Class.forName("reflect.TestArguments").getMethod("main", String[].class);mainMethod.invoke(null, (Object)new String[]{"111","sdsds"});Method test1Method = Class.forName("reflect.TestArguments").getMethod("test1", String[].class);mainMethod.invoke(null, (Object)new String[]{"111","sdsds"});}}


五,Filed类:

1Field类代表某个类中一个成员变量

2、方法

        Field getField(String s);//只能获取公有和父类中公有

       Field getDeclaredField(String s);//获取该类中任意成员变量,包括私有

       setAccessible(ture);

        //如果是私有字段,要先将该私有字段进行取消权限检查的能力。也称暴力访问。

       set(Object obj, Object value);//将指定对象变量上此Field对象表示的字段设置为指定的新值。

      Object get(Object obj);//返回指定对象上Field表示的字段的值。


六,类加载器:

1,概述:类加载器就是加载类的工具,Jvm运行的时候需要加载class文件,在内存中字节码。加载class,并生成字节码文件的过程是由类加载器完成的。因为类加载器也是java类,任何类都是需要类加载器加载的,所以一定有一个不是java类的加载器,BootStrap,Jvm还内置了2个类加载器,ExtClassLoader和AppClassLoader,他们是由BootStrap加载。

2,类加载器之间的父子关系和管辖范围图:

BootStrap:加载的是 java包,javax包,这些系统级的包,在JRE/lib/rt.jar包内。
ExtClassLoader则JRE/lib/ext/*.jar,这里是加载该目录下的所有jar包。
如果要手动编写System类的话就必须自己编写一个类加载器,不要委托机制才可以加载到。

3,委托机制:

类加载器加载线程中的第一个类,如果这个类中还有其他类的话,则用这个类加载器加载其他的类。就是A类中引用了B类,那么加载AB类的加载器都是同一个。每个类加载器加载类的时候都会委托给上级加载,当上级没有加载到这个类的话就返回给原加载器,如果还是加载不到就会报异常ClassnotFoundException。


七,代理:

1,定义:一个已经开发好的目标类,想要为这个类增加一些系统功能,这时我们就可以编写一个与目标类具有相同接口的代理类,代理类的每个目标方法调用目标类的相同方法,并在调用方法时加上系统功能的代码,这时候调用代理类就可以获得目标类里面的方法。客户类真正的想要访问的对象是目标对象,但客户类真正可以访问的对象是代理对象。客户类对目标对象的访问是通过访问代理对象来实现的。当然,代理类与目标类要实现同一个接口。目标类也称为委托类。

(1)面向面的编程AOP(Aspect Oriented Program)
      系统中可能存在交叉业务需要切入到系统中的一方面,如:
                 安全       事务          日志
StudentService ---|----------|------------|-------------
CourseService ---|----------|------------|-------------
MiscService    
  ---|----------|------------|-------------
面向
面的编程的目标就是要是交叉的业务模块化,可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码运行起来的效果是一样的,如:
------------------------------------------------------切面
func1         func2            func3
{             {                { 
....            ....              ......
}             }                }
------------------------------------------------------切面
使用代理技术正好解决这样的问题,代理是实现AOP功能的核心和关键技术。
(2)Proxy类和InvocationHandler接口提供了生成动态代理的功能

2,作用:

当写好的程序进行调试,想要监控每个方法运行了多长时间,就可以在配置文件中配置使用代理类来完成,等测试类完成了交给用户运行的时候,直接再在配置文件中配置使用目标类。这样就不用修改代码,比较高效。

八,细节:

1、获取Class对象的三种方式:

         加载XX.class文件进内存时就被封装成了对象,该对象就是字节码文件对象。如何获取Class对象呢?

方式一:

        通过对象的getClass方法进行获取。

        如:Class clazz=new Person().getClass();//Person是一个类名

        麻烦之处:每次都需要具体的类和该类的对象,以及调用getClass方法。

方式二:

         任何数据类型都具备着一个静态的属性class,这个属性直接获取到该类型的对应Class对象。

        如:Class clazz=Person.class;//Person是一个类名

        比第一种较为简单,不用创建对象,不用调用getClass方法,但是还是要使用具体的类,和该类中的一个静态属性class完成。

方式三:

        这种方式较为简单,只要知道类的名称即可。不需要使用该类,也不需要去调用具体的属性和行为。就可以获取到Class对象了。

        如:Class clazz=Class.forName("包名.Person");//Person是一个类名

        这种方式仅知道类名就可以获取到该类字节码对象的方式,更有利于扩展。


2,类加载器:

1、简述:类加载器是将.class的文件加载进内存,也可将普通文件中的信息加载进内存。

2、文件的加载问题:

        1)eclipse会将源程序中的所有.java文件编译成.class文件,然后放到classPath指定的目录中去。并且会将非.java文件原封不动的复制到.class指定的目录中去。在运行的时候,执行的是.class文件。

        2)将配置文件放到.class文件目录中一同打包,类加载器就会一同加载。

3、资源文件的加载:是使用类加载器。

        1)由类加载器ClassLoader来加载进内存,即用getClassLoader()方法获取类加载器,然后用类加载器的getResourceAsStream(String name)方法,将配置文件(资源文件)加载进内存。利用类加载器来加载配置文件,需把配置文件放置的包名一起写上。这种方式只有读取功能。

       2)Class类也提供getResourceAsStream方法来加载资源文件,其实它内部就是调用了ClassLoader的方法。这时,配置文件是相对类文件的当前目录的,也就是说用这种方法,配置文件前面可以省略包名。

      如:类名.class.getResourceAsStream(“资源文件名”)。


3,动态代理和代理的区别:

一个静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类,

静态代理事先知道要代理的是什么,而动态代理不知道要代理的是什么东西。只有在运行时才知道。

4,反射类加载器及代理之间的关系:

类加载器是反射的前提,代理是基于类加载器和反射的。













0 0
原创粉丝点击