最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaSE基礎(chǔ)之反射機制(反射Class)詳解

 更新時間:2022年09月01日 14:24:12   作者:@每天都要敲代碼  
反射機制有什么用?通過java語言中的反射機制可以操作字節(jié)碼文件,可以讀和修改字節(jié)碼文件。所以本文將為大家講講反射機制的使用,需要的可以參考一下

一:反射機制概述

1、反射機制有什么用?

通過java語言中的反射機制可以操作字節(jié)碼文件。

優(yōu)點類似于黑客。(可以讀和修改字節(jié)碼文件。)

通過反射機制可以操作代碼片段。(class文件。)   

2、反射機制的相關(guān)類在哪個包下?

java.lang.reflect.*;   

3、反射機制相關(guān)的重要的類有哪些?

java.lang.Class:代表整個字節(jié)碼,代表一個類型,代表整個類。

java.lang.reflect.Method:代表字節(jié)碼中的方法字節(jié)碼。代表類中的方法。

java.lang.reflect.Constructor:代表字節(jié)碼中的構(gòu)造方法字節(jié)碼。代表類中的構(gòu)造方法

java.lang.reflect.Field:代表字節(jié)碼中的屬性字節(jié)碼。代表類中的成員變量(靜態(tài)變量+實例變量)。     

   // java.lang.Class:(整個是一個class)
            public class User{
                // Field (成員變量)
                int no;
 
                // Constructor(構(gòu)造方法)
                public User(){
                
                }
                public User(int no){
                    this.no = no;
                }
 
 
                // Method(方法)
                public void setNo(int no){
                    this.no = no;
                }
                public int getNo(){
                    return no;
                }
            }

二:反射Class

1. 獲取Class的三種方式 

要操作一個類的字節(jié)碼,需要首先獲取到這個類的字節(jié)碼,怎么獲取java.lang.Class實例?

三種方式:

第一種:Class c = Class.forName("完整類名帶包名");

1、靜態(tài)方法

2、方法的參數(shù)是一個字符串。

3、字符串需要的是一個完整類名。

4、完整類名必須帶有包名。java.lang包也不能省略。

第二種:Class c = 對象(引用).getClass();

第三種:Class c = 任何類型.class;

package com.bjpowernode.java.reflect;
 
import java.util.Date;
 
