1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Java jvm 類加載 反射

        共 8523字,需瀏覽 18分鐘

         ·

        2020-10-29 23:59

        點擊上方藍色字體,選擇“標星公眾號”

        優(yōu)質文章,第一時間送達

        ? 作者?|??吳楠予

        來源 |? urlify.cn/E3euIb

        66套java從入門到精通實戰(zhàn)課程分享

        Java 底層

        jvm,類加載,反射

        Java語言是跨平臺語言,一段java代碼,經(jīng)過編譯成class文件后,能夠在不同系統(tǒng)的服務器上運行;因為java語言中有虛擬機jvm,才有了跨平臺,java為了實現(xiàn)跨平臺,在jvm上投入了很大的研發(fā)開發(fā)資源。jvm是java的底層,本文學習探討下java的jvm及關聯(lián)的類加載和反射知識

        JVM

        JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用于計算設備的規(guī)范,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現(xiàn)的。

        Java語言的一個非常重要的特點就是與平臺的無關性。而使用Java虛擬機是實現(xiàn)這一特點的關鍵。一般的高級語言如果要在不同的平臺上運行,至少需要編譯成不同的目標代碼。而引入Java語言虛擬機后,Java語言在不同平臺上運行時不需要重新編譯。Java語言使用模式Java虛擬機屏蔽了與具體平臺相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節(jié)碼),就可以在多種平臺上不加修改地運行。Java虛擬機在執(zhí)行字節(jié)碼時,把字節(jié)碼解釋成具體平臺上的機器指令執(zhí)行。[1]

        jvm的構成

        jvm周期:是在java程序執(zhí)行時運行,程序結束時停止

        jvm的基本結構有:類加載子系統(tǒng)、本地方法棧、Java棧、方法區(qū)、Java堆、pc寄存器,垃圾回收,執(zhí)行引擎

        類加載子系統(tǒng)

        java是面向對象語言,邏輯代碼中的類文件執(zhí)行邏輯前,是需要jvm讀取class文件并校驗初始化后才能使用的,包括變量,方法,構造。

        類加載系統(tǒng)可以認為是在使用到java對像時(抽象),對java對象字節(jié)碼的讀取加載預編譯(具體),之后不再加載(讀取校驗一次)。

        Java棧

        棧是先進后出的結構,java棧時一塊線程私有的內(nèi)存空間,可以理解為一個java線程對應一個java棧,棧和線程密切關聯(lián),棧包含線程運行的實時信息,如當前運行方法地址,方法中的瞬時變量等信息

        方法區(qū)

        在一個jvm實例的內(nèi)部,類型信息被存儲在一個稱為方法區(qū)的內(nèi)存邏輯區(qū)中。類型信息是由類加載器在類加載時從類文件中提取出來的。類(靜態(tài))變量也存儲在方法區(qū)中。

        Java堆

        java堆是和應用程序關系最為密切的內(nèi)存空間,幾乎所有的對象都存放在堆上。并且java堆是完全自動化管理的,通過垃圾回收機制,垃圾對象會被自動清理,而不需要顯示的釋放。

        pc寄存器

        存放計算機下一步要執(zhí)行的指令的地址,

        垃圾回收

        因為程序運行沒創(chuàng)建一個對象都需要使用硬件的內(nèi)存資源,不能無限使用,jvm的垃圾回收能夠自動回收不再使用的java對象,使內(nèi)存空間有效利用。垃圾回收線程是后臺執(zhí)行的,不需要認為回收內(nèi)存垃圾,即使有垃圾回收方法調(diào)用,但并不能控制jvm如何去將一個對象失效回收。

        執(zhí)行引擎

        Java 字節(jié)碼指令指向特定邏輯得本地機器碼,而JVM 解釋執(zhí)行Java字節(jié)碼指令時,會直接調(diào)用字節(jié)碼指向得本地機器碼;

        java底層由C語言編寫,執(zhí)行java程序時,jvm每讀取一個字節(jié)碼指令動作,執(zhí)行引擎就解析解釋執(zhí)行本地系統(tǒng)對應的本地機器碼。

        類加載

        虛擬機把描述類的數(shù)據(jù)從 Class 文件加載到內(nèi)存,并對數(shù)據(jù)進行校驗、轉換解析和初始化,最終形成可以被虛擬機直接使用的 Java 類型,這就是虛擬機的類加載機制。

        在Java語言里面,類型的加載、連接和初始化過程都是在程序運行期間完成的

        雙親委派機制

        作為軟件開發(fā)語言,java在安全方面也有很高的要求,所以類加載是有一套規(guī)則的,jre是java運行時的環(huán)境,包括很多基本類,如java.lang.String 是字符串類,這個類很基礎也很重要,那在加載的時候不能允許加載的String類被篡改,java保證類加載安全,首先看是否已經(jīng)加載,如果沒有查看核心庫是否有此類,沒有此類才會去擴展環(huán)境找類文件加載,這種機制保證了類在加載時的唯一性和安全性。

        java類加載一般來說是詢問自己的parentClassLoader 加載,如果沒有加載成功,才自己加載,加載順序是自上而下

        java.lang.ClassLoader 加載類方法

        protected?Class?loadClass(String?name,?boolean?resolve)
        ????????throws?ClassNotFoundException
        ????{
        ????????synchronized?(getClassLoadingLock(name))?{
        ????????????//?First,?check?if?the?class?has?already?been?loaded
        ????????????Class?c?=?findLoadedClass(name);?//0.是否已加載
        ????????????if?(c?==?null)?{
        ????????????????long?t0?=?System.nanoTime();
        ????????????????try?{
        ????????????????????if?(parent?!=?null)?{
        ????????????????????????c?=?parent.loadClass(name,?false);?//1.沒有加載,首先通過父類加載器加載
        ????????????????????}?else?{
        ????????????????????????c?=?findBootstrapClassOrNull(name);?//1.沒有父類加載器時加載方式
        ????????????????????}
        ????????????????}?catch?(ClassNotFoundException?e)?{
        ????????????????????//?ClassNotFoundException?thrown?if?class?not?found
        ????????????????????//?from?the?non-null?parent?class?loader
        ????????????????}

        ????????????????if?(c?==?null)?{?
        ????????????????????//?If?still?not?found,?then?invoke?findClass?in?order
        ????????????????????//?to?find?the?class.
        ????????????????????long?t1?=?System.nanoTime();
        ????????????????????c?=?findClass(name);
        ?????//如果父類沒有加載到類,則使用findClass方法去加載類(這個方法可以重寫自定義)
        ????????????????????//?this?is?the?defining?class?loader;?record?the?stats
        ????????????????????sun.misc.PerfCounter.getParentDelegationTime().addTime(t1?-?t0);
        ????????????????????sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
        ????????????????????sun.misc.PerfCounter.getFindClasses().increment();
        ????????????????}
        ????????????}
        ????????????if?(resolve)?{
        ????????????????resolveClass(c);
        ????????????}
        ????????????return?c;
        ????????}
        ????}

        反射

        反射是Java重要的技術點,在框架開發(fā),AOP切面編程代理等方面都需要反射方面的技術去實現(xiàn)。

        Java反射機制主要提供了以下功能:

        • 在運行時判斷任意一個對象所屬的類。

        • 在運行時構造任意一個類的對象。

        • 在運行時判斷任意一個類所具有的成員變量和方法。

        • 在運行時調(diào)用任意一個對象的方法。

        • 生成動態(tài)代理。

        反射相關的類

        Class 類的字節(jié)碼對象

        Field 類的屬性

        Method 類的方法

        Constructor 類的構造方法

        Annotation 類(方法字段)的注解

        反射的使用

        一般使用

        模擬事務的注解

        @Target({ElementType.TYPE,ElementType.METHOD})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Inherited
        public?@interface?defTransaction?{

        }

        普通封裝對象

        public?interface?People?{

        ?String?getName();
        ?void?setName(String?name);
        ?Integer?getAge();
        ?void?setAge(Integer?age);
        ?BigDecimal?getMoney();
        ?void?setMoney(BigDecimal?money);
        ?@defTransaction
        ?void?addMoney(BigDecimal?addNum);
        ?@defTransaction
        ?void?subTractMoney(BigDecimal?subNum);
        ?
        }

        public?class?TestPeople?implements?People{
        ?
        ?//?姓名
        ?public?String?name;
        ?
        ?//?年齡
        ?private?Integer?age;
        ?
        ?//?錢
        ?private?BigDecimal?money;
        ?
        ?public?String?getName()?{
        ??return?name;
        ?}
        ?
        ?public?void?setName(String?name)?{
        ??this.name?=?name;
        ?}
        ?public?Integer?getAge()?{
        ??return?age;
        ?}
        ?public?void?setAge(Integer?age)?{
        ??this.age?=?age;
        ?}
        ?public?BigDecimal?getMoney()?{
        ??return?money;
        ?}
        ?public?void?setMoney(BigDecimal?money)?{
        ??this.money?=?money;
        ?}

        ?@Override
        ?public?void?addMoney(BigDecimal?addNum)?{
        ??this.money?=?this.money.add(addNum);
        ??
        ?}

        ?@Override
        ?public?void?subTractMoney(BigDecimal?subNum)?{
        ??this.money?=?this.money.subtract(subNum);
        ?}??
        }

        反射測試類

        public?class?ReflectTest?{

        ?public?static?void?main(String[]?args)?{
        ??//?普通對象創(chuàng)建?使用new
        ??People?testPeople?=?new?TestPeople();
        ??testPeople.setName("Frank");
        ??testPeople.setAge(18);
        ??testPeople.setMoney(new?BigDecimal(10));
        ??System.out.println("json:"?+?JsonUtil.objectToJson(testPeople));
        ??
        ??//?反射創(chuàng)建對象?class.newInstance()
        ??ClassLoader?contextClassLoader?=?Thread.currentThread().getContextClassLoader();
        ??try?{
        ???Class?clazz?=?contextClassLoader.loadClass("com.domoment.leaves.common.util.reflect.TestPeople");
        ???if(clazz?!=?null)?{
        ?????Object?people?=?clazz.newInstance();
        ?????System.out.println("newInstance?start?json:"?+?JsonUtil.objectToJson(people));
        ?????
        ?????//?通過反射執(zhí)行方法
        ?????Method?setName?=?clazz.getMethod("setName",?String.class);
        ?????setName.invoke(people,?"inoverFrank");
        ?????
        ?????
        ?????System.out.println("newInstance?end?json:"?+?JsonUtil.objectToJson(people));
        ?????
        ???}
        ??}?catch?(Exception?e)?{
        ???e.printStackTrace();
        ??}
        ?}
        }

        使用反射實現(xiàn)代理

        代理類DefProxy (People是被代理類)

        public?class?DefProxy?implements?InvocationHandler{

        ??//?這個就是我們要代理的真實對象
        ????private?Object?subject;
        ????
        ????//????構造方法,給我們要代理的真實對象賦初值
        ????public?DefProxy(Object?subject){
        ????????this.subject?=?subject;
        ????}
        ????
        ?@Override
        ?public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{
        ??Annotation[]?annotations?=?method.getDeclaredAnnotations();
        ??boolean?transactionOpen?=?false;
        ??for?(Annotation?annotation?:?annotations)?{
        ???if(annotation?instanceof?defTransaction)?{
        ????transactionOpen?=?true;
        ????break;
        ???}
        ??}
        ??if(transactionOpen)?{?//當方法上有?defTransaction?注解時,執(zhí)行方法前開啟事務
        ???System.out.println("open?Transaction");
        ??}
        ??System.out.println("proxy:"?+?method.getName());
        ??Object?result?=?method.invoke(subject,?args);
        ??
        ??if(transactionOpen)?{?//當方法上有?defTransaction?注解時,執(zhí)行方法后關閉事務
        ???System.out.println("close?Transaction");
        ??}
        ??return?result;
        ?}

        }

        代理測試代碼

        public?class?ReflectTest?{

        ?public?static?void?main(String[]?args)?{
        ??//?反射創(chuàng)建對象
        ??ClassLoader?contextClassLoader?=?Thread.currentThread().getContextClassLoader();
        ??try?{
        ???Class?clazz?=?contextClassLoader.loadClass("com.domoment.leaves.common.util.reflect.TestPeople");
        ???if(clazz?!=?null)?{
        ?????Object?people?=?clazz.newInstance();
        ?????System.out.println("newInstance?start?json:"?+?JsonUtil.objectToJson(people));
        ?????
        ?????
        ?????Method?setName?=?clazz.getMethod("setName",?String.class);
        ?????setName.invoke(people,?"inoverFrank");
        ?????
        ?????System.out.println("newInstance?end?json:"?+?JsonUtil.objectToJson(people));
        ?????
        ?????InvocationHandler?handler?=?new?DefProxy(people);
        ?????
        ?????????????????//?構造代理對象
        ?????People?proxyPeople?=?(People)Proxy.
        ???????newProxyInstance(handler.getClass().getClassLoader(),?people.getClass().getInterfaces(),?handler);

        ?????proxyPeople.setName("proxySetFrank");
        ?????proxyPeople.setAge(20);
        ?????proxyPeople.setMoney(new?BigDecimal(999));
        ?????System.out.println("proxyPeople?end?json:"?+?JsonUtil.objectToJson(people));
        ?????proxyPeople.addMoney(new?BigDecimal(20));
        ?????System.out.println("proxyPeople?add?json:"?+?JsonUtil.objectToJson(people));
        ?????proxyPeople.subTractMoney(new?BigDecimal(17));
        ?????System.out.println("proxyPeople?end?json:"?+?JsonUtil.objectToJson(people));
        ?????
        ???}
        ??}?catch?(Exception?e)?{
        ???e.printStackTrace();
        ??}
        ?}
        }

        控制臺打印

        newInstance?start?json:{}
        newInstance?end?json:{"name":"inoverFrank"}
        proxy:setName
        proxy:setAge
        proxy:setMoney
        proxyPeople?end?json:{"name":"proxySetFrank","age":20,"money":999}
        open?Transaction
        proxy:addMoney
        close?Transaction
        proxyPeople?add?json:{"name":"proxySetFrank","age":20,"money":1019}
        open?Transaction
        proxy:subTractMoney
        close?Transaction
        proxyPeople?end?json:{"name":"proxySetFrank","age":20,"money":1002}

        可以看到方法上有 defTransaction 注解的時候,

        方法執(zhí)行前 打印 open Transaction

        方法執(zhí)行后 打印 close Transaction

        這是模擬,真實場景就可以將打印改為代理時擴展方法,如數(shù)據(jù)庫操作時候,開啟關閉事務




        粉絲福利:實戰(zhàn)springboot+CAS單點登錄系統(tǒng)視頻教程免費領取

        ???

        ?長按上方微信二維碼?2 秒
        即可獲取資料



        感謝點贊支持下哈?

        瀏覽 56
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产成人三级三级三级97 | 男人天堂网2023 | 国产亚洲精品成人a v久久网站 | 久久久久国产成人免费精品免费 | 黄色三级片视频网站 | 大色综合网 | 国产成人亚洲精品自产在线 | 国产毛片一区二区三区在线视频 | 黄色小视频网站免费 | 男人插入女人下面 |