欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java中的反射及其優(yōu)點說明

 更新時間:2022年05月11日 14:34:03   作者:TimeTDIT  
這篇文章主要介紹了java中的反射及其優(yōu)點說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

java反射及優(yōu)點

反射是java的一大特性,而且是有些框架實現(xiàn)了IoC/DI的原理,本文就來探討下java中的反射及其優(yōu)點。

首先是普通的java靜態(tài)類加載,java靜態(tài)類是通過new實現(xiàn)的,在編譯時刻就要加載所有可能用到的類,這樣實際上存在一些缺點的,比如只要有一個類沒有找到或者出現(xiàn)重大的問題編譯便不會通過,導致其他存在的類也無法使用。另一方面,如果要加載其他的類就要重新進行編譯,有的時候是非常不方便的。下面就引入反射機制來動態(tài)加載類來解決這個問題。

首先創(chuàng)建一個ClassInterface接口,放在com.classTest包下:

package com.classTest;?
public interface ClassInterface {
? ? public void start(); ? ? ? //接口約定start()方法
}

然后分別使用Class1Impl和Class2Impl類去實現(xiàn)這個接口,也放在com.classTest包下:

package com.classTest;?
public class Class1Impl implements ClassInterface {
?
? ? @Override
? ? public void start() {
? ? ? ? // TODO Auto-generated method stub
? ? ? ? System.out.println("This is Class1Impl"); ? //實現(xiàn)start()
? ? }
}
package com.classTest;?
public class Class2Impl implements ClassInterface {
?
? ? @Override
? ? public void start() {
? ? ? ? // TODO Auto-generated method stub
? ? ? ? System.out.println("This is Class2Impl"); ? //實現(xiàn)start()
? ? }?
}

下面先用正常的類加載來說明正常類加載的缺點:

package com.test;?
import java.util.Scanner;?
import com.classTest.ClassInterface;
?
public class LoadClassTest {
? ? ClassInterface c1 = new Class1Impl();
? ? ClassInterface c2 = new Class2Impl();
? ? c1.start();
? ? c2.start();
}

上面是正常的new方法生成的對象,然后調用接口里的方法,但是一旦Class1Impl類或者Class2Impl類沒有,那有的哪個類也就無法使用,而且想要使用新的ClassInterface接口下的方法還是需要重新寫類,重新寫測試方法,重新生成測試對象,重新編譯...

下面介紹利用反射機制動態(tài)加載類來解決這個問題:

package com.test;?
import java.util.Scanner;?
import com.classTest.ClassInterface;
?
public class LoadClassTest {
? ? public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
? ? ? ? //new 創(chuàng)建對象是靜態(tài)加載類,在編譯時刻就需要加載所有可能用到的類
? ? ? ? //動態(tài)記載類可以解決這個問題
? ? ? ? Scanner sc = new Scanner(System.in);
? ? ? ? String className = sc.nextLine();
? ? ? ? //動態(tài)加載類,在運行的時刻進行加載
? ? ? ? //使用類類型(class type) 通過Class這個類的forName(className)方法動態(tài)創(chuàng)建類對象
? ? ? ? Class c = Class.forName(className);
? ? ? ? //通過類類型 用newInstance()方法創(chuàng)建該類對象
? ? ? ? ClassInterface ci = (ClassInterface) c.newInstance();
? ? ? ? ci.start();//動態(tài)加載類 調用其方法
? ? }
}

有沒有看出這其中的差異,想要加載其他類只需要輸入另外的類名即可(這里的類名是包含包的),forName()方法可以通過類名動態(tài)創(chuàng)建類類型的對象,然后用類類型的對象的newInstance()方法創(chuàng)建該類類型對象(也就是一個類)的對象(調用newInstance()方法的類類型對象需要進行轉化),之后就可以用生成對象調用接口下的方法了。

那這時候可能就會有人問了,要是在我們不知道接口名稱為ClassInterface的情況下,我們該如何訪問className這個類類型生成的c這個類對象下面的方法呢?我們來實現(xiàn)一下:

Class c = Class.forName("com.classTest.Foo");//創(chuàng)建一個類對象c
Method m1 = c.getMethod("fun1", int.class,int.class);//通過getMethod方法獲取c的方法,第一個參數(shù)表示想要獲取的方法名稱fun1,之后的參數(shù)列表表示fun1這個函數(shù)的所有參數(shù)的類類型。
Object o = m1.invoke(foo1,new Object[]{10,20} );//通過invoke方法來調用我們前面通過getMethod()獲得的方法,第一個參數(shù)表示執(zhí)行我們所獲得方法的對象,第二個參數(shù)表示我們所獲取方法的參數(shù),這里是兩個int類型。如果沒有返回值返回null,有返回值則返回具體的返回值,這里將返回結果保存在o對象里。

