亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

一:反射機制概述

1、反射機制有什么用?

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

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

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

2、反射機制的相關類在哪個包下?

java.lang.reflect.*;   

3、反射機制相關的重要的類有哪些?

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

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

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

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

   // java.lang.Class:(整個是一個class)
            public class User{
                // Field (成員變量)
                int no;
 
                // Constructor(構造方法)
                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ù)構造方法,必須保證無參構造存在才可以;所以一旦我們寫上了有參構造方法,無參構造方法也要寫上! 如果有有參構造方法,而沒有寫無參構造方法會出現(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í)行結果:
                無參數(shù)構造方法
                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 {
    // 無參構造(不寫也行,默認會有)
    public User() {
        System.out.println("無參數(shù)構造方法");
    }
 
    // 有參構造寫了,無參構造必須寫;不然調(diào)用newInstance()會出現(xiàn)異常
    public User(String s) {
        System.out.println("無參數(shù)構造方法");
    }
 
}

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

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

(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關閉流
        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í)行結果:
            無參數(shù)構造方法
            com.bjpowernode.java.bean.User@4554617c
        */
 
        // 怎么體現(xiàn)靈活性?
        // 這里的代碼我們都不改變,只改變classinfo.properties配置文件
        // 例如改成:className=java.util.Date
        // 此時執(zhí)行的結果就變了: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í)行結果: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)境下也是沒問題的
        // 假設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
 
        // 假設有一個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. 擴展:類加載器概述

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

(1)什么是類加載器?

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

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

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

(3)假設有這樣一段代碼: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)先從啟動類加載器中加載,這個稱為“父”,“父”無法加載到,再從擴展類加載器中加載,這個稱為“母”。

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

小總結

1、回顧反射機制

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

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

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

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

java.lang.reflect.*;

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

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ù)構造方法來實例化對象      

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

一定要注意:

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

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

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

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

(7)關于路徑問題?    

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結尾,但是寫的時候不能帶上.properties。
ResourceBundle bundle = ResourceBundle.getBundle("com/bjpowernode/test");
String value = bundle.getString(key);

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

相關文章

  • 淺談一下Java中的堆和棧

    淺談一下Java中的堆和棧

    這篇文章主要介紹了一下Java中的堆和棧,Java數(shù)據(jù)類型在執(zhí)行過程中存儲在兩種不同形式的內(nèi)存中:棧和堆,它們通常由運行Java虛擬機(JVM)的底層平臺維護,需要的朋友可以參考下
    2023-04-04
  • Java_異常類(錯誤和異常,兩者的區(qū)別介紹)

    Java_異常類(錯誤和異常,兩者的區(qū)別介紹)

    下面小編就為大家?guī)硪黄狫ava_異常類(錯誤和異常,兩者的區(qū)別介紹) 。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-09-09
  • GraalVm的反射配置輔助工具agentlib配置及使用

    GraalVm的反射配置輔助工具agentlib配置及使用

    這篇文章主要為大家介紹了GraalVm的反射配置輔助工具agentlib的配置文件及使用說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-02-02
  • Dubbo服務校驗參數(shù)的解決方案

    Dubbo服務校驗參數(shù)的解決方案

    這篇文章主要介紹了Dubbo服務如何優(yōu)雅的校驗參數(shù),Dubbo框架本身是支持參數(shù)校驗的,同時也是基于JSR303去實現(xiàn)的,今天通過示例代碼介紹下詳細實現(xiàn)過程,需要的朋友可以參考下
    2022-03-03
  • JAVA中的注解機制解讀

    JAVA中的注解機制解讀

    這篇文章主要介紹了JAVA中的注解機制解讀,通過調(diào)用Java的反射機制相關API來訪問annotation信息,首先加載使用注解的類,得到class類,然后再得到類相應的方法,成員變量,需要的朋友可以參考下
    2023-10-10
  • springboot bean循環(huán)依賴實現(xiàn)以及源碼分析

    springboot bean循環(huán)依賴實現(xiàn)以及源碼分析

    最近在使用Springboot做項目的時候,遇到了一個循環(huán)依賴的 問題,所以下面這篇文章主要給大家介紹了關于springboot bean循環(huán)依賴實現(xiàn)以及源碼分析的相關資料,需要的朋友可以參考下
    2021-06-06
  • Spring Cloud Gateway 獲取請求體(Request Body)的多種方法

    Spring Cloud Gateway 獲取請求體(Request Body)的多種方法

    這篇文章主要介紹了Spring Cloud Gateway 獲取請求體(Request Body)的多種方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • Spring Boot實現(xiàn)動態(tài)更新任務的方法

    Spring Boot實現(xiàn)動態(tài)更新任務的方法

    這篇文章主要介紹了Spring Boot實現(xiàn)動態(tài)更新任務的方法,文中給出了詳細的示例代碼供大家參考學習,對大家學習使用Spring Boot動態(tài)更新任務具有一定的參考價值,需要的朋友們來一起看看吧。
    2017-04-04
  • Java中遍歷Map的多種方法示例及優(yōu)缺點總結

    Java中遍歷Map的多種方法示例及優(yōu)缺點總結

    在java中遍歷Map有不少的方法,下面這篇文章主要給大家介紹了關于Java中遍歷Map的多種方法,以及各種方法的優(yōu)缺點總結,文中通過示例代碼介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
    2017-07-07
  • SpringBoot 之啟動流程詳解

    SpringBoot 之啟動流程詳解

    SpringBoot 是一個基于 Spring 框架的快速開發(fā)框架,旨在簡化 Spring 應用程序的開發(fā)和部署。在本文中,我們將深入分析 SpringBoot 啟動過程的源代碼,并提供必要的解釋和說明
    2023-04-04

最新評論