国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java 反射

nodejh / 1862人閱讀

摘要:反射的使用通過反射獲取構造方法并使用首先我們聲明一個類方便我們進行介紹默認的構造方法默認的構造方法無參構造方法調用了公有無參構造方法執行了。。。

1.概述 1.1 什么是反射

java反射機制是指在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法,對于任意一個對象,都能調用它的任意一個方法和屬性,這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。

1.2 為什么要使用反射

正常的要實例化一個對象并調用sayHello方法

ClassA objA = new ClassA();
objA.sayHello();

通過反射去實例化一個對象并調用sayHello方法

Class objA = Class.forName("com.spring.fanshe.Human");
Method method = objA.getMethod("sayHello");
method.invoke(objA.newInstance);

在source階段實際上二者并無任何區別,反射也沒有體現出任何的優勢,那么任何一個java開發人員必然會問為什么要使用反射?

反射的重點在于runtime階段的獲取類信息和調用類方法,那么當你的編碼過程中有“部分信息是source階段不清晰,需要在runtime階段動態臨時加載”這種場景,反射就可以派上用場了

我們考慮幾個編碼場景:

編碼階段不知道需要實例化的類名是哪個,需要在runtime從配置文件中加載:

Class clazz = class.forName("xxx.xxx.xxx")
clazz.newInstance();

在runtime階段,需要臨時訪問類的某個私有屬性

ClassA objA = new ClassA();
Field xxx = objA.getClass().getDeclaredField("xxx")
xxx.setAccessible(true);

所以,反射的優點在于“有些編碼需求在source階段無法實現,只能在runtime階段通過反射實現”,而非“source階段正常編碼方式能解決的,反射的方式能解決的更好”,所以比較反射和正常編碼方式的優劣是沒有意義的,反射解決的是正常編碼無法解決的編碼場景,如果正常編碼方式可以解決的,強行使用反射反而是毫無意義的,編碼不是為了show技巧。

2. Class類的介紹

Class類的實例表示正在運行的Java應用程序中的類和接口,也就是JVM中有N多的實例,每個類都有該Class對象(包括基本數據類型)

Class類沒有公共構造方法,Class對象是在加載類時由jvm以及通過調用類加載器中的defineClass方法自動構造的。也就是這不需要我們自己去處理創建,JVM已經幫我們創建好了。

如果我們應用反射來在運行時得到類的信息,根據類的那些信息做一些特定的操作,那么,首先毫無疑問的就是得到類的信息,在JDK中提供Class對象來保存類的信息,所以,反射的第一步就是得到Class對象。在JDK中提供了三種方式得到Class對象

這三種方式請看如下代碼:

