初学者可能会想反射是什么,有什么作用。那我就以一个简单的小需求开始。现在有3个类,A,B,C. 现在我想要一个方法,根据输入的字符串,获取相应的实例对象,即当我给这个对象传入"A"的时候,我要获取一个A实例,传入"B"的时候获取一个B实例,有人说用if, 那么如果有1000个类,就用1000个if或者case么,而且,如果不事先知道有多少种情况呢? [java] view plaincopyprint?
Public Object (string type)
{
……
}
Public Object (string type)
{
……
}
要解决这个问题,我们先从基础知识开始学习。
在Java程序执行的时候,在这个进程中,内存分为代码区,静态存储区,堆内存和栈内存。一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。静态存储区,主要是用来存储字符串和类的静态成员变量等。现在说到了对于反射来讲很重要的一块内存,代码区(CodeSegment)。代码区主要存放的是加载到内存的二进制文件。注意,这不是对象实例,而是那些一个个还没有被唤醒的。class文件。
从面相对象的角度来讲,这些文件都是一类,都是Class类。至于如何理解。class文件对象和实例对象,我是这样理解的。在代码区的。class对象就像是下载视频的种子,虽然它并不是一个实实在在的视频,但是必须要通过这个种子才能获得视频文件,而且一个种子可以使用多次。相对应的,在程序中。class文件对象,要通过这个对象来获取需要的对象,而且能多次使用。
在Java虚拟机中,有一个很重要的搬运工的角色,就是ClassLoader,这是一大类Class,它们的作用就是把相应的用到的二进制的Class文件加载到内存中。注意,这里有一个动态的加载机制,不是说,在程序启动的时候,如果ClassPath下有100个。class文件,就会把所有的二进制码一下子加载到内存中,而是刚刚开始的时候JVM使用ClassLoader把最初的几个。class二进制码Load到内存中,之后的是用到的时候才加载,慢慢的会有更多的加载到存中。当然也可以通过代码显示的要求立即把相应的二进制类代码加载到内存,如JDBC驱动的加载 Class.forName("com.mysql.jdbc.Driver")
在这里有一个相关的知识点就是static静态语句块的问题。有人说,静态语句块是第一次new对象的时候执行,这种说法是不准确的,确切的说,是加载到内存中的时候执行。一般来讲我们自己写的类,是用的时候才加载到内存,而我们用的方式,一般都是new一个对象,一般不会强制显示的去加载,所以,大家就以为是第一次实例化的时候执行。如果我们使用Class.Forname显示的把它load到内存,而并不new对象,可以发现,此时静态代码块也执行了。
现在解决最初提出的那个问题,只需要一句代码
String type = "A";
Object o = Class.forName(type)。newInstance();
下面是有关反射使用的一些常用的方法,包括获取成员方法等。从面相对象的角度看,类中的一个个属性或者方法都是对象,要让其执行,调用invoke就可以了。
|
|