类的加载和反射

来源:互联网 发布:计划任务软件 编辑:程序博客网 时间:2024/05/21 11:09

当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载、连接、初始化三个步骤来对类进行初始化,也成类的加载或类的初始化

类的加载、连接、初始化

当我们调用java命令运行某个Java程序时,该命令将会启动一条Java虚拟机进程,不管该Java程序多么复杂、程序启动多少线程,他们都处于该Java虚拟机进程里,并使用该JVM进程的内存区。

类的加载

类的加载是指将类的Class文件读入内存,并为之创建一个Java.lang.Class对象。

类的连接

类被加载后,系统会为之生成一个Class对象,接着进入类的连接,类的连接会把类的二进制数据合并到JRE中

类的初始化

类的初始化阶段,虚拟机对类进行初始化,主要是静态属性的初始化,包括静态属性、静态初始化块。类初始化之前,先要进行父类初始化。

而对象的初始化顺序如下:

首先初始化父类(从Object到直接父类),然后

一、静态变量、静态初始化块(它们之间按顺序初始化)

二、变量、初始化块(它们之间按顺序初始化)

三、构造器

具体顺序如何呢:

父类--静态变量、静态初始化块(类初始化过程中进行)
子类--静态变量、静态初始化块(类初始化过程中进行)
父类--变量、初始化块
父类--构造器


子类--变量、初始化块
子类--构造器

也就是说,子类静态变量、静态初始化块的初始化仅在父类静态变量、静态初始化块之后。

反射

反射的定义

在java中,我们可以于运行时加载、探知、使用编译期间完全未知的classes,或者说java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methode定义),并生成其对象实体、对其fields赋值、唤醒其methods。

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

前面文章讲过,每个类被加载后,系统会为该类生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类。Java程序中获得Class对象常有如下三种方式:

一、使用Class类的forname()静态方法,参数为某类的全限定类名(必须添加完整包名)。Class c1 = Class.forName ("java.lang.String");

二、调用某个类的Class属性来获取该类对应的Class对象。如Person.class将会返回Person类对应的Class对象

三、调用某个对象的getClass()方法,该方法是Java.lang.Object类中的一个方法,所以所有Java对象都可以调用该方法。

从Class中获取类信息

class类定义了大量的实例方法来获取该Class对象所对应的详细信息,有以下方法:

访问Class对应的类所包含的构造器:getConstructor()、getConstructors()、getDeclaredConstructor()、getDeclaredConstructors()等。返回Constructor对象

访问Class对应类所包含的方法:getMethod()、getMethods()、getDeclaredMethod()、getDeclaredMethodes()等。返回Method对象

访问Class对应类所包含的属性:getField()、getFields()、getDeclaredField()、getDeclaredFields()等。返回Field对象。

另外还有获取内部类、包名、注释、外部类、父类、接口等方法。

使用反射生成并操作对象

Class对象可以获得该类里包括的方法(用Method对象表示)、构造器(用Constructor对象表示)、属性(用Field对象表示),这三个类都定义在java.lang.reflect包下,并实现了java.lang.reflect.member接口,程序可以通过method对象来执行对应的方法、用Constructor对象来调用对应的构造器来创建对象、通过Field直接访问并修改属性值。

通过反射来生成对象有两种方式:

一、使用Class对象的newInstance()方法来创建该class对象对应类的实例,这种方法要求改Class对象的对应类必须有默认构造方法,实际是用默认构造器来创建实例。

二、使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建Class对象对应类的实例。

通过第一种方式来创建对象是比较常见的情形。

import java.util.*;import java.io.*;public class ObjectPoolFactory{//定义一个对象池,前面是对象名,后面是实际对象private Map<String ,Object> objectPool = new HashMap<String , Object>();//定义一个创建对象的方法,//该方法只要传入一个字符串类名,程序可以根据该类名生成Java对象private Object createObject(String clazzName)throws InstantiationException , IllegalAccessException,ClassNotFoundException{//根据字符串来获取对应的Class对象Class<?> clazz =Class.forName(clazzName);//使用clazz对应类的默认构造器创建实例return clazz.newInstance();}//该方法根据指定文件来初始化对象池,//它会根据配置文件来创建对象public void initPool(String fileName)throws InstantiationException , IllegalAccessException,ClassNotFoundException{FileInputStream fis = null;try{fis = new FileInputStream(fileName);Properties props = new Properties();props.load(fis);for (String name : props.stringPropertyNames()){//每取出一对属性名-属性值对,就根据属性值创建一个对象//调用createObject创建对象,并将对象添加到对象池中objectPool.put(name , createObject(props.getProperty(name))); } }catch (IOException ex){System.out.println("读取" + fileName + "异常");}finally{try{if (fis != null){fis.close();}}catch (IOException ex){ex.printStackTrace();}}}public Object getObject(String name){//从objectPool中取出指定name对应的对象。return objectPool.get(name);}public static void main(String[] args)throws Exception{ObjectPoolFactory pf = new ObjectPoolFactory();pf.initPool("obj.txt");System.out.println(pf.getObject("a"));}}




原创粉丝点击