public class ReflectTest01 {
    public static void main(String[] args) {
 
        // 第一種方式:Class.forName()
        Class c1 = null;
        Class c2 = null;
        try {
            // c1代表String.class文件,或者說c1代表String類型。
            c1 = Class.forName("java.lang.String"); 
            // c2代表Date類型
            c2 = Class.forName("java.util.Date"); 
            // c3代表Integer類型
            Class c3 = Class.forName("java.lang.Integer"); 
            // c4代表System類型
            Class c4 = Class.forName("java.lang.System");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
 
        // 第二種方式:對象.getClass()
        // java中任何一個對象都有一個方法:getClass()
        String s = "abc";
        // x代表String.class字節(jié)碼文件;x代表String類型
        Class x = s.getClass(); 
        // true(==判斷的是對象的內(nèi)存地址)
        System.out.println(x == c1); 
 
        Date time = new Date();
        Class y = time.getClass();
        // true (c2和y兩個變量中保存的內(nèi)存地址都是一樣的,都指向方法區(qū)中的字節(jié)碼文件)
        System.out.println(c2 == y); 
 
        // 第三種方式,java語言中任何一種類型,包括基本數(shù)據(jù)類型,它都有.class屬性。
        // z代表String類型
        Class z = String.class;
        // k代表Date類型 
        Class k = Date.class; 
        // f代表int類型
        Class f = int.class; 
        // e代表double類型
        Class e = double.class; 
        System.out.println(c1 == x && x == z); // true
 
    }
 
}

2. 通過反射實例化(創(chuàng)建)對象

(1)獲取到Class,通過Class的newInstance()方法來實例化(創(chuàng)建)對象。

(2)newInstance()方法內(nèi)部實際上調(diào)用了無參數(shù)構(gòu)造方法,必須保證無參構(gòu)造存在才可以;所以一旦我們寫上了有參構(gòu)造方法,無參構(gòu)造方法也要寫上! 如果有有參構(gòu)造方法,而沒有寫無參構(gòu)造方法會出現(xiàn)異java.lang.InstantiationException 實例化異常

package com.bjpowernode.java.reflect;
 
import com.bjpowernode.java.bean.User;
 
public class ReflectTest02 {
    public static void main(String[] args) {
 
        // 第一種方法創(chuàng)建對象:不使用反射機制
        User user = new User();
        System.out.println(user);
 
        // 第二種方法創(chuàng)建對象:以反射機制的方式創(chuàng)建對象。(這種方式比較靈活)
        try {
            // 通過反射機制,獲取Class,通過Class來實例化(創(chuàng)建)對象
            Class c = Class.forName("com.bjpowernode.java.bean.User");
            Object obj = c.newInstance();
           
            System.out.println(obj);
            /*
            執(zhí)行結(jié)果:
                無參數(shù)構(gòu)造方法
                com.bjpowernode.java.bean.User@4554617c
            */
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}
package com.bjpowernode.java.bean;
 
public class User {
    // 無參構(gòu)造(不寫也行,默認會有)
    public User() {
        System.out.println("無參數(shù)構(gòu)造方法");
    }
 
    // 有參構(gòu)造寫了,無參構(gòu)造必須寫;不然調(diào)用newInstance()會出現(xiàn)異常
    public User(String s) {
        System.out.println("無參數(shù)構(gòu)造方法");
    }
 
}

3. 通過讀配置屬性文件實例化對象

(1)通過讀配置屬性文件實例化對象,java代碼寫一遍,再不改變java源代碼的基礎(chǔ)之上,只改變配置文件,可以做到不同對象的實例化;非常之靈活。(符合OCP開閉原則:對擴展開放,對修改關(guān)閉)

(2)配置文件寫好,命名為xxx.properties,然后使用IO流+Properties

(3)后期我們要學習的是高級框架,而工作過程中,也都是使用高級框架,

包括: ssh ssm

  • Spring SpringMVC MyBatis
  • Spring Struts Hibernate
  • ...

這些高級框架底層實現(xiàn)原理:都采用了反射機制。所以反射機制很重要的;學會了反射機制有利于我們理解剖析框架底層的源代碼。

package com.bjpowernode.java.reflect;
 
import java.io.FileReader;
import java.util.Properties;
 
public class ReflectTest03 {
    public static void main(String[] args) throws Exception {
        // IO流+Properties集合
        // 通過IO流讀classinfo.properties配置文件
        // 配置文件內(nèi)容是:className=com.bjpowernode.java.bean.User
        FileReader reader = new FileReader("day08\\classinfo.properties");
        // 創(chuàng)建屬性類對象Map,properties的key和value都是String
        Properties pro = new Properties();
        // 加載
        pro.load(reader);
        // reader關(guān)閉流
        reader.close();
        // 通過key獲取value
        String s = pro.getProperty("className");
        //System.out.println(s); // com.bjpowernode.java.bean.User
 
        // 最后在通過反射機制實例化對象
        Class c = Class.forName(s);
        Object obj = c.newInstance();
        System.out.println(obj);
        /*
        執(zhí)行結(jié)果:
            無參數(shù)構(gòu)造方法
            com.bjpowernode.java.bean.User@4554617c
        */
 
        // 怎么體現(xiàn)靈活性?
        // 這里的代碼我們都不改變,只改變classinfo.properties配置文件
        // 例如改成:className=java.util.Date
        // 此時執(zhí)行的結(jié)果就變了:Wed Aug 03 15:40:02 CST 2022
 
    }
}

4. 只讓靜態(tài)代碼塊執(zhí)行

Class.forName()執(zhí)行發(fā)生了什么

(1)Class.forName("完整類名");這個方法的執(zhí)行會導致類加載,類加載時,靜態(tài)代碼塊執(zhí)行。如果你只是希望一個類的靜態(tài)代碼塊執(zhí)行,其它代碼一律不執(zhí)行,使用Class.forName()

package com.bjpowernode.java.reflect;
 
public class ReflectTest04 {
    public static void main(String[] args) {
        try {
            // Class.forName()這個方法的執(zhí)行會導致:類加載。
            // 類加載,靜態(tài)代碼塊就會執(zhí)行
            Class.forName("com.bjpowernode.java.reflect.MyClass");
            // 執(zhí)行結(jié)果:MyClass類的靜態(tài)代碼塊執(zhí)行了!
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
 
class MyClass{
    // 靜態(tài)代碼塊在類加載時執(zhí)行,并且只執(zhí)行一次
    static{
        System.out.println("MyClass類的靜態(tài)代碼塊執(zhí)行了!");
    }
}

5. 獲取類路徑下文件的絕對路徑

(1)怎么獲取一個文件的絕對路徑。以下講解的這種方式是通用的。但前提是:文件需要在類路徑(src)下才能用這種方式。

(2) 例如:

 String path = Thread.currentThread().getContextClassLoader()
               .getResource("User.properties").getPath();
  • Thread.currentThread() 當前線程對象
  • getContextClassLoader() 是線程對象的方法,可以獲取到當前線程的類加載器對象。
  • getResource() 【獲取資源】這是類加載器對象的方法,當前線程的類加載器默認從類的根路徑下加載資源。
  • getPath() 獲取路徑
package com.bjpowernode.java.reflect;
 
import java.io.FileReader;
 
// 研究一下文件路徑的問題
public class AboutPath {
    public static void main(String[] args) throws Exception {
        // 我們寫成下面這種路徑形式,只能在IDEA工具中才能找到,不夠通用!
        FileReader reader = new FileReader("day08\\classinfo.properties");
 
        // 通用的一種方式:
        // 注意:使用以下通用方式的前提是:這個文件必須在類路徑下。
        // 什么類路徑下?方式在src下的都是類路徑下?!緎rc是類的根路徑】
 
        //Thread.currentThread() 當前線程對象
        //getContextClassLoader() 是線程對象的方法,可以獲取到當前線程的類加載器對象。
        //getResource() 【獲取資源】這是類加載器對象的方法,當前線程的類加載器默認從類的根路徑下加載資源。
        // 寫成下面這種形式,放到Linux環(huán)境下也是沒問題的
        // 假設(shè)classinfo.properties剛好在src下
        String path = Thread.currentThread().getContextClassLoader()
                .getResource("classinfo.properties").getPath();
        // 拿到絕對路徑
        System.out.println(path); // C:/Users/86177/IdeaProjects/JavaSe1/out/production/day08/classinfo.properties
 
        // 假設(shè)有一個example文件沒有直接在src下面,而是bean下面(com/bjpowernode/java/bean/example)
        String path2 = Thread.currentThread().getContextClassLoader()
                .getResource("com/bjpowernode/java/bean/example").getPath();
        // 獲取絕對路徑
        System.out.println(path2); // C:/Users/86177/IdeaProjects/JavaSe1/out/production/day08/com/bjpowernode/java/bean/example
    }
}

這樣我們就可以修改原來的代碼,得到更加通用的方式!

第一種:先通過相對路徑(這里的相對路徑前提:一定是在src下的才可以;在模塊下的就不行)獲取絕對路徑,然后創(chuàng)建流:

// 1.得到相對路徑
String path =Thread.currentThread().getContextClassLoader().getResource("相對路徑").getPath(); 
// 2.創(chuàng)建流
 FileReader reader = new FileReader(path);

第二種方式:直接返回一個流(InputStream)

InputStream reader = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream("com/bjpowernode/java/bean/example");

注意:這兩種方式還是還是使用IO流+properties集合的方式,使用絕對路徑而不是相對路徑更加的通用:

第一種方式先得到絕對路徑,返回String,然后在創(chuàng)建IO流

第二種方式直接返回的就是一個流InputStream

package com.bjpowernode.java.reflect;
 
import java.io.FileReader;
import java.io.InputStream;
import java.util.Properties;
 
public class ReflectTest05 {
    public static void main(String[] args) throws Exception {
         // 第一種方式:先拿到絕對路徑,然后創(chuàng)建流
          //還是以example為例(className=java.util.Date),先拿到絕對路徑
        String path = Thread.currentThread().getContextClassLoader()
                .getResource("com/bjpowernode/java/bean/example").getPath();
        FileReader reader = new FileReader(path);
      
        // 第二種方式:直接返回一個流(InputStream)
        InputStream reader = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream("com/bjpowernode/java/bean/example");
 
        // 創(chuàng)建Map集合對象
        Properties pro = new Properties();
        pro.load(reader);
        reader.close();
        // 通過key獲取value
        String className = pro.getProperty("className");
 
        // 創(chuàng)建對象
        Class c = Class.forName(className);
        Object obj= c.newInstance();
        System.out.println(obj); // Wed Aug 03 17:00:36 CST 2022
 
    }
}

第三種方式:利用資源綁定器(常用)

(1)前兩種方式都需要創(chuàng)建一個流,而是用資源綁定器就不需要了!

(2)java.util包下提供了一個資源綁定器,便于獲取屬性配置文件中的內(nèi)容。

(3)使用這種方式的時候,屬性配置文件xxx.properties必須放到類路徑下。

資源綁定器,只能綁定xxx.properties文件。并且這個文件必須在類路徑下。文件擴展名也必須是properties

(4)并且在寫路徑的時候,路徑后面的擴展名.properties不能寫。

ResourceBundle boudle = ResourceBundle.getBundle("classinfo");
String className = boudle.getString("className");
package com.bjpowernode.java.reflect;
 
import java.util.ResourceBundle;
 
public class ResourceBundleTest {
    public static void main(String[] args) throws Exception {
        // 例如:classinfo.properties(className=java.util.Date)
        ResourceBundle boudle = ResourceBundle.getBundle("classinfo");
        // 通過key獲取value
        String className = boudle.getString("className");
        //System.out.println(className); // java.util.Date
        // 實例化對象
        Class c = Class.forName(className);
        Object obj = c.newInstance();
        System.out.println(obj); // Wed Aug 03 19:31:20 CST 2022
 
    }
}

6. 擴展:類加載器概述

關(guān)于JDK中自帶的類加載器:(不需要掌握)

(1)什么是類加載器?

專門負責加載類的命令/工具;ClassLoader

(2)JDK中自帶了3個類加載器

  • 啟動類加載器:rt.jar
  • 擴展類加載器:ext/*.jar
  • 應用類加載器:classpath

(3)假設(shè)有這樣一段代碼:String s = "abc"; 

代碼在開始執(zhí)行之前,會將所需要類全部加載到JVM當中。通過類加載器加載,看到以上代碼類加載器會找String.class文件,找到就加載,那么是怎么進行加載的呢?

首先通過“啟動類加載器”加載

注意:啟動類加載器專門加載:C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jarrt.jar中都是JDK最核心的類庫。

如果通過“啟動類加載器”加載不到的時候,然后會通過"擴展類加載器"加載

注意:擴展類加載器專門加載:C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\*.jar

如果“擴展類加載器”沒有加載到,那么會通過“應用類加載器”加載

注意:應用類加載器專門加載:classpath中的類。

(4)java中為了保證類加載的安全,使用了雙親委派機制。

優(yōu)先從啟動類加載器中加載,這個稱為“父”,“父”無法加載到,再從擴展類加載器中加載,這個稱為“母”。

雙親委派。如果都加載不到,才會考慮從應用類加載器中加載。直到加載到為止。

小總結(jié)

1、回顧反射機制

(1)什么是反射機制?反射機制有什么用?

反射機制:可以操作字節(jié)碼文件

作用:可以讓程序更加靈活

(2)反射機制相關(guān)的類在哪個包下?

java.lang.reflect.*;

(3)反射機制相關(guān)的主要的類?

java.lang.Class
java.lang.reflect.Method;
java.lang.reflect.Constructor;
java.lang.reflect.Field;

(4)在java中獲取Class的三種方式?

第一種:     

Class c = Class.forName("完整類名");

第二種:

Class c = 對象.getClass();

第三種:

Class c = int.class;

(5)獲取了Class之后,可以調(diào)用無參數(shù)構(gòu)造方法來實例化對象      

//c代表的就是日期Date類型
Class c = Class.forName("java.util.Date");
//實例化一個Date日期類型的對象
Object obj = c.newInstance();

一定要注意:

newInstance()底層調(diào)用的是該類型的無參數(shù)構(gòu)造方法。

如果沒有這個無參數(shù)構(gòu)造方法會出現(xiàn)"實例化"異常。

(6)如果你只想讓一個類的“靜態(tài)代碼塊”執(zhí)行的話,你可以怎么做?

Class.forName("該類的類名");這樣類就加載,類加載的時候,靜態(tài)代碼塊執(zhí)行!

(7)關(guān)于路徑問題?    

String path = Thread.currentThread().getContextClassLoader()
    .getResource("寫相對路徑,但是這個相對路徑從src出發(fā)開始找").getPath();    
 
String path = Thread.currentThread().getContextClassLoader()
    .getResource("abc").getPath();    //必須保證src下有abc文件。
 
String path = Thread.currentThread().getContextClassLoader()
    .getResource("a/db").getPath();    //必須保證src下有a目錄,a目錄下有db文件。

這種方式是為了獲取一個文件的絕對路徑。(通用方式,不會受到環(huán)境移植的影響)

但是該文件要求放在類路徑下,換句話說:也就是放到src下面。src下是類的根路徑。      

// 直接以流的形式返回:
InputStream in = Thread.currentThread().getContextClassLoader()
     .getResourceAsStream("com/bjpowernode/test.properties");

(8)IO流 + Properties集合,怎么快速綁定屬性資源文件?

// 第一:第一這個文件必須在類路徑(src)下
// 第二:這個文件必須是以.properties結(jié)尾,但是寫的時候不能帶上.properties。
ResourceBundle bundle = ResourceBundle.getBundle("com/bjpowernode/test");
String value = bundle.getString(key);

到此這篇關(guān)于JavaSE基礎(chǔ)之反射機制(反射Class)詳解的文章就介紹到這了,更多相關(guān)JavaSE反射機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot整合Canal方法詳解

    SpringBoot整合Canal方法詳解

    這篇文章主要介紹了SpringBoot整合Canal,canal可以用來監(jiān)控數(shù)據(jù)庫數(shù)據(jù)的變化,從而獲得新增數(shù)據(jù),或者修改的數(shù)據(jù),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
    2022-12-12
  • 詳解Java中Hibernate的基本原理

    詳解Java中Hibernate的基本原理

    持久化是將程序數(shù)據(jù)在持久狀態(tài)和瞬時狀態(tài)間轉(zhuǎn)換的機制。JDBC就是一種持久化機制。文件IO也是一種持久化機制。下面通過本文給大家介紹Java中Hibernate的基本原理,需要的朋友參考下吧
    2017-09-09
  • Java 十大排序算法之選擇排序刨析

    Java 十大排序算法之選擇排序刨析

    選擇排序是一種簡單直觀的排序算法,無論什么數(shù)據(jù)進去都是 O(n²) 的時間復雜度。所以用到它的時候,數(shù)據(jù)規(guī)模越小越好。唯一的好處可能就是不占用額外的內(nèi)存空間了吧
    2021-11-11
  • gateway網(wǎng)關(guān)接口請求的校驗方式

    gateway網(wǎng)關(guān)接口請求的校驗方式

    這篇文章主要介紹了gateway網(wǎng)關(guān)接口請求的校驗方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java使用apache commons連接ftp修改ftp文件名失敗原因

    java使用apache commons連接ftp修改ftp文件名失敗原因

    這篇文章主要介紹了java使用apache commons連接ftp修改ftp文件名失敗原因解析,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-08-08
  • 如何對Mysql數(shù)據(jù)表查詢出來的結(jié)果進行排序

    如何對Mysql數(shù)據(jù)表查詢出來的結(jié)果進行排序

    這篇文章主要介紹了如何對Mysql數(shù)據(jù)表查詢出來的結(jié)果進行排序問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Netty分布式行解碼器邏輯源碼解析

    Netty分布式行解碼器邏輯源碼解析

    這篇文章主要為大家介紹了Netty分布式行解碼器邏輯源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-03-03
  • SpringBoot之導入靜態(tài)資源詳解

    SpringBoot之導入靜態(tài)資源詳解

    今天帶大家學習SpringBoot導入靜態(tài)資源的過程,文中介紹的非常詳細,對正在學習java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • 一次因Java應用造成CPU過高的排查實踐過程

    一次因Java應用造成CPU過高的排查實踐過程

    一個應用占用CPU很高,除了確實是計算密集型應用之外,通常原因都是出現(xiàn)了死循環(huán)。下面這篇文章主要給大家介紹了一次因Java應用造成CPU過高的排查實踐過程,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2018-11-11
  • 淺析SpringBoot中常見的底層注解

    淺析SpringBoot中常見的底層注解

    Spring?Boot?是一個用于創(chuàng)建獨立的、基于Spring框架的Java應用程序的框架,它提供了許多注解,下面小編就來和大家介紹一些常見的底層注解吧
    2023-08-08

最新評論

鄂托克前旗| 茶陵县| 靖远县| 邢台市| 垫江县| 三穗县| 纳雍县| 马鞍山市| 聂拉木县| 东山县| 武定县| 淮安市| 额尔古纳市| 信宜市| 宾阳县| 安庆市| 漯河市| 南京市| 临安市| 武城县| 陵川县| 涿鹿县| 江孜县| 东丽区| 宽甸| 黔南| 南城县| 濉溪县| 元氏县| 台东市| 饶阳县| 沂南县| 鸡东县| 车险| 通辽市| 乌兰县| 富川| 礼泉县| 慈溪市| 马关县| 黄山市|