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的反射原理

        共 12924字,需瀏覽 26分鐘

         ·

        2021-03-18 09:42

        點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

        優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

          作者 |  Deep Blue

        來源 |  urlify.cn/rqU36f

        1、Java的編譯過程

        談及反射,不得不先了解一下,java的整個(gè)編譯過程,整體的java編譯過程可以參考 之前的一篇 一個(gè)java文件被執(zhí)行的歷程 

        這里我們只針對(duì) 對(duì)象這一層級(jí)來討論,一個(gè)java文件,我們經(jīng)過編譯,會(huì)得出 一個(gè) 字節(jié)碼文件(.class),這時(shí)候,進(jìn)入解釋階段,編譯器會(huì)將這個(gè).class加載進(jìn)內(nèi)存中,此時(shí),它首先會(huì)生成一個(gè) Class對(duì)象。


        2、Class對(duì)象與對(duì)象形成的過程

            2.1Class對(duì)象

        在java世界里,一切皆對(duì)象。從某種意義上來說,java有兩種對(duì)象:實(shí)例對(duì)象和Class對(duì)象。對(duì)于每個(gè)類而言,JRE 都為其保留一個(gè)不變的 Class 類型的對(duì)象。

        Class對(duì)象會(huì)有以下幾個(gè)特點(diǎn):

        1. Class 對(duì)象只能由系統(tǒng)建立對(duì)象

        2. 一個(gè)類在 JVM 中只會(huì)有一個(gè)Class實(shí)例

        3. –每個(gè)類的實(shí)例都會(huì)記得自己是由哪個(gè) Class 實(shí)例所生成

        class對(duì)象包含的信息有:

        • 數(shù)據(jù)成員名

        • 內(nèi)部方法

        • 構(gòu)造方法

        • 集成自哪個(gè)接口、類


              2.2對(duì)象的形成過程

        我們的實(shí)例對(duì)象是通過Class對(duì)象來創(chuàng)建的。

        每一個(gè)類都有一個(gè)Class對(duì)象,每當(dāng)編譯一個(gè)新類就產(chǎn)生一個(gè)Class對(duì)象,基本類型 (boolean, byte, char, short, int, long, float, and double)有Class對(duì)象,數(shù)組有Class對(duì)象,就連關(guān)鍵字void也有Class對(duì)象(void.class)。Class對(duì)象對(duì)應(yīng)著java.lang.Class類,如果說類是對(duì)象抽象和集合的話,那么Class類就是對(duì)類的抽象和集合。

        Class類沒有公共的構(gòu)造方法,Class對(duì)象是在類加載的時(shí)候由Java虛擬機(jī)以及通過調(diào)用類加載器中的 defineClass 方法自動(dòng)構(gòu)造的,因此不能顯式地聲明一個(gè)Class對(duì)象。

        在類加載階段,類加載器首先檢查這個(gè)類的Class對(duì)象是否已經(jīng)被加載。如果尚未加載,默認(rèn)的類加載器就會(huì)根據(jù)類的全限定名查找.class文件。在這個(gè)類的字節(jié)碼被加載時(shí),它們會(huì)接受驗(yàn)證,以確保其沒有被破壞,并且不包含不良java代碼。一旦某個(gè)類的Class對(duì)象被載入內(nèi)存,我們就可以它來創(chuàng)建這個(gè)類的所有對(duì)象。


        3、反射的本質(zhì)及應(yīng)用

          上面的基礎(chǔ)了解完畢,我們進(jìn)入今天的主體,何為反射。

        所謂反射,官方的定義是: 指計(jì)算機(jī)程序在運(yùn)行時(shí)(runtime) 可以訪問、檢測(cè)和修改它本身狀態(tài)或行為的一種能力。通俗說,反射就是程序在運(yùn)行的時(shí)候能夠“觀察”并且修改自己的行為,是程序?qū)ψ陨淼姆此?、自檢、修改。

          理解反射,首先得知道它的對(duì)立面,“正射”


           3.1“正射”

        前面說到了Class對(duì)象,每個(gè)類的運(yùn)行時(shí)的類型信息就是用Class對(duì)象表示的。系統(tǒng)會(huì)自動(dòng)創(chuàng)建唯一一個(gè)Class對(duì)象,它包含了與類有關(guān)的信息。此時(shí)的java文件(一個(gè)類)處于一個(gè)中間狀態(tài),并不是我們使用的對(duì)象,只有當(dāng)我們使用  “ new  Object()”時(shí),才會(huì)在JVM堆中根據(jù)這個(gè)Class對(duì)象來產(chǎn)生真正供我們使用的實(shí)例對(duì)象。其實(shí)也就是上面部分的對(duì)象的形成過程。

        正射的使用意義是,我事先定義了一個(gè)對(duì)象的某些東西,然后當(dāng)我需要的時(shí)候,我會(huì)通知內(nèi)存去創(chuàng)建這個(gè)對(duì)象,然后我事先知道這個(gè)對(duì)象有什么,所以我會(huì)精準(zhǔn)的調(diào)用它的某個(gè)方法,某個(gè)成員變量。

        用一個(gè)我們習(xí)以為常的demo來舉一下例:

        class Human {
            String name;
            int age;
            String nation;
            Human(String name,int age,String nation) {
                this.name=name;
                this.age=age;
                this.nation=nation;
            }
            void changeName(String name){
                this.name=name;
            }
        }
        public class Main {
            public static void main(String[] args){
                Human human=new Human("張三",22,"中國(guó)");
                human.changeName("李四");
            }
        }

        在上面Main類的main方法中,我之所以可以寫human.changeName(“張三”) 是因?yàn)镠uman類也是我自己寫的,我清楚的知道,human作為Human的實(shí)例對(duì)象,可以調(diào)用changeName方法,如果我手抖寫了調(diào)用changeNamee方法,我也會(huì)立即改回來,因?yàn)槲抑繦uman里沒有這個(gè)方法。假如我不知道Human里有沒有一個(gè)改名字的方法,即Human類對(duì)我來說是不透明的第三方類,我嘗試性的在程序中調(diào)用了一個(gè)newName方法,保存、編譯。這時(shí)候編譯器會(huì)通知我,這樣寫程序是不對(duì)的,Human里沒有一個(gè)叫newName的方法,編譯失敗。


        3.2反射

        假如此時(shí)我只想使用對(duì)象某一個(gè)方法,某一個(gè)成員變量,而不想用其他的部分,這時(shí)候如果用“正射”(走正常的對(duì)象創(chuàng)建過程,new一下),就會(huì)被迫創(chuàng)建一個(gè)完整的該對(duì)象(有一說一,有點(diǎn)浪費(fèi)),此時(shí)我可以根據(jù)類的全路徑+名稱,去內(nèi)存中拿出這個(gè)類的Class對(duì)象,根據(jù)這個(gè)Class對(duì)象,靈活的去獲取這個(gè)類片面的信息。這種在運(yùn)行時(shí)訪問、修改對(duì)象的狀態(tài)和行為,可以給程序帶來極大的靈活性。這便是反射


        3.3反射可提供的功能

        1. 在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類。

        2. 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象。

        3. 在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法。

        4. 在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法。

        5. 生成動(dòng)態(tài)代理。

        詳細(xì)的API使用,可以查閱java的官方文檔。


        3.4反射的使用

          使用Java注解配合反射可以開發(fā)出各種工具、框架。例如,Spring中的注解、工廠模式中創(chuàng)建對(duì)象的方式等

        這里實(shí)現(xiàn)一個(gè)用自定義注解 @AutoField 實(shí)現(xiàn)為屬性賦值。

        定義注解@AutoField 

        @Target({ElementType.FIELD})
        @Retention(RetentionPolicy.RUNTIME)
        public @interface AutoField {
            String value() default "";
        }

        編寫解析類。BeanFactory中的createBean方法通過反射拿到注解 @AutoField的值并賦給對(duì)象。

        public class BeanFactory {
            public static <T> T createBean(Class<T> clazz) {
                T o = null;
                try {
                    o = clazz.newInstance();
                } catch (InstantiationException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
                Field[] declaredFields = clazz.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    if (declaredField.isAnnotationPresent(AutoField.class)) {
                        AutoField AutoField = declaredField.getAnnotation(AutoField.class);
                        if (!declaredField.isAccessible())
                            declaredField.setAccessible(true);
                        try {
                            if (declaredField.getType().getSimpleName().equals("String"))
                                declaredField.set(o, AutoField.value());
                            else if (declaredField.getType().getSimpleName().equals("byte"))
                                declaredField.set(o, Byte.parseByte(AutoField.value()));
                            else if (declaredField.getType().getSimpleName().equals("short"))
                                declaredField.set(o, Short.parseShort(AutoField.value()));
                            else if (declaredField.getType().getSimpleName().equals("int"))
                                declaredField.set(o, Integer.parseInt(AutoField.value()));
                            else if (declaredField.getType().getSimpleName().equals("long"))
                                declaredField.set(o, Long.parseLong(AutoField.value()));
                            else if (declaredField.getType().getSimpleName().equals("float"))
                                declaredField.set(o, Float.parseFloat(AutoField.value()));
                            else if (declaredField.getType().getSimpleName().equals("double"))
                                declaredField.set(o, Double.parseDouble(AutoField.value()));
                            else if (declaredField.getType().getSimpleName().equals("long"))
                                declaredField.set(o, Long.parseLong(AutoField.value()));
                            else if (declaredField.getType().getSimpleName().equals("boolean"))
                                declaredField.set(o, Boolean.parseBoolean(AutoField.value()));
                            else
                                throw new RuntimeException(declaredField.getName() + " of " + clazz.getName() + " is not a value field");
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException(e);
                        }

                    }
                }
                return o;
            }
        }

          定義實(shí)體類

        public class Teacher {

          @AutoField("12223")
          private int id;

          @AutoField("Zhang")
          private String name;

          @AutoField("20")
          private int age;

          @AutoField("false")
          private boolean isProfessor;

          @AutoField("G")
          private String sex;

          @AutoField("CQU")
          private String school;

          public int getId() {
            return id;
          }

          public String getName() {
            return name;
          }

          public int getAge() {
            return age;
          }

          public boolean isProfessor() {
            return isProfessor;
          }

          public String getSex() {
            return sex;
          }

          public String getSchool() {
            return school;
          }

          public void setId(int id) {
            this.id = id;
          }

          public void setName(String name) {
            this.name = name;
          }

          public void setAge(int age) {
            this.age = age;
          }

          public void setProfessor(boolean professor) {
            isProfessor = professor;
          }

          public void setSex(String sex) {
            this.sex = sex;
          }

          public void setSchool(String school) {
            this.school = school;
          }

          @Override
          public String toString() {
            return "Teacher{" +
              "id=" + id +
              ", name='" + name + '\'' +
              ", age=" + age +
              ", isProfessor=" + isProfessor +
              ", sex=" + sex +
              ", school='
        " + school + '\'' +
            '}';
          }
        }

        測(cè)試

        public class Main {
            public static void main(String[] args) {
                Teacher teacher = BeanFactory.createBean(Teacher.class);
                System.out.println(teacher);
            }





        粉絲福利:Java從入門到入土學(xué)習(xí)路線圖

        ??????

        ??長(zhǎng)按上方微信二維碼 2 秒


        感謝點(diǎn)贊支持下哈 

        瀏覽 51
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        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>
            free大乳女神pics | 成人午夜精品视频 | 欧美人交性 | 网红鹿少女演绎点外卖视频 | 午夜福利成人 | 一道来毛片 | 三级黄色中文字幕 | 国产精品久久久久劲爆 | jlzz国产丝袜18老师女人 | 日韩一区国产 |