第16篇-JAVA 類(lèi)加載與反射

2022-03-11 11:29 更新
  • 每篇一句 :敢于彎曲,是為了更堅(jiān)定的站立
  • 初學(xué)心得: 追求遠(yuǎn)中的歡聲笑語(yǔ),追求遠(yuǎn)中的結(jié)伴同行
  • (筆者:JEEP/711)[JAVA筆記 | 時(shí)間:2017-05-12| JAVA 類(lèi)加載與反射 ]

1.類(lèi)加載

  • 類(lèi)加載器負(fù)責(zé)將 .class 文件(可能在磁盤(pán)上, 也可能在網(wǎng)絡(luò)上) 加載到內(nèi)存中, 并為之生成對(duì)應(yīng)的 java.lang.Class 對(duì)象
    - 當(dāng)程序主動(dòng)使用某個(gè)類(lèi)時(shí),如果該類(lèi)還未被加載到內(nèi)存中,系統(tǒng)會(huì)通過(guò)加載、連接、初始化三個(gè)步驟來(lái)對(duì)該類(lèi)進(jìn)行初始化,如果沒(méi)有意外,JVM將會(huì)連續(xù)完成這三個(gè)步驟,所以有時(shí)也把這三個(gè)步驟統(tǒng)稱(chēng)為類(lèi)加載或類(lèi)初始化。
    - 類(lèi)加載指的是將類(lèi)的class文件讀入內(nèi)存,并為之創(chuàng)建一個(gè)java.lang.Class對(duì)象,也就是說(shuō)當(dāng)程序使用任何類(lèi)時(shí),系統(tǒng)都會(huì)為之建立一個(gè)java.lang.Class對(duì)象

2.類(lèi)數(shù)據(jù)的來(lái)源

通過(guò)使用不同的類(lèi)加載器,可以從不同來(lái)源加載類(lèi)的二進(jìn)制數(shù)據(jù),通常有如下幾種來(lái)源:
- 從本地文件系統(tǒng)來(lái)加載class文件,這是前面絕大部分示例程序的類(lèi)加載方式。
- 從JAR包中加載class文件,這種方式也是很常見(jiàn)的,前面介紹JDBC編程時(shí)用到的數(shù)據(jù)庫(kù)驅(qū)動(dòng)類(lèi)就是放在JAR文件中,JVM可以從JAR文件中直接加載該class文件
- 通過(guò)網(wǎng)絡(luò)在加載class文件
- 把一個(gè)Java源文件動(dòng)態(tài)編譯、并執(zhí)行加載

3.類(lèi)的連接

當(dāng)類(lèi)被加載之后,系統(tǒng)為之生成一個(gè)對(duì)應(yīng)的Class對(duì)象,接著將會(huì)進(jìn)入連接階段,連接階段將會(huì)負(fù)責(zé)把類(lèi)的二進(jìn)制數(shù)據(jù)合并到JRE中

類(lèi)連接又可分為如下三個(gè)階段:
- 驗(yàn)證:驗(yàn)證階段用于檢驗(yàn)被加載的類(lèi)是否有正確的內(nèi)部結(jié)構(gòu),并和其他類(lèi)協(xié)調(diào)一致
- 準(zhǔn)備:類(lèi)準(zhǔn)備階段則負(fù)責(zé)為類(lèi)的靜態(tài)屬性分配內(nèi)存,并設(shè)置默認(rèn)初始值
- 解析:將類(lèi)的二進(jìn)制數(shù)據(jù)中的符號(hào)引用替換成直接引用

4.類(lèi)加載器

類(lèi)加載器負(fù)責(zé)將.class文件(可能在磁盤(pán)上,也可能在網(wǎng)絡(luò)上)加載到內(nèi)存中,并為之生成對(duì)應(yīng)的java.lang.Class對(duì)象

當(dāng)JVM啟動(dòng)時(shí),會(huì)形成由三個(gè)類(lèi)加載器組成的初始類(lèi)加載器層次結(jié)構(gòu):
- Bootstrap ClassLoader:根類(lèi)加載器。
- Extension ClassLoader:擴(kuò)展類(lèi)加載器。
- System ClassLoader:系統(tǒng)類(lèi)加載器

5.什么是反射

反射就是把Java類(lèi)中的各種成分映射成一個(gè)個(gè)的java對(duì)象。例如,一個(gè)類(lèi)有:成員變量,方法,構(gòu)造方法,包等等信息,利用反射技術(shù)可以對(duì)一個(gè)類(lèi)進(jìn)行解剖,把各個(gè)組成部分映射成一個(gè)個(gè)對(duì)象

6.Class類(lèi)

Class類(lèi)用于表示.class文件
如何得到某個(gè)class文件對(duì)應(yīng)的class對(duì)象

類(lèi)名.class,
對(duì)象.getClass()
Class.forName(“類(lèi)名”)

數(shù)組類(lèi)型的Class實(shí)例對(duì)象

Class.isArray()

7.Constructor類(lèi)