這樣的優(yōu)點是顯而易見的,類無需在編譯前全部加載,而且修改接口實現(xiàn)類的時候也不用重新編譯。

這只是反射的一小部分,但是也是很重要的一部分,也是Spring中IoC/DI的實現(xiàn)基礎。

(另外告訴大家一個小tip:所謂的泛型數(shù)據容器的數(shù)據類型(也就是HashMap<String,String>中的<String,String>)不能寫入其他數(shù)據類型實際上只是存在于編譯層面的,是為了防止開發(fā)者往里面誤寫入自己不想寫入的東西,然而通過泛型可以跳過編譯層面實現(xiàn)往這個泛型數(shù)據容器里存入和這個泛型數(shù)據容器數(shù)據類型不一樣的數(shù)據,雖然這樣之后用foreach遍歷就會報錯...)

java反射機制(Reflection)

1.什么是反射?反射有什么作用?

能夠分析類能力的程序稱為反射。反射機制允許程序在運行狀態(tài)借助Reflection API取得任何類的內部信息,并能直接操作任意對象的內部屬性及方法。

反射機制的作用

  • 在運行時判斷任意一個對象所屬的類
  • 在運行時構造任意一個類的對象
  • 在運行時判斷任意一個類所具有的成員變量和方法
  • 在運行時調用任意一個對象的成員變量和方法
  • 在運行時獲取泛型信息
  • 在運行時處理注解
  • 生成 動態(tài)代理

2.反射相關的主要API

  • java.lang.Class:代表一個類
  • java.lang.reflect.Method:代表類的方法
  • java.lang.reflect. Field:代表類的成員變量
  • java.lang.reflect.Constructor:代表類的構造器

3.什么是Class類

對Class類的深入理解

  • Class本身也是一個類
  • Class 對象只能由系統(tǒng)建立對象(Class 對象是在加載類時由Java 虛擬機以及通過調用類加載器中的 defineClass 方法自動構造的)
  • 一個類在 JVM 中只會有一個Class實例
  • 一個Class對象對應的是一個加載到JVM中的一個.class文件
  • 每個類的實例都會記得自己是由哪個 Class 實例所生成
  • 通過Class可以完整地得到一個類中的完整結構

類的加載過程:

程序經過javac.exe命令以后,會生成一 個或多個字節(jié)碼文件(.class結尾)。

接著我們使用java.exe命令對某個字節(jié)碼文件進行解釋運行。相當于將某個字節(jié)碼文件加載到內存中。此過程就稱為類的加載。加載到內存中的類,我們就稱為運行時類,此運行時類,就作為CLass的一個實例。

java.Lang.Class實例的獲?。ㄋ姆N方式) 

package package03;
import org.junit.Test;
public class ReflectiveTeat01 {
    //獲取 Class 類的實例
    @Test
    public void test01() throws Exception {
        //方式一:通過調用運行時類得屬性:.class
        Class clazz1 = Person.class;
        System.out.println(clazz1);//class package03.Person
        //方式二:通過運行時類的對象,調用 getClass() 方法
        Person p1 = new Person();
        Class clazz2 = p1.getClass();
        System.out.println(clazz2);//class package03.Person
        //方式三:調用 Class 的靜態(tài)方法:forName(String classPath)
        Class clazz3 = Class.forName("package03.Person");
        System.out.println(clazz3);//class package03.Person
        //方法四:使用類的加載器:ClassLoader
        ClassLoader classLoader = ReflectiveTeat01.class.getClassLoader();
        Class clazz4 = classLoader. loadClass("package03.Person") ;
        System. out . println(clazz4);//class package03.Person
    }
}

4.調用運行時類的指定結構

如何操作運行時類中指定的屬性

@Test
    public void testField() throws Exception {
        Class clazz = Person.class;
        //創(chuàng)建運行時類的對象 P
        Person p = (Person) clazz.newInstance();
        //獲取指定的屬性
        Field fieldName = clazz.getDeclaredField("id");
        //fieldName 要操作的屬性名賦值給 fieldName 變量名
        
        //保證當前屬性是可訪問的
        fieldName .setAccessible(true);
        /*
        設置當前屬性的值
        set():參數(shù)1:指明設置哪個對象的屬性
              參數(shù)2:將此屬性值設置為多少
         */
        fieldName.set(p,1001);
        /*
        獲取當前屬性的值
        get():參數(shù)1:獲取哪個對象的當前屬性值
         */
        int intName = (int) fieldName.get(p);
        System.out.println(intName );
    }

操作運行時類的方法

已調用 show 方法例子:該方法有 注解,參數(shù),返回值,權限?。╬rivate)