public static void main(String[] args) {

        //第一種方式獲取Class對象
        Student stu1 = new Student();//這一new 產生一個Student對象,一個Class對象。
        Class stuClass = stu1.getClass();//獲取Class對象
        System.out.println(stuClass.getName());


        //第二種方式獲取Class對象
        Class stuClass2 = Student.class;
        System.out.println(stuClass == stuClass2);//判斷第一種方式獲取的Class對象和第二種方式獲取的是否是同一個


        //第三種方式獲取Class對象
        try {
            Class stuClass3 = Class.forName("com.spring.fanshe.Student");//注意此字符串必須是真實路徑,就是帶包名的類路徑,包名.類名
            System.out.println(stuClass3 == stuClass2);//判斷三種方式是否獲取的是同一個Class對象
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

}

運行結果:

調用了公有、無參構造方法執行了。。。
com.spring.fanshe.Student
true
true

注意:在運行期間,一個類,只有一個Class對象產生
上面得到Class對象的方式中,常用第三種,第一種對象都有了還要反射干什么,第二種需要導入類的包,依賴太強,不導包就拋編譯錯誤。一般都用第三種,一個字符串可以傳入也可以寫在配置文件中等多種方法。

3. 反射的使用 3.1 通過反射獲取構造方法并使用

首先我們聲明一個Student類方便我們進行介紹:

public class Student {

    //(默認的構造方法)
    Student(String str){
        System.out.println("(默認)的構造方法 s = " + str);
    }

    //無參構造方法
    public Student(){
        System.out.println("調用了公有、無參構造方法執行了。。。");
    }

    //有一個參數的構造方法
    public Student(char name){
        System.out.println("姓名:" + name);
    }

    //有多個參數的構造方法
    public Student(String name ,int age){
        System.out.println("姓名:"+name+"年齡:"+ age);
    }

    //受保護的構造方法
    protected Student(boolean n){
        System.out.println("受保護的構造方法 n = " + n);
    }

    //私有構造方法
    private Student(int age){
        System.out.println("私有的構造方法   年齡:"+ age);
    }
}

測試類

通過Class對象可以獲取某個類中的:構造方法、成員變量、成員方法;并訪問成員;

/* 
 * 通過Class對象可以獲取某個類中的:構造方法、成員變量、成員方法;并訪問成員; 
 *  
 * 1.獲取構造方法: 
 *      1).批量的方法: 
 *          public Constructor[] getConstructors():所有"公有的"構造方法 
            public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、默認、公有) 
      
 *      2).獲取單個的方法,并調用: 
 *          public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法: 
 *          public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"可以是私有的,或受保護、默認、公有; 
 *       
 *          調用構造方法: 
 *          Constructor-->newInstance(Object... initargs) 
 */  
public class Constructors {
    public static void main(String[] args) throws Exception {
        //1.加載Class對象
        Class clazz = Class.forName("com.spring.fanshe.Student");


        System.out.println("**********************所有公有構造方法*********************************");
        Constructor[] conArray = clazz.getConstructors();
        for(Constructor c : conArray){
            System.out.println(c);
        }


        System.out.println("************所有的構造方法(包括:私有、受保護、默認、公有)***************");
        conArray = clazz.getDeclaredConstructors();
        for(Constructor c : conArray){
            System.out.println(c);
        }

        System.out.println("*****************獲取公有、無參的構造方法*******************************");
        Constructor con = clazz.getConstructor();
        System.out.println("con = " + con);
        //調用構造方法
        Object obj = con.newInstance();
        System.out.println("obj = " + obj);

        System.out.println("******************獲取私有構造方法,并調用*******************************");
        con = clazz.getDeclaredConstructor(int.class);
        System.out.println(con);
        //調用構造方法
        con.setAccessible(true);//暴力訪問(忽略掉訪問修飾符)
        obj = con.newInstance(25);
    }
}

運行結果如下:

**********************所有公有構造方法*********************************
public com.spring.fanshe.Student(java.lang.String,int)
public com.spring.fanshe.Student(char)
public com.spring.fanshe.Student()
************所有的構造方法(包括:私有、受保護、默認、公有)***************
private com.spring.fanshe.Student(int)
protected com.spring.fanshe.Student(boolean)
public com.spring.fanshe.Student(java.lang.String,int)
public com.spring.fanshe.Student(char)
public com.spring.fanshe.Student()
com.spring.fanshe.Student(java.lang.String)
*****************獲取公有、無參的構造方法*******************************
con = public com.spring.fanshe.Student()
調用了公有、無參構造方法執行了。。。
obj = com.spring.fanshe.Student@60e53b93
******************獲取私有構造方法,并調用*******************************
private com.spring.fanshe.Student(int)
私有的構造方法   年齡:25
3.2 獲取成員變量并調用

聲明一個Person類,定義了各種類型和修飾符的成員變量

public class Person {

    public String name;
    protected int age;
    char sex;
    private String phoneNum;

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", sex=" + sex
                + ", phoneNum=" + phoneNum + "]";
    }
}

測試類

/* 
 * 獲取成員變量并調用: 
 *  
 * 1.批量的 
 *      1).Field[] getFields():獲取所有的"公有字段" 
 *      2).Field[] getDeclaredFields():獲取所有字段,包括:私有、受保護、默認、公有; 
 * 2.獲取單個的: 
 *      1).public Field getField(String fieldName):獲取某個"公有的"字段; 
 *      2).public Field getDeclaredField(String fieldName):獲取某個字段(可以是私有的) 
 *  
 *   設置字段的值: 
 *      Field --> public void set(Object obj,Object value): 
 *                  參數說明: 
 *                  1.obj:要設置的字段所在的對象; 
 *                  2.value:要為字段設置的值; 
 *  
 */  
 