Constructor類(lèi)的實(shí)例對(duì)象代表類(lèi)的一個(gè)構(gòu)造方法
得到某個(gè)類(lèi)所有的構(gòu)造方法,例:

Constructor [] constructors= Class.forName("java.lang.String").getConstructors();

得到某一個(gè)構(gòu)造方法,例:


Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);

利用構(gòu)造方法創(chuàng)建實(shí)例對(duì)象:

String str = (String)constructor.newInstance(“abc”);

Class類(lèi)的newInstance()方法也可創(chuàng)建類(lèi)的實(shí)例,其內(nèi)部工作原理是先得無(wú)參的構(gòu)造方法,再用構(gòu)造方法創(chuàng)建實(shí)例對(duì)象

String obj =(String)Class.forName("java.lang.String").newInstance();

8.內(nèi)省(Introspector)

訪問(wèn)JavaBean屬性的兩種方式
- 直接調(diào)用bean的setXXX或getXXX方法
- 通過(guò)內(nèi)省技術(shù)訪問(wèn)(java.beans包提供了內(nèi)省的API),內(nèi)省技術(shù)訪問(wèn)也提供了兩種方式
- 通過(guò)PropertyDescriptor類(lèi)操作Bean的屬性
- 通過(guò)Introspector類(lèi)獲得Bean對(duì)象的 BeanInfo,然后通過(guò) BeanInfo 來(lái)獲取屬性的描述器( PropertyDescriptor ),通過(guò)這個(gè)屬性描述器就可以獲取某個(gè)屬性對(duì)應(yīng)的 getter/setter 方法,然后通過(guò)反射機(jī)制來(lái)調(diào)用這些方法

內(nèi)省—beanutils工具包
Apache組織開(kāi)發(fā)了一套用于操作JavaBean的API,這套API考慮到了很多實(shí)際開(kāi)發(fā)中的應(yīng)用場(chǎng)景,因此在實(shí)際開(kāi)發(fā)中很多程序員使用這套API操作JavaBean,以簡(jiǎn)化程序代碼的編寫(xiě)

Beanutils工具包的常用類(lèi):
- BeanUtils
- PropertyUtils
- ConvertUtils.regsiter(Converter convert, Class clazz)
- 自定義轉(zhuǎn)換器

9.反射案例


<br> package com.mvc.bean;
<br> import com.mvc.service.imp.UserServiceImp;
<br> import java.util.ResourceBundle;
<br> /**
<br>  * Created by JEEP-711 
<br>  */
<br> public class BeanFactory {
<br>     private static ResourceBundle bundle;
<br>     static {
<br>         bundle = ResourceBundle.getBundle("instance"); //文件內(nèi)容
<br>     }
<br>     public static <T& T getInstance(String key, Class<T& clazz){
<br>         try {
<br>             String className = bundle.getString(key);//類(lèi)的全路徑
<br>             return (T)Class.forName(className).newInstance();//反射方式
<br>         } catch (Exception e) {
<br>             throw new RuntimeException(e);
<br>         }
<br>     }
<br> }
<br> ```
<br> ```
<br> package com.mvc.controller;
<br> import com.alibaba.fastjson.JSON;
<br> import com.mvc.bean.BeanFactory;
<br> import com.mvc.bean.Type;
<br> import com.mvc.service.ITypeService;
<br> import com.mvc.service.imp.TypeServiceImpl;
<br> import org.apache.commons.beanutils.BeanUtils;
<br> import javax.servlet.ServletException;
<br> import javax.servlet.http.HttpServlet;
<br> import javax.servlet.http.HttpServletRequest;
<br> import javax.servlet.http.HttpServletResponse;
<br> import java.io.IOException;
<br> import java.io.Writer;
<br> import java.util.List;
<br> /**
<br>  * Created by JEEP-711 
<br>  */
<br> public class TypeServlet extends HttpServlet{
<br>                                                //反射
<br> ITypeService iTypeService = BeanFactory.getInstance("typeService",ITypeService.class);
<br>     @Override
<br>     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
<br>         resp.setContentType("text/html;charset=UTF-8");//設(shè)置UTF-8編碼格式
<br>         req.setCharacterEncoding("UTF-8");//設(shè)置UTF-8編碼格式
<br>         String method = req.getParameter("m");
<br>         if("add".equals(method)){
<br>             add(req,resp);//調(diào)用add方法
<br>         }else if("update".equals(method)){
<br>             update(req,resp);//調(diào)用修改方法
<br>         }else if("ajax_all".equals(method)){
<br>             ajaxAll(req,resp);
<br>         }else if("delete".equals(method)){
<br>             delete(req,resp);
<br>         }else {
<br>             index(req,resp);//調(diào)用錯(cuò)誤方法
<br>         }
<br>     }
<br> }
<br> ```

初學(xué)(JAVA 類(lèi)加載與反射 高級(jí)階段) 難點(diǎn): ★★★★★

希望每一篇文章都能夠?qū)ψx者們提供幫助與提升,這乃是每一位筆者的初衷

感謝您的閱讀 歡迎您的留言與建議

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)