@MyAnonotation//自定義注解
? ? private String show(String nation) {
? ? ? ? System.out.println("我的國籍是:" + nation);
? ? ? ? return nation;
? ? }
 @Test
    public void testMethod() throws Exception {
        Class clazz = Person.class;
        //創(chuàng)建運行時類對象
        Person p = (Person) clazz.newInstance();
       /* 1.獲取指定的某個方法
       getDeclaredMethod():參數(shù)1:指明獲取的方法的名稱
                           參數(shù)2:指明獲取的方法的形參列表
       * */
        Method show = clazz.getDeclaredMethod("show", String.class);
        //2.保證當前方法時可訪問的
        show.setAccessible(true);
        /*
        3.調用方法的invoke():參數(shù)1:方法的調用者
                            參數(shù)2:給方法形參賦值的實參
          invoke()方法的返回值即為對應類中調用的方法的返回值
         */
        show.invoke(p, "CHN");
        
        //調用靜態(tài)方法時:
        //private static void showDesc()
        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
        //如果調用的運行時類中的方法沒有返回值,則 invoke() 返回 null
        Object invoke = showDesc.invoke(Person.class);
        System.out.println(invoke);
    }

上面代碼用到的 Person 類

public class Person {
    private String name;
    private int age;
    public int id;
    //空參構造器
    public Person() {
    }
    //全參構造器
    public Person(String name, int age, int id) {
        this.name = name;
        this.age = age;
        this.id = id;
    }
    @MyAnonotation
    private String show(String nation) {
        System.out.println("我的國籍是:" + nation);
        return nation;
    }
    //靜態(tài)方法
    private static void showDesc(){
        System.out.println("我是一個可愛的人");
    }
    // get、set 方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Java比較兩個List的值是否相等的方法

    Java比較兩個List的值是否相等的方法

    這篇文章主要介紹了Java比較兩個List的值是否相等的方法,涉及java針對隊列比較的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • springboot如何從數(shù)據庫獲取數(shù)據,用echarts顯示(數(shù)據可視化)

    springboot如何從數(shù)據庫獲取數(shù)據,用echarts顯示(數(shù)據可視化)

    這篇文章主要介紹了springboot如何從數(shù)據庫獲取數(shù)據,用echarts顯示(數(shù)據可視化),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Java的內存分配與回收策略詳解

    Java的內存分配與回收策略詳解

    這篇文章主要介紹了Java的內存分配與回收策略詳解,對象的內存分配,就是在堆上分配,對象主要分配在新生代的 Eden 區(qū)上,少數(shù)情況下可能直接分配在老年代,分配規(guī)則不固定,取決于當前使用的垃圾收集器組合以及相關的參數(shù)配置,需要的朋友可以參考下
    2023-08-08
  • IDEA啟動tomcat控制臺中文亂碼問題的解決方法(100%有效)

    IDEA啟動tomcat控制臺中文亂碼問題的解決方法(100%有效)

    很多人在idea中啟動項目時會出現(xiàn)控制臺的中文亂碼,其實也無傷大雅,但是本人看著不舒服,下面這篇文章主要給大家介紹了關于IDEA啟動tomcat控制臺中文亂碼問題的解決方法,需要的朋友可以參考下
    2022-09-09
  • 淺析 ArrayList 和 LinkedList 有什么區(qū)別

    淺析 ArrayList 和 LinkedList 有什么區(qū)別

    ArrayList 和 LinkedList 有什么區(qū)別,是面試官非常喜歡問的一個問題。今天通過本文給大家詳細介紹下,感興趣的朋友跟隨小編一起看看吧
    2020-10-10
  • Spring中的事務隔離級別的介紹

    Spring中的事務隔離級別的介紹

    今天小編就為大家分享一篇關于Spring中的事務隔離級別的介紹,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Maven 錯誤找不到符號的解決方法

    Maven 錯誤找不到符號的解決方法

    這篇文章主要介紹了Maven 錯誤找不到符號的解決方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08
  • 通過實例解析Java List正確使用方法

    通過實例解析Java List正確使用方法

    這篇文章主要介紹了通過實例解析Java List正確使用方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • SpringBoot配置使用H2數(shù)據庫的簡單教程

    SpringBoot配置使用H2數(shù)據庫的簡單教程

    H2是一個Java編寫的關系型數(shù)據庫,它可以被嵌入Java應用程序中使用,或者作為一個單獨的數(shù)據庫服務器運行。本文將介紹SpringBoot如何配置使用H2數(shù)據庫
    2021-05-05
  • 淺談Spring中IOC的理解和認知

    淺談Spring中IOC的理解和認知

    這篇文章主要介紹了淺談Spring中IOC的理解和認知,想了解Spring的同學不要錯過啊
    2021-04-04

最新評論