反射_类加载器_代理
2015-06-04 21:03
281 查看
一:概念介绍:
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>.此类没有公共的构造方法。
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");
5,Class和class区别:
1)class:Java中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,不同的实例对象有不同的属性值。
2)Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是Class。Class是Java程序中各个Java类的总称;它是反射的基石,通过Class类来使用反射。
三,Constructor类:
1,
2,方法:
对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
四,method类:
1,
2,方法:
对带有指定参数的指定对象调用由此
Method[] getMethods();//只获取公共和父类中的方法。
Method[] getDeclaredMethods();//获取本类中包含私有。
Method getMethod("方法名",参数.class(如果是空参可以写null));
Object invoke(Object obj ,参数);//调用方法
如果方法是静态,invoke方法中的对象参数可以为null。
五,Filed类:
1、Field类代表某个类中一个成员变量
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,反射类加载器及代理之间的关系:
类加载器是反射的前提,代理是基于类加载器和反射的。
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区别:
1)class:Java中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,不同的实例对象有不同的属性值。
2)Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是Class。Class是Java程序中各个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类:
1、Field类代表某个类中一个成员变量
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,反射类加载器及代理之间的关系:
类加载器是反射的前提,代理是基于类加载器和反射的。
相关文章推荐
- P122.42
- JAVA基础——IO流
- 欢迎使用CSDN-markdown编辑器
- Mac OS安装Apache、Tomcat、Nginx、PHP、MySQL、终端配色
- 英语要提高阅读和听力
- 小组自评、互评
- 乂文®便携触摸屏-介绍
- 将博客搬至CSDN
- 对软件功程课的改善建议
- 新的开始
- iOS 7系列译文:忘记NSURLConnection,拥抱NSURLSession吧!
- suspend() 和 resume() 方法,notify()和wait()方法区别
- 如何提升你的能力?给年轻程序员的几条建议
- BZOJ3990 排序
- 【每日scrum】NO.3
- 简单谈一下wordpress中的ajax请求,为什么会一直返回“0”
- 我所理解的设计模式(C++实现)——适配器模式(Adapter Pattern)
- UML简单介绍(十一)——协作图的概念与实例完全解析
- 没有毅力很可怕 一事无成很可怕 越来越不自信很可怕
- 【每日scrum】NO.2