public static void main(String[] args) throws Exception {
        //1.獲取Class對象  
        Class personClass = Class.forName("com.spring.fanshe.Person");
        //2.獲取字段  
        System.out.println("************獲取所有公有的字段********************");
        Field[] fieldArray = personClass.getFields();
        for(Field f : fieldArray){
            System.out.println(f);
        }
        System.out.println("************獲取所有的字段(包括私有、受保護、默認的)********************");
        fieldArray = personClass.getDeclaredFields();
        for(Field f : fieldArray){
            System.out.println(f);
        }
        System.out.println("*************獲取公有字段**并調用***********************************");
        Field f = personClass.getField("name");
        System.out.println(f);
        //獲取一個對象  
        Object obj = personClass.getConstructor().newInstance();//產生Person對象--》Person person = new Person();  
        //為字段設置值  
        f.set(obj, "劉德華");//為Person對象中的name屬性賦值--》person.name = "劉德華"  
        //驗證  
        Person person = (Person)obj;
        System.out.println("驗證姓名:" + person.name);


        System.out.println("**************獲取私有字段****并調用********************************");
        f = personClass.getDeclaredField("phoneNum");
        System.out.println(f);
        f.setAccessible(true);//暴力反射,解除私有限定  
        f.set(obj, "18888889999");
        System.out.println("驗證電話:" + person);

    }

運行結果如下:

************獲取所有公有的字段********************
public java.lang.String com.spring.fanshe.Person.name
************獲取所有的字段(包括私有、受保護、默認的)********************
public java.lang.String com.spring.fanshe.Person.name
protected int com.spring.fanshe.Person.age
char com.spring.fanshe.Person.sex
private java.lang.String com.spring.fanshe.Person.phoneNum
*************獲取公有字段**并調用***********************************
public java.lang.String com.spring.fanshe.Person.name
驗證姓名:劉德華
**************獲取私有字段****并調用********************************
private java.lang.String com.spring.fanshe.Person.phoneNum
驗證電話:Person [name=劉德華, age=0, sex= , phoneNum=18888889999]
3.3 獲取成員方法并調用

我們創建一個Human類,定義了3種成員方法,不同參數列表和不同的訪問修飾符

public class Human {

    public void show1(String s){
        System.out.println("調用了:公有的,String參數的show1(): s = " + s);
    }
    protected void show2(){
        System.out.println("調用了:受保護的,無參的show2()");
    }
    void show3(){
        System.out.println("調用了:默認的,無參的show3()");
    }
    private String show4(int age){
        System.out.println("調用了,私有的,并且有返回值的,int參數的show4(): age = " + age);
        return "abcd";
    }
}

測試類:

/* 
 * 獲取成員方法并調用: 
 *  
 * 1.批量的: 
 *      public Method[] getMethods():獲取所有"公有方法";(包含了父類的方法也包含Object類) 
 *      public Method[] getDeclaredMethods():獲取所有的成員方法,包括私有的(不包括繼承的) 
 * 2.獲取單個的: 
 *      public Method getMethod(String name,Class... parameterTypes): 
 *                  參數: 
 *                      name : 方法名; 
 *                      Class ... : 形參的Class類型對象 
 *      public Method getDeclaredMethod(String name,Class... parameterTypes) 
 *  
 *   調用方法: 
 *      Method --> public Object invoke(Object obj,Object... args): 
 *                  參數說明: 
 *                  obj : 要調用方法的對象; 
 *                  args:調用方式時所傳遞的實參; 
 */  
 
 
public static void main(String[] args) throws Exception {
        //獲取Class對象
        Class humClass = Class.forName("com.spring.fanshe.Human");


        System.out.println("***************獲取所有的”公有“方法*******************");
        humClass.getMethods();
        Method[] methodArray = humClass.getMethods();
        for (Method m : methodArray) {
            System.out.println(m);
        }


        System.out.println("***************獲取所有的方法,包括私有的*******************");
        methodArray = humClass.getDeclaredMethods();
        for (Method m : methodArray) {
            System.out.println(m);
        }


        System.out.println("***************獲取公有的show1()方法*******************");
        Method m = humClass.getMethod("show1", String.class);
        System.out.println(m);
        //實例化一個humdent對象  
        Object obj = humClass.newInstance();
        m.invoke(obj, "劉德華");


        System.out.println("***************獲取私有的show4()方法******************");
        m = humClass.getDeclaredMethod("show4", int.class);
        System.out.println(m);
        m.setAccessible(true);//解除私有限定  
        Object result = m.invoke(obj, 20);//需要兩個參數,一個是要調用的對象(獲取有反射),一個是實參  
        System.out.println("返回值:" + result);
    }

運行結果如下:

***************獲取所有的”公有“方法*******************
public void com.spring.fanshe.Human.show1(java.lang.String)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
***************獲取所有的方法,包括私有的*******************
public void com.spring.fanshe.Human.show1(java.lang.String)
private java.lang.String com.spring.fanshe.Human.show4(int)
void com.spring.fanshe.Human.show3()
protected void com.spring.fanshe.Human.show2()
***************獲取公有的show1()方法*******************
public void com.spring.fanshe.Human.show1(java.lang.String)
調用了:公有的,String參數的show1(): s = 劉德華
***************獲取私有的show4()方法******************
private java.lang.String com.spring.fanshe.Human.show4(int)
調用了,私有的,并且有返回值的,int參數的show4(): age = 20
返回值:abcd
3.4 通過反射運行配置文件內容

student類:

public class Book {  
    public void show(){  
        System.out.println("is show()");  
    }  
}

配置文件以txt文件為例子(1.txt):

className = cn.fanshe.Student  
methodName = show

測試類:

/*
 * 我們利用反射和配置文件,可以使:應用程序更新時,對源碼無需進行任何修改
 * 我們只需要將新類發送給客戶端,并修改配置文件即可
 */
public class BookClass {

    public static void main(String[] args) throws Exception {
        //通過反射獲取Class對象
        Class stuClass = Class.forName(getValue("className"));//"cn.fanshe.Student"
        //2獲取show()方法
        Method m = stuClass.getMethod(getValue("methodName"));//show
        //3.調用show()方法
        m.invoke(stuClass.getConstructor().newInstance());

    }

    //此方法接收一個key,在配置文件中獲取相應的value
    public static String getValue(String key) throws IOException {
        Properties pro = new Properties();//獲取配置文件的對象
        FileReader in = new FileReader("F:projectwhy-springsrcmain
esources1.txt");//獲取輸入流
        pro.load(in);//將流加載到配置文件對象中
        in.close();
        return pro.getProperty(key);//返回根據key獲取的value值
    }

}

看到這里有沒有想起Spring中配置Bean的XML文件:

3.5 通過反射越過泛型檢查

如下面方法所示,

public static void main(String[] args) throws Exception{
        ArrayList strList = new ArrayList<>();
        strList.add("aaa");
        strList.add("bbb");
        
        //在聲明泛型為String的類型的ArrayList中添加int類型
        strList.add(100);

        

        //遍歷集合
        for(Object obj : strList){
            System.out.println(obj);
        }
    }

運行結果:

Error:(16, 16) java: 對于add(int), 找不到合適的方法
    方法 java.util.Collection.add(java.lang.String)不適用
      (參數不匹配; int無法轉換為java.lang.String)

但是通過反射我們就可以繞過泛型檢查,將int類型的值100添加到泛型為String的ArrayList 中,如下代碼所示:

    public static void main(String[] args) throws Exception{
        ArrayList strList = new ArrayList<>();
        strList.add("aaa");
        strList.add("bbb");
//        strList.add(100);
        //獲取ArrayList的Class對象,反向的調用add()方法,添加數據
        Class listClass = strList.getClass(); //得到 strList 對象的字節碼 對象
        //獲取add()方法
        Method m = listClass.getMethod("add", Object.class);
        //調用add()方法
        m.invoke(strList, 100);

        //遍歷集合
        for(Object obj : strList){
            System.out.println(obj);
        }
    }

運行結果:

aaa
bbb
100
4. 反射的應用

在Spring的配置文件中,經??吹饺缦屡渲茫?/p>

那么通過這樣配置,Spring是怎么幫我們實例化對象,并且放到容器中去了了?對,就是通過反射!??!
下面是Spring通過配置進行實例化對象,并放到容器中的偽代碼:

//解析元素的id屬性得到該字符串值為“courseDao”  
String idStr = "courseDao";  
//解析元素的class屬性得到該字符串值為“com.qcjy.learning.Dao.impl.CourseDaoImpl”  
String classStr = "com.qcjy.learning.Dao.impl.CourseDaoImpl";  
//利用反射知識,通過classStr獲取Class類對象  
Class cls = Class.forName(classStr);  
//實例化對象  
Object obj = cls.newInstance();  
//container表示Spring容器  
container.put(idStr, obj);

通過解析xml文件,獲取到id屬性和class屬性里面的內容,利用反射原理獲取到配置里面類的實例對象,存入到Spring的bean容器中。

當一個類里面需要應用另一類的對象時,Spring的配置如下所示:

  
       
       

我們繼續用偽代碼的形式來模擬實現一下Spring底層處理原理:

//解析元素的name屬性得到該字符串值為“courseDao”  
String nameStr = "courseDao";  
//解析元素的ref屬性得到該字符串值為“courseDao”  
String refStr = "courseDao";  
//生成將要調用setter方法名  
String setterName = "set" + nameStr.substring(0, 1).toUpperCase()  
        + nameStr.substring(1);  
//獲取spring容器中名為refStr的Bean,該Bean將會作為傳入參數  
Object paramBean = container.get(refStr);  
//獲取setter方法的Method類,此處的cls是剛才反射代碼得到的Class對象  
Method setter = cls.getMethod(setterName, paramBean.getClass());  
//調用invoke()方法,此處的obj是剛才反射代碼得到的Object對象  
setter.invoke(obj, paramBean);

通過上面對Spring底層原理的分析,可以發現,其實并不難,用到的都是反射機制,通過反射實例化對象,存入到Spring的bean容器中。

只要在代碼或配置文件中看到類的完整路徑(包.類),其底層原理基本上使用的就是Java的反射機制。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/74094.html

相關文章

  • Java筆記-反射機制(一)

    摘要:反射機制一結合官方通過編寫的反射教程,復習一下反射的知識。反射的概念反射是一種在運行時獲取以及修改應用行為的一種工具。因為反射需要動態的解析類的信息,相比于非反射使用的方式要慢。反射需要獲取一定的運行時權限,在特定的安全環境下不一定存在。 Java反射機制(一) 結合Oracle官方通過JDK8編寫的反射教程,復習一下反射的知識。結尾篇補一個小例子。 主要內容 這次博客的主要內容就是簡...

    AWang 評論0 收藏0
  • Java 反射教程

    摘要:反射非常強大和有用。另外,反射可以用在映射結果集的列名到對象的方法。本教程將深入介紹反射。本教程還將清除一些關于范型信息在運行時可用性的認知混淆。類對象使用反射時,起點通常是需要使用反射檢視的類的對象。 Java反射可以在運行時檢視類、接口、屬性和方法,而無需在編譯時知道類名、方法名等等。它也同樣使用反射支持實例化新的對象、調用方法和get/set屬性值。 Java反射非常強大和有用...

    klivitamJ 評論0 收藏0
  • Java反射詳細介紹

    摘要:通過反射獲取帶參無返回值成員方法并使用設置安全檢查,訪問私有構造函數必須創建實例這種不行,注意和方法需要傳遞參數測試復制這個功能獲取私有方法,同樣注意和的區別賦予訪問權限調用方法。 反射 目錄介紹 1.反射概述 1.1 反射概述 1.2 獲取class文件對象的三種方式 1.3 反射常用的方法介紹 1.4 反射的定義 1.5 反射的組成 1.6 反射的作用有哪些 2.反射的...

    ingood 評論0 收藏0
  • Java反射學習小記

    摘要:反射使用類對象提供的基本元數據,能從類對象中找出方法或字段的名稱,然后獲取表示方法或字段的對象。常見的反射手段有反射和反射。以之前的反射為例其中指定了方法的返回類型,其實不止如此。 Java反射機制主要提供了以下功能: 在運行時判斷任意一個對象所屬的類 在運行時構造任意一個類的對象 在運行時判斷任意一個類所具有的成員變量和方法 在運行時調用任意一個對象的方法 生成動態代理 很多框架...

    frank_fun 評論0 收藏0
  • Reflection:Java反射機制的應用場景

    近期在維護公司項目的時候遇到一個問題,因為實體類中的 set 方法涉及到了業務邏輯,因此在給對象賦值的過程中不能夠使用 set 方法,為了實現功能,所以采用了反射的機制給對象屬性賦值,借此機會也了解了反射的一些具體用法和使用場景,分以下兩點對反射進行分析: 反射的優勢和劣勢 反射的應用場景 反射的優勢和劣勢 ??個人理解,反射機制實際上就是上帝模式,如果說方法的調用是 Java 正確的打開方式...

    浠ラ箍 評論0 收藏0
  • 樂字節Java反射之一:反射概念與獲取反射源頭class

    摘要:一反射機制概念程序運行時,允許改變程序結構或變量類型,這種語言稱為動態語言,如,是動態語言顯然,,不是動態語言,但是有著一個非常突出的動態相關機制。相關的為二獲取源頭重點打開權限所有類的對象其實都是的實例。 一、Java反射機制概念 程序運行時,允許改變程序結構或變量類型,這種語言稱為動態語言,如Python, Ruby是動態語言;顯然C++,Java,C#不是動態語言,但是JAVA有...

    caikeal